18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci#include <errno.h>
38c2ecf20Sopenharmony_ci#include <stdbool.h>
48c2ecf20Sopenharmony_ci#include <stdio.h>
58c2ecf20Sopenharmony_ci#include <string.h>
68c2ecf20Sopenharmony_ci#include <unistd.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <arpa/inet.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/in.h>
128c2ecf20Sopenharmony_ci#include <linux/in6.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "bpf_util.h"
158c2ecf20Sopenharmony_ci#include "network_helpers.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define clean_errno() (errno == 0 ? "None" : strerror(errno))
188c2ecf20Sopenharmony_ci#define log_err(MSG, ...) ({						\
198c2ecf20Sopenharmony_ci			int __save = errno;				\
208c2ecf20Sopenharmony_ci			fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \
218c2ecf20Sopenharmony_ci				__FILE__, __LINE__, clean_errno(),	\
228c2ecf20Sopenharmony_ci				##__VA_ARGS__);				\
238c2ecf20Sopenharmony_ci			errno = __save;					\
248c2ecf20Sopenharmony_ci})
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct ipv4_packet pkt_v4 = {
278c2ecf20Sopenharmony_ci	.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
288c2ecf20Sopenharmony_ci	.iph.ihl = 5,
298c2ecf20Sopenharmony_ci	.iph.protocol = IPPROTO_TCP,
308c2ecf20Sopenharmony_ci	.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
318c2ecf20Sopenharmony_ci	.tcp.urg_ptr = 123,
328c2ecf20Sopenharmony_ci	.tcp.doff = 5,
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct ipv6_packet pkt_v6 = {
368c2ecf20Sopenharmony_ci	.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
378c2ecf20Sopenharmony_ci	.iph.nexthdr = IPPROTO_TCP,
388c2ecf20Sopenharmony_ci	.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
398c2ecf20Sopenharmony_ci	.tcp.urg_ptr = 123,
408c2ecf20Sopenharmony_ci	.tcp.doff = 5,
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic int settimeo(int fd, int timeout_ms)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct timeval timeout = { .tv_sec = 3 };
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (timeout_ms > 0) {
488c2ecf20Sopenharmony_ci		timeout.tv_sec = timeout_ms / 1000;
498c2ecf20Sopenharmony_ci		timeout.tv_usec = (timeout_ms % 1000) * 1000;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout,
538c2ecf20Sopenharmony_ci		       sizeof(timeout))) {
548c2ecf20Sopenharmony_ci		log_err("Failed to set SO_RCVTIMEO");
558c2ecf20Sopenharmony_ci		return -1;
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout,
598c2ecf20Sopenharmony_ci		       sizeof(timeout))) {
608c2ecf20Sopenharmony_ci		log_err("Failed to set SO_SNDTIMEO");
618c2ecf20Sopenharmony_ci		return -1;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define save_errno_close(fd) ({ int __save = errno; close(fd); errno = __save; })
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ciint start_server(int family, int type, const char *addr_str, __u16 port,
708c2ecf20Sopenharmony_ci		 int timeout_ms)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct sockaddr_storage addr = {};
738c2ecf20Sopenharmony_ci	socklen_t len;
748c2ecf20Sopenharmony_ci	int fd;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (make_sockaddr(family, addr_str, port, &addr, &len))
778c2ecf20Sopenharmony_ci		return -1;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	fd = socket(family, type, 0);
808c2ecf20Sopenharmony_ci	if (fd < 0) {
818c2ecf20Sopenharmony_ci		log_err("Failed to create server socket");
828c2ecf20Sopenharmony_ci		return -1;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (settimeo(fd, timeout_ms))
868c2ecf20Sopenharmony_ci		goto error_close;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (bind(fd, (const struct sockaddr *)&addr, len) < 0) {
898c2ecf20Sopenharmony_ci		log_err("Failed to bind socket");
908c2ecf20Sopenharmony_ci		goto error_close;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (type == SOCK_STREAM) {
948c2ecf20Sopenharmony_ci		if (listen(fd, 1) < 0) {
958c2ecf20Sopenharmony_ci			log_err("Failed to listed on socket");
968c2ecf20Sopenharmony_ci			goto error_close;
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return fd;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cierror_close:
1038c2ecf20Sopenharmony_ci	save_errno_close(fd);
1048c2ecf20Sopenharmony_ci	return -1;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ciint fastopen_connect(int server_fd, const char *data, unsigned int data_len,
1088c2ecf20Sopenharmony_ci		     int timeout_ms)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct sockaddr_storage addr;
1118c2ecf20Sopenharmony_ci	socklen_t addrlen = sizeof(addr);
1128c2ecf20Sopenharmony_ci	struct sockaddr_in *addr_in;
1138c2ecf20Sopenharmony_ci	int fd, ret;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (getsockname(server_fd, (struct sockaddr *)&addr, &addrlen)) {
1168c2ecf20Sopenharmony_ci		log_err("Failed to get server addr");
1178c2ecf20Sopenharmony_ci		return -1;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	addr_in = (struct sockaddr_in *)&addr;
1218c2ecf20Sopenharmony_ci	fd = socket(addr_in->sin_family, SOCK_STREAM, 0);
1228c2ecf20Sopenharmony_ci	if (fd < 0) {
1238c2ecf20Sopenharmony_ci		log_err("Failed to create client socket");
1248c2ecf20Sopenharmony_ci		return -1;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (settimeo(fd, timeout_ms))
1288c2ecf20Sopenharmony_ci		goto error_close;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	ret = sendto(fd, data, data_len, MSG_FASTOPEN, (struct sockaddr *)&addr,
1318c2ecf20Sopenharmony_ci		     addrlen);
1328c2ecf20Sopenharmony_ci	if (ret != data_len) {
1338c2ecf20Sopenharmony_ci		log_err("sendto(data, %u) != %d\n", data_len, ret);
1348c2ecf20Sopenharmony_ci		goto error_close;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return fd;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cierror_close:
1408c2ecf20Sopenharmony_ci	save_errno_close(fd);
1418c2ecf20Sopenharmony_ci	return -1;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int connect_fd_to_addr(int fd,
1458c2ecf20Sopenharmony_ci			      const struct sockaddr_storage *addr,
1468c2ecf20Sopenharmony_ci			      socklen_t addrlen)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	if (connect(fd, (const struct sockaddr *)addr, addrlen)) {
1498c2ecf20Sopenharmony_ci		log_err("Failed to connect to server");
1508c2ecf20Sopenharmony_ci		return -1;
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return 0;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ciint connect_to_fd(int server_fd, int timeout_ms)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct sockaddr_storage addr;
1598c2ecf20Sopenharmony_ci	struct sockaddr_in *addr_in;
1608c2ecf20Sopenharmony_ci	socklen_t addrlen, optlen;
1618c2ecf20Sopenharmony_ci	int fd, type;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	optlen = sizeof(type);
1648c2ecf20Sopenharmony_ci	if (getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &type, &optlen)) {
1658c2ecf20Sopenharmony_ci		log_err("getsockopt(SOL_TYPE)");
1668c2ecf20Sopenharmony_ci		return -1;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	addrlen = sizeof(addr);
1708c2ecf20Sopenharmony_ci	if (getsockname(server_fd, (struct sockaddr *)&addr, &addrlen)) {
1718c2ecf20Sopenharmony_ci		log_err("Failed to get server addr");
1728c2ecf20Sopenharmony_ci		return -1;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	addr_in = (struct sockaddr_in *)&addr;
1768c2ecf20Sopenharmony_ci	fd = socket(addr_in->sin_family, type, 0);
1778c2ecf20Sopenharmony_ci	if (fd < 0) {
1788c2ecf20Sopenharmony_ci		log_err("Failed to create client socket");
1798c2ecf20Sopenharmony_ci		return -1;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (settimeo(fd, timeout_ms))
1838c2ecf20Sopenharmony_ci		goto error_close;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (connect_fd_to_addr(fd, &addr, addrlen))
1868c2ecf20Sopenharmony_ci		goto error_close;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return fd;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cierror_close:
1918c2ecf20Sopenharmony_ci	save_errno_close(fd);
1928c2ecf20Sopenharmony_ci	return -1;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciint connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct sockaddr_storage addr;
1988c2ecf20Sopenharmony_ci	socklen_t len = sizeof(addr);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (settimeo(client_fd, timeout_ms))
2018c2ecf20Sopenharmony_ci		return -1;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) {
2048c2ecf20Sopenharmony_ci		log_err("Failed to get server addr");
2058c2ecf20Sopenharmony_ci		return -1;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if (connect_fd_to_addr(client_fd, &addr, len))
2098c2ecf20Sopenharmony_ci		return -1;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	return 0;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ciint make_sockaddr(int family, const char *addr_str, __u16 port,
2158c2ecf20Sopenharmony_ci		  struct sockaddr_storage *addr, socklen_t *len)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	if (family == AF_INET) {
2188c2ecf20Sopenharmony_ci		struct sockaddr_in *sin = (void *)addr;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci		sin->sin_family = AF_INET;
2218c2ecf20Sopenharmony_ci		sin->sin_port = htons(port);
2228c2ecf20Sopenharmony_ci		if (addr_str &&
2238c2ecf20Sopenharmony_ci		    inet_pton(AF_INET, addr_str, &sin->sin_addr) != 1) {
2248c2ecf20Sopenharmony_ci			log_err("inet_pton(AF_INET, %s)", addr_str);
2258c2ecf20Sopenharmony_ci			return -1;
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci		if (len)
2288c2ecf20Sopenharmony_ci			*len = sizeof(*sin);
2298c2ecf20Sopenharmony_ci		return 0;
2308c2ecf20Sopenharmony_ci	} else if (family == AF_INET6) {
2318c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6 = (void *)addr;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		sin6->sin6_family = AF_INET6;
2348c2ecf20Sopenharmony_ci		sin6->sin6_port = htons(port);
2358c2ecf20Sopenharmony_ci		if (addr_str &&
2368c2ecf20Sopenharmony_ci		    inet_pton(AF_INET6, addr_str, &sin6->sin6_addr) != 1) {
2378c2ecf20Sopenharmony_ci			log_err("inet_pton(AF_INET6, %s)", addr_str);
2388c2ecf20Sopenharmony_ci			return -1;
2398c2ecf20Sopenharmony_ci		}
2408c2ecf20Sopenharmony_ci		if (len)
2418c2ecf20Sopenharmony_ci			*len = sizeof(*sin6);
2428c2ecf20Sopenharmony_ci		return 0;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci	return -1;
2458c2ecf20Sopenharmony_ci}
246