// SPDX-License-Identifier: GPL-2.0-only #include #include #include #include #include #include #include #include #include #include #include "bpf_util.h" #include "network_helpers.h" #define clean_errno() (errno == 0 ? "None" : strerror(errno)) #define log_err(MSG, ...) fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \ __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) struct ipv4_packet pkt_v4 = { .eth.h_proto = __bpf_constant_htons(ETH_P_IP), .iph.ihl = 5, .iph.protocol = IPPROTO_TCP, .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), .tcp.urg_ptr = 123, .tcp.doff = 5, }; struct ipv6_packet pkt_v6 = { .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6), .iph.nexthdr = IPPROTO_TCP, .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES), .tcp.urg_ptr = 123, .tcp.doff = 5, }; int start_server_with_port(int family, int type, __u16 port) { struct sockaddr_storage addr = {}; socklen_t len; int fd; if (family == AF_INET) { struct sockaddr_in *sin = (void *)&addr; sin->sin_family = AF_INET; sin->sin_port = htons(port); len = sizeof(*sin); } else { struct sockaddr_in6 *sin6 = (void *)&addr; sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(port); len = sizeof(*sin6); } fd = socket(family, type | SOCK_NONBLOCK, 0); if (fd < 0) { log_err("Failed to create server socket"); return -1; } if (bind(fd, (const struct sockaddr *)&addr, len) < 0) { log_err("Failed to bind socket"); close(fd); return -1; } if (type == SOCK_STREAM) { if (listen(fd, 1) < 0) { log_err("Failed to listed on socket"); close(fd); return -1; } } return fd; } int start_server(int family, int type) { return start_server_with_port(family, type, 0); } static const struct timeval timeo_sec = { .tv_sec = 3 }; static const size_t timeo_optlen = sizeof(timeo_sec); int connect_to_fd(int family, int type, int server_fd) { int fd, save_errno; fd = socket(family, type, 0); if (fd < 0) { log_err("Failed to create client socket"); return -1; } if (connect_fd_to_fd(fd, server_fd) < 0 && errno != EINPROGRESS) { save_errno = errno; close(fd); errno = save_errno; return -1; } return fd; } int connect_fd_to_fd(int client_fd, int server_fd) { struct sockaddr_storage addr; socklen_t len = sizeof(addr); int save_errno; if (setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &timeo_sec, timeo_optlen)) { log_err("Failed to set SO_RCVTIMEO"); return -1; } if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { log_err("Failed to get server addr"); return -1; } if (connect(client_fd, (const struct sockaddr *)&addr, len) < 0) { if (errno != EINPROGRESS) { save_errno = errno; log_err("Failed to connect to server"); errno = save_errno; } return -1; } return 0; } int connect_wait(int fd) { struct epoll_event ev = {}, events[2]; int timeout_ms = 1000; int efd, nfd; efd = epoll_create1(EPOLL_CLOEXEC); if (efd < 0) { log_err("Failed to open epoll fd"); return -1; } ev.events = EPOLLRDHUP | EPOLLOUT; ev.data.fd = fd; if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev) < 0) { log_err("Failed to register fd=%d on epoll fd=%d", fd, efd); close(efd); return -1; } nfd = epoll_wait(efd, events, ARRAY_SIZE(events), timeout_ms); if (nfd < 0) log_err("Failed to wait for I/O event on epoll fd=%d", efd); close(efd); return nfd; }