1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <errno.h> 3 #include <stdbool.h> 4 #include <stdio.h> 5 #include <string.h> 6 #include <unistd.h> 7 8 #include <arpa/inet.h> 9 10 #include <linux/err.h> 11 #include <linux/in.h> 12 #include <linux/in6.h> 13 14 #include "bpf_util.h" 15 #include "network_helpers.h" 16 17 #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 18 #define log_err(MSG, ...) ({ \ 19 int __save = errno; \ 20 fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \ 21 __FILE__, __LINE__, clean_errno(), \ 22 ##__VA_ARGS__); \ 23 errno = __save; \ 24 }) 25 26 struct ipv4_packet pkt_v4 = { 27 .eth.h_proto = __bpf_constant_htons(ETH_P_IP), 28 .iph.ihl = 5, 29 .iph.protocol = IPPROTO_TCP, 30 .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), 31 .tcp.urg_ptr = 123, 32 .tcp.doff = 5, 33 }; 34 35 struct ipv6_packet pkt_v6 = { 36 .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6), 37 .iph.nexthdr = IPPROTO_TCP, 38 .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES), 39 .tcp.urg_ptr = 123, 40 .tcp.doff = 5, 41 }; 42 43 int settimeo(int fd, int timeout_ms) 44 { 45 struct timeval timeout = { .tv_sec = 3 }; 46 47 if (timeout_ms > 0) { 48 timeout.tv_sec = timeout_ms / 1000; 49 timeout.tv_usec = (timeout_ms % 1000) * 1000; 50 } 51 52 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, 53 sizeof(timeout))) { 54 log_err("Failed to set SO_RCVTIMEO"); 55 return -1; 56 } 57 58 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, 59 sizeof(timeout))) { 60 log_err("Failed to set SO_SNDTIMEO"); 61 return -1; 62 } 63 64 return 0; 65 } 66 67 #define save_errno_close(fd) ({ int __save = errno; close(fd); errno = __save; }) 68 69 static int __start_server(int type, const struct sockaddr *addr, 70 socklen_t addrlen, int timeout_ms, bool reuseport) 71 { 72 int on = 1; 73 int fd; 74 75 fd = socket(addr->sa_family, type, 0); 76 if (fd < 0) { 77 log_err("Failed to create server socket"); 78 return -1; 79 } 80 81 if (settimeo(fd, timeout_ms)) 82 goto error_close; 83 84 if (reuseport && 85 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) { 86 log_err("Failed to set SO_REUSEPORT"); 87 return -1; 88 } 89 90 if (bind(fd, addr, addrlen) < 0) { 91 log_err("Failed to bind socket"); 92 goto error_close; 93 } 94 95 if (type == SOCK_STREAM) { 96 if (listen(fd, 1) < 0) { 97 log_err("Failed to listed on socket"); 98 goto error_close; 99 } 100 } 101 102 return fd; 103 104 error_close: 105 save_errno_close(fd); 106 return -1; 107 } 108 109 int start_server(int family, int type, const char *addr_str, __u16 port, 110 int timeout_ms) 111 { 112 struct sockaddr_storage addr; 113 socklen_t addrlen; 114 115 if (make_sockaddr(family, addr_str, port, &addr, &addrlen)) 116 return -1; 117 118 return __start_server(type, (struct sockaddr *)&addr, 119 addrlen, timeout_ms, false); 120 } 121 122 int *start_reuseport_server(int family, int type, const char *addr_str, 123 __u16 port, int timeout_ms, unsigned int nr_listens) 124 { 125 struct sockaddr_storage addr; 126 unsigned int nr_fds = 0; 127 socklen_t addrlen; 128 int *fds; 129 130 if (!nr_listens) 131 return NULL; 132 133 if (make_sockaddr(family, addr_str, port, &addr, &addrlen)) 134 return NULL; 135 136 fds = malloc(sizeof(*fds) * nr_listens); 137 if (!fds) 138 return NULL; 139 140 fds[0] = __start_server(type, (struct sockaddr *)&addr, addrlen, 141 timeout_ms, true); 142 if (fds[0] == -1) 143 goto close_fds; 144 nr_fds = 1; 145 146 if (getsockname(fds[0], (struct sockaddr *)&addr, &addrlen)) 147 goto close_fds; 148 149 for (; nr_fds < nr_listens; nr_fds++) { 150 fds[nr_fds] = __start_server(type, (struct sockaddr *)&addr, 151 addrlen, timeout_ms, true); 152 if (fds[nr_fds] == -1) 153 goto close_fds; 154 } 155 156 return fds; 157 158 close_fds: 159 free_fds(fds, nr_fds); 160 return NULL; 161 } 162 163 void free_fds(int *fds, unsigned int nr_close_fds) 164 { 165 if (fds) { 166 while (nr_close_fds) 167 close(fds[--nr_close_fds]); 168 free(fds); 169 } 170 } 171 172 int fastopen_connect(int server_fd, const char *data, unsigned int data_len, 173 int timeout_ms) 174 { 175 struct sockaddr_storage addr; 176 socklen_t addrlen = sizeof(addr); 177 struct sockaddr_in *addr_in; 178 int fd, ret; 179 180 if (getsockname(server_fd, (struct sockaddr *)&addr, &addrlen)) { 181 log_err("Failed to get server addr"); 182 return -1; 183 } 184 185 addr_in = (struct sockaddr_in *)&addr; 186 fd = socket(addr_in->sin_family, SOCK_STREAM, 0); 187 if (fd < 0) { 188 log_err("Failed to create client socket"); 189 return -1; 190 } 191 192 if (settimeo(fd, timeout_ms)) 193 goto error_close; 194 195 ret = sendto(fd, data, data_len, MSG_FASTOPEN, (struct sockaddr *)&addr, 196 addrlen); 197 if (ret != data_len) { 198 log_err("sendto(data, %u) != %d\n", data_len, ret); 199 goto error_close; 200 } 201 202 return fd; 203 204 error_close: 205 save_errno_close(fd); 206 return -1; 207 } 208 209 static int connect_fd_to_addr(int fd, 210 const struct sockaddr_storage *addr, 211 socklen_t addrlen) 212 { 213 if (connect(fd, (const struct sockaddr *)addr, addrlen)) { 214 log_err("Failed to connect to server"); 215 return -1; 216 } 217 218 return 0; 219 } 220 221 int connect_to_fd(int server_fd, int timeout_ms) 222 { 223 struct sockaddr_storage addr; 224 struct sockaddr_in *addr_in; 225 socklen_t addrlen, optlen; 226 int fd, type; 227 228 optlen = sizeof(type); 229 if (getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &type, &optlen)) { 230 log_err("getsockopt(SOL_TYPE)"); 231 return -1; 232 } 233 234 addrlen = sizeof(addr); 235 if (getsockname(server_fd, (struct sockaddr *)&addr, &addrlen)) { 236 log_err("Failed to get server addr"); 237 return -1; 238 } 239 240 addr_in = (struct sockaddr_in *)&addr; 241 fd = socket(addr_in->sin_family, type, 0); 242 if (fd < 0) { 243 log_err("Failed to create client socket"); 244 return -1; 245 } 246 247 if (settimeo(fd, timeout_ms)) 248 goto error_close; 249 250 if (connect_fd_to_addr(fd, &addr, addrlen)) 251 goto error_close; 252 253 return fd; 254 255 error_close: 256 save_errno_close(fd); 257 return -1; 258 } 259 260 int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms) 261 { 262 struct sockaddr_storage addr; 263 socklen_t len = sizeof(addr); 264 265 if (settimeo(client_fd, timeout_ms)) 266 return -1; 267 268 if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { 269 log_err("Failed to get server addr"); 270 return -1; 271 } 272 273 if (connect_fd_to_addr(client_fd, &addr, len)) 274 return -1; 275 276 return 0; 277 } 278 279 int make_sockaddr(int family, const char *addr_str, __u16 port, 280 struct sockaddr_storage *addr, socklen_t *len) 281 { 282 if (family == AF_INET) { 283 struct sockaddr_in *sin = (void *)addr; 284 285 memset(addr, 0, sizeof(*sin)); 286 sin->sin_family = AF_INET; 287 sin->sin_port = htons(port); 288 if (addr_str && 289 inet_pton(AF_INET, addr_str, &sin->sin_addr) != 1) { 290 log_err("inet_pton(AF_INET, %s)", addr_str); 291 return -1; 292 } 293 if (len) 294 *len = sizeof(*sin); 295 return 0; 296 } else if (family == AF_INET6) { 297 struct sockaddr_in6 *sin6 = (void *)addr; 298 299 memset(addr, 0, sizeof(*sin6)); 300 sin6->sin6_family = AF_INET6; 301 sin6->sin6_port = htons(port); 302 if (addr_str && 303 inet_pton(AF_INET6, addr_str, &sin6->sin6_addr) != 1) { 304 log_err("inet_pton(AF_INET6, %s)", addr_str); 305 return -1; 306 } 307 if (len) 308 *len = sizeof(*sin6); 309 return 0; 310 } 311 return -1; 312 } 313 314 char *ping_command(int family) 315 { 316 if (family == AF_INET6) { 317 /* On some systems 'ping' doesn't support IPv6, so use ping6 if it is present. */ 318 if (!system("which ping6 >/dev/null 2>&1")) 319 return "ping6"; 320 else 321 return "ping -6"; 322 } 323 return "ping"; 324 } 325