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 static const struct network_helper_opts default_opts; 222 223 int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts) 224 { 225 struct sockaddr_storage addr; 226 struct sockaddr_in *addr_in; 227 socklen_t addrlen, optlen; 228 int fd, type; 229 230 if (!opts) 231 opts = &default_opts; 232 233 optlen = sizeof(type); 234 if (getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &type, &optlen)) { 235 log_err("getsockopt(SOL_TYPE)"); 236 return -1; 237 } 238 239 addrlen = sizeof(addr); 240 if (getsockname(server_fd, (struct sockaddr *)&addr, &addrlen)) { 241 log_err("Failed to get server addr"); 242 return -1; 243 } 244 245 addr_in = (struct sockaddr_in *)&addr; 246 fd = socket(addr_in->sin_family, type, 0); 247 if (fd < 0) { 248 log_err("Failed to create client socket"); 249 return -1; 250 } 251 252 if (settimeo(fd, opts->timeout_ms)) 253 goto error_close; 254 255 if (opts->cc && opts->cc[0] && 256 setsockopt(fd, SOL_TCP, TCP_CONGESTION, opts->cc, 257 strlen(opts->cc) + 1)) 258 goto error_close; 259 260 if (connect_fd_to_addr(fd, &addr, addrlen)) 261 goto error_close; 262 263 return fd; 264 265 error_close: 266 save_errno_close(fd); 267 return -1; 268 } 269 270 int connect_to_fd(int server_fd, int timeout_ms) 271 { 272 struct network_helper_opts opts = { 273 .timeout_ms = timeout_ms, 274 }; 275 276 return connect_to_fd_opts(server_fd, &opts); 277 } 278 279 int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms) 280 { 281 struct sockaddr_storage addr; 282 socklen_t len = sizeof(addr); 283 284 if (settimeo(client_fd, timeout_ms)) 285 return -1; 286 287 if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { 288 log_err("Failed to get server addr"); 289 return -1; 290 } 291 292 if (connect_fd_to_addr(client_fd, &addr, len)) 293 return -1; 294 295 return 0; 296 } 297 298 int make_sockaddr(int family, const char *addr_str, __u16 port, 299 struct sockaddr_storage *addr, socklen_t *len) 300 { 301 if (family == AF_INET) { 302 struct sockaddr_in *sin = (void *)addr; 303 304 memset(addr, 0, sizeof(*sin)); 305 sin->sin_family = AF_INET; 306 sin->sin_port = htons(port); 307 if (addr_str && 308 inet_pton(AF_INET, addr_str, &sin->sin_addr) != 1) { 309 log_err("inet_pton(AF_INET, %s)", addr_str); 310 return -1; 311 } 312 if (len) 313 *len = sizeof(*sin); 314 return 0; 315 } else if (family == AF_INET6) { 316 struct sockaddr_in6 *sin6 = (void *)addr; 317 318 memset(addr, 0, sizeof(*sin6)); 319 sin6->sin6_family = AF_INET6; 320 sin6->sin6_port = htons(port); 321 if (addr_str && 322 inet_pton(AF_INET6, addr_str, &sin6->sin6_addr) != 1) { 323 log_err("inet_pton(AF_INET6, %s)", addr_str); 324 return -1; 325 } 326 if (len) 327 *len = sizeof(*sin6); 328 return 0; 329 } 330 return -1; 331 } 332 333 char *ping_command(int family) 334 { 335 if (family == AF_INET6) { 336 /* On some systems 'ping' doesn't support IPv6, so use ping6 if it is present. */ 337 if (!system("which ping6 >/dev/null 2>&1")) 338 return "ping6"; 339 else 340 return "ping -6"; 341 } 342 return "ping"; 343 } 344