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