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