1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 5 #include <assert.h> 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <limits.h> 9 #include <string.h> 10 #include <stdarg.h> 11 #include <stdbool.h> 12 #include <stdint.h> 13 #include <inttypes.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <strings.h> 17 #include <time.h> 18 #include <unistd.h> 19 20 #include <sys/socket.h> 21 #include <sys/types.h> 22 #include <sys/wait.h> 23 24 #include <netdb.h> 25 #include <netinet/in.h> 26 27 #include <linux/tcp.h> 28 29 static int pf = AF_INET; 30 31 #ifndef IPPROTO_MPTCP 32 #define IPPROTO_MPTCP 262 33 #endif 34 #ifndef SOL_MPTCP 35 #define SOL_MPTCP 284 36 #endif 37 38 #ifndef MPTCP_INFO 39 struct mptcp_info { 40 __u8 mptcpi_subflows; 41 __u8 mptcpi_add_addr_signal; 42 __u8 mptcpi_add_addr_accepted; 43 __u8 mptcpi_subflows_max; 44 __u8 mptcpi_add_addr_signal_max; 45 __u8 mptcpi_add_addr_accepted_max; 46 __u32 mptcpi_flags; 47 __u32 mptcpi_token; 48 __u64 mptcpi_write_seq; 49 __u64 mptcpi_snd_una; 50 __u64 mptcpi_rcv_nxt; 51 __u8 mptcpi_local_addr_used; 52 __u8 mptcpi_local_addr_max; 53 __u8 mptcpi_csum_enabled; 54 }; 55 56 struct mptcp_subflow_data { 57 __u32 size_subflow_data; /* size of this structure in userspace */ 58 __u32 num_subflows; /* must be 0, set by kernel */ 59 __u32 size_kernel; /* must be 0, set by kernel */ 60 __u32 size_user; /* size of one element in data[] */ 61 } __attribute__((aligned(8))); 62 63 struct mptcp_subflow_addrs { 64 union { 65 __kernel_sa_family_t sa_family; 66 struct sockaddr sa_local; 67 struct sockaddr_in sin_local; 68 struct sockaddr_in6 sin6_local; 69 struct __kernel_sockaddr_storage ss_local; 70 }; 71 union { 72 struct sockaddr sa_remote; 73 struct sockaddr_in sin_remote; 74 struct sockaddr_in6 sin6_remote; 75 struct __kernel_sockaddr_storage ss_remote; 76 }; 77 }; 78 79 #define MPTCP_INFO 1 80 #define MPTCP_TCPINFO 2 81 #define MPTCP_SUBFLOW_ADDRS 3 82 #endif 83 84 struct so_state { 85 struct mptcp_info mi; 86 uint64_t mptcpi_rcv_delta; 87 uint64_t tcpi_rcv_delta; 88 }; 89 90 #ifndef MIN 91 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 92 #endif 93 94 static void die_perror(const char *msg) 95 { 96 perror(msg); 97 exit(1); 98 } 99 100 static void die_usage(int r) 101 { 102 fprintf(stderr, "Usage: mptcp_sockopt [-6]\n"); 103 exit(r); 104 } 105 106 static void xerror(const char *fmt, ...) 107 { 108 va_list ap; 109 110 va_start(ap, fmt); 111 vfprintf(stderr, fmt, ap); 112 va_end(ap); 113 fputc('\n', stderr); 114 exit(1); 115 } 116 117 static const char *getxinfo_strerr(int err) 118 { 119 if (err == EAI_SYSTEM) 120 return strerror(errno); 121 122 return gai_strerror(err); 123 } 124 125 static void xgetaddrinfo(const char *node, const char *service, 126 const struct addrinfo *hints, 127 struct addrinfo **res) 128 { 129 int err = getaddrinfo(node, service, hints, res); 130 131 if (err) { 132 const char *errstr = getxinfo_strerr(err); 133 134 fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n", 135 node ? node : "", service ? service : "", errstr); 136 exit(1); 137 } 138 } 139 140 static int sock_listen_mptcp(const char * const listenaddr, 141 const char * const port) 142 { 143 int sock = -1; 144 struct addrinfo hints = { 145 .ai_protocol = IPPROTO_TCP, 146 .ai_socktype = SOCK_STREAM, 147 .ai_flags = AI_PASSIVE | AI_NUMERICHOST 148 }; 149 150 hints.ai_family = pf; 151 152 struct addrinfo *a, *addr; 153 int one = 1; 154 155 xgetaddrinfo(listenaddr, port, &hints, &addr); 156 hints.ai_family = pf; 157 158 for (a = addr; a; a = a->ai_next) { 159 sock = socket(a->ai_family, a->ai_socktype, IPPROTO_MPTCP); 160 if (sock < 0) 161 continue; 162 163 if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, 164 sizeof(one))) 165 perror("setsockopt"); 166 167 if (bind(sock, a->ai_addr, a->ai_addrlen) == 0) 168 break; /* success */ 169 170 perror("bind"); 171 close(sock); 172 sock = -1; 173 } 174 175 freeaddrinfo(addr); 176 177 if (sock < 0) 178 xerror("could not create listen socket"); 179 180 if (listen(sock, 20)) 181 die_perror("listen"); 182 183 return sock; 184 } 185 186 static int sock_connect_mptcp(const char * const remoteaddr, 187 const char * const port, int proto) 188 { 189 struct addrinfo hints = { 190 .ai_protocol = IPPROTO_TCP, 191 .ai_socktype = SOCK_STREAM, 192 }; 193 struct addrinfo *a, *addr; 194 int sock = -1; 195 196 hints.ai_family = pf; 197 198 xgetaddrinfo(remoteaddr, port, &hints, &addr); 199 for (a = addr; a; a = a->ai_next) { 200 sock = socket(a->ai_family, a->ai_socktype, proto); 201 if (sock < 0) 202 continue; 203 204 if (connect(sock, a->ai_addr, a->ai_addrlen) == 0) 205 break; /* success */ 206 207 die_perror("connect"); 208 } 209 210 if (sock < 0) 211 xerror("could not create connect socket"); 212 213 freeaddrinfo(addr); 214 return sock; 215 } 216 217 static void parse_opts(int argc, char **argv) 218 { 219 int c; 220 221 while ((c = getopt(argc, argv, "h6")) != -1) { 222 switch (c) { 223 case 'h': 224 die_usage(0); 225 break; 226 case '6': 227 pf = AF_INET6; 228 break; 229 default: 230 die_usage(1); 231 break; 232 } 233 } 234 } 235 236 static void do_getsockopt_bogus_sf_data(int fd, int optname) 237 { 238 struct mptcp_subflow_data good_data; 239 struct bogus_data { 240 struct mptcp_subflow_data d; 241 char buf[2]; 242 } bd; 243 socklen_t olen, _olen; 244 int ret; 245 246 memset(&bd, 0, sizeof(bd)); 247 memset(&good_data, 0, sizeof(good_data)); 248 249 olen = sizeof(good_data); 250 good_data.size_subflow_data = olen; 251 252 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen); 253 assert(ret < 0); /* 0 size_subflow_data */ 254 assert(olen == sizeof(good_data)); 255 256 bd.d = good_data; 257 258 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen); 259 assert(ret == 0); 260 assert(olen == sizeof(good_data)); 261 assert(bd.d.num_subflows == 1); 262 assert(bd.d.size_kernel > 0); 263 assert(bd.d.size_user == 0); 264 265 bd.d = good_data; 266 _olen = rand() % olen; 267 olen = _olen; 268 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen); 269 assert(ret < 0); /* bogus olen */ 270 assert(olen == _olen); /* must be unchanged */ 271 272 bd.d = good_data; 273 olen = sizeof(good_data); 274 bd.d.size_kernel = 1; 275 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen); 276 assert(ret < 0); /* size_kernel not 0 */ 277 278 bd.d = good_data; 279 olen = sizeof(good_data); 280 bd.d.num_subflows = 1; 281 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen); 282 assert(ret < 0); /* num_subflows not 0 */ 283 284 /* forward compat check: larger struct mptcp_subflow_data on 'old' kernel */ 285 bd.d = good_data; 286 olen = sizeof(bd); 287 bd.d.size_subflow_data = sizeof(bd); 288 289 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen); 290 assert(ret == 0); 291 292 /* olen must be truncated to real data size filled by kernel: */ 293 assert(olen == sizeof(good_data)); 294 295 assert(bd.d.size_subflow_data == sizeof(bd)); 296 297 bd.d = good_data; 298 bd.d.size_subflow_data += 1; 299 bd.d.size_user = 1; 300 olen = bd.d.size_subflow_data + 1; 301 _olen = olen; 302 303 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &_olen); 304 assert(ret == 0); 305 306 /* no truncation, kernel should have filled 1 byte of optname payload in buf[1]: */ 307 assert(olen == _olen); 308 309 assert(bd.d.size_subflow_data == sizeof(good_data) + 1); 310 assert(bd.buf[0] == 0); 311 } 312 313 static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w) 314 { 315 struct mptcp_info i; 316 socklen_t olen; 317 int ret; 318 319 olen = sizeof(i); 320 ret = getsockopt(fd, SOL_MPTCP, MPTCP_INFO, &i, &olen); 321 322 if (ret < 0) 323 die_perror("getsockopt MPTCP_INFO"); 324 325 assert(olen == sizeof(i)); 326 327 if (s->mi.mptcpi_write_seq == 0) 328 s->mi = i; 329 330 assert(s->mi.mptcpi_write_seq + w == i.mptcpi_write_seq); 331 332 s->mptcpi_rcv_delta = i.mptcpi_rcv_nxt - s->mi.mptcpi_rcv_nxt; 333 } 334 335 static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t w) 336 { 337 struct my_tcp_info { 338 struct mptcp_subflow_data d; 339 struct tcp_info ti[2]; 340 } ti; 341 int ret, tries = 5; 342 socklen_t olen; 343 344 do { 345 memset(&ti, 0, sizeof(ti)); 346 347 ti.d.size_subflow_data = sizeof(struct mptcp_subflow_data); 348 ti.d.size_user = sizeof(struct tcp_info); 349 olen = sizeof(ti); 350 351 ret = getsockopt(fd, SOL_MPTCP, MPTCP_TCPINFO, &ti, &olen); 352 if (ret < 0) 353 xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)"); 354 355 assert(olen <= sizeof(ti)); 356 assert(ti.d.size_kernel > 0); 357 assert(ti.d.size_user == 358 MIN(ti.d.size_kernel, sizeof(struct tcp_info))); 359 assert(ti.d.num_subflows == 1); 360 361 assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data)); 362 olen -= sizeof(struct mptcp_subflow_data); 363 assert(olen == ti.d.size_user); 364 365 if (ti.ti[0].tcpi_bytes_sent == w && 366 ti.ti[0].tcpi_bytes_received == r) 367 goto done; 368 369 if (r == 0 && ti.ti[0].tcpi_bytes_sent == w && 370 ti.ti[0].tcpi_bytes_received) { 371 s->tcpi_rcv_delta = ti.ti[0].tcpi_bytes_received; 372 goto done; 373 } 374 375 /* wait and repeat, might be that tx is still ongoing */ 376 sleep(1); 377 } while (tries-- > 0); 378 379 xerror("tcpi_bytes_sent %" PRIu64 ", want %zu. tcpi_bytes_received %" PRIu64 ", want %zu", 380 ti.ti[0].tcpi_bytes_sent, w, ti.ti[0].tcpi_bytes_received, r); 381 382 done: 383 do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO); 384 } 385 386 static void do_getsockopt_subflow_addrs(int fd) 387 { 388 struct sockaddr_storage remote, local; 389 socklen_t olen, rlen, llen; 390 int ret; 391 struct my_addrs { 392 struct mptcp_subflow_data d; 393 struct mptcp_subflow_addrs addr[2]; 394 } addrs; 395 396 memset(&addrs, 0, sizeof(addrs)); 397 memset(&local, 0, sizeof(local)); 398 memset(&remote, 0, sizeof(remote)); 399 400 addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data); 401 addrs.d.size_user = sizeof(struct mptcp_subflow_addrs); 402 olen = sizeof(addrs); 403 404 ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen); 405 if (ret < 0) 406 die_perror("getsockopt MPTCP_SUBFLOW_ADDRS"); 407 408 assert(olen <= sizeof(addrs)); 409 assert(addrs.d.size_kernel > 0); 410 assert(addrs.d.size_user == 411 MIN(addrs.d.size_kernel, sizeof(struct mptcp_subflow_addrs))); 412 assert(addrs.d.num_subflows == 1); 413 414 assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data)); 415 olen -= sizeof(struct mptcp_subflow_data); 416 assert(olen == addrs.d.size_user); 417 418 llen = sizeof(local); 419 ret = getsockname(fd, (struct sockaddr *)&local, &llen); 420 if (ret < 0) 421 die_perror("getsockname"); 422 rlen = sizeof(remote); 423 ret = getpeername(fd, (struct sockaddr *)&remote, &rlen); 424 if (ret < 0) 425 die_perror("getpeername"); 426 427 assert(rlen > 0); 428 assert(rlen == llen); 429 430 assert(remote.ss_family == local.ss_family); 431 432 assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0); 433 assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0); 434 435 memset(&addrs, 0, sizeof(addrs)); 436 437 addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data); 438 addrs.d.size_user = sizeof(sa_family_t); 439 olen = sizeof(addrs.d) + sizeof(sa_family_t); 440 441 ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen); 442 assert(ret == 0); 443 assert(olen == sizeof(addrs.d) + sizeof(sa_family_t)); 444 445 assert(addrs.addr[0].sa_family == pf); 446 assert(addrs.addr[0].sa_family == local.ss_family); 447 448 assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) != 0); 449 assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) != 0); 450 451 do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS); 452 } 453 454 static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w) 455 { 456 do_getsockopt_mptcp_info(s, fd, w); 457 458 do_getsockopt_tcp_info(s, fd, r, w); 459 460 do_getsockopt_subflow_addrs(fd); 461 } 462 463 static void connect_one_server(int fd, int pipefd) 464 { 465 char buf[4096], buf2[4096]; 466 size_t len, i, total; 467 struct so_state s; 468 bool eof = false; 469 ssize_t ret; 470 471 memset(&s, 0, sizeof(s)); 472 473 len = rand() % (sizeof(buf) - 1); 474 475 if (len < 128) 476 len = 128; 477 478 for (i = 0; i < len ; i++) { 479 buf[i] = rand() % 26; 480 buf[i] += 'A'; 481 } 482 483 buf[i] = '\n'; 484 485 do_getsockopts(&s, fd, 0, 0); 486 487 /* un-block server */ 488 ret = read(pipefd, buf2, 4); 489 assert(ret == 4); 490 close(pipefd); 491 492 assert(strncmp(buf2, "xmit", 4) == 0); 493 494 ret = write(fd, buf, len); 495 if (ret < 0) 496 die_perror("write"); 497 498 if (ret != (ssize_t)len) 499 xerror("short write"); 500 501 total = 0; 502 do { 503 ret = read(fd, buf2 + total, sizeof(buf2) - total); 504 if (ret < 0) 505 die_perror("read"); 506 if (ret == 0) { 507 eof = true; 508 break; 509 } 510 511 total += ret; 512 } while (total < len); 513 514 if (total != len) 515 xerror("total %lu, len %lu eof %d\n", total, len, eof); 516 517 if (memcmp(buf, buf2, len)) 518 xerror("data corruption"); 519 520 if (s.tcpi_rcv_delta) 521 assert(s.tcpi_rcv_delta <= total); 522 523 do_getsockopts(&s, fd, ret, ret); 524 525 if (eof) 526 total += 1; /* sequence advances due to FIN */ 527 528 assert(s.mptcpi_rcv_delta == (uint64_t)total); 529 close(fd); 530 } 531 532 static void process_one_client(int fd, int pipefd) 533 { 534 ssize_t ret, ret2, ret3; 535 struct so_state s; 536 char buf[4096]; 537 538 memset(&s, 0, sizeof(s)); 539 do_getsockopts(&s, fd, 0, 0); 540 541 ret = write(pipefd, "xmit", 4); 542 assert(ret == 4); 543 544 ret = read(fd, buf, sizeof(buf)); 545 if (ret < 0) 546 die_perror("read"); 547 548 assert(s.mptcpi_rcv_delta <= (uint64_t)ret); 549 550 if (s.tcpi_rcv_delta) 551 assert(s.tcpi_rcv_delta == (uint64_t)ret); 552 553 ret2 = write(fd, buf, ret); 554 if (ret2 < 0) 555 die_perror("write"); 556 557 /* wait for hangup */ 558 ret3 = read(fd, buf, 1); 559 if (ret3 != 0) 560 xerror("expected EOF, got %lu", ret3); 561 562 do_getsockopts(&s, fd, ret, ret2); 563 if (s.mptcpi_rcv_delta != (uint64_t)ret + 1) 564 xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret); 565 close(fd); 566 } 567 568 static int xaccept(int s) 569 { 570 int fd = accept(s, NULL, 0); 571 572 if (fd < 0) 573 die_perror("accept"); 574 575 return fd; 576 } 577 578 static int server(int pipefd) 579 { 580 int fd = -1, r; 581 582 switch (pf) { 583 case AF_INET: 584 fd = sock_listen_mptcp("127.0.0.1", "15432"); 585 break; 586 case AF_INET6: 587 fd = sock_listen_mptcp("::1", "15432"); 588 break; 589 default: 590 xerror("Unknown pf %d\n", pf); 591 break; 592 } 593 594 r = write(pipefd, "conn", 4); 595 assert(r == 4); 596 597 alarm(15); 598 r = xaccept(fd); 599 600 process_one_client(r, pipefd); 601 602 return 0; 603 } 604 605 static void test_ip_tos_sockopt(int fd) 606 { 607 uint8_t tos_in, tos_out; 608 socklen_t s; 609 int r; 610 611 tos_in = rand() & 0xfc; 612 r = setsockopt(fd, SOL_IP, IP_TOS, &tos_in, sizeof(tos_out)); 613 if (r != 0) 614 die_perror("setsockopt IP_TOS"); 615 616 tos_out = 0; 617 s = sizeof(tos_out); 618 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s); 619 if (r != 0) 620 die_perror("getsockopt IP_TOS"); 621 622 if (tos_in != tos_out) 623 xerror("tos %x != %x socklen_t %d\n", tos_in, tos_out, s); 624 625 if (s != 1) 626 xerror("tos should be 1 byte"); 627 628 s = 0; 629 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s); 630 if (r != 0) 631 die_perror("getsockopt IP_TOS 0"); 632 if (s != 0) 633 xerror("expect socklen_t == 0"); 634 635 s = -1; 636 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s); 637 if (r != -1 && errno != EINVAL) 638 die_perror("getsockopt IP_TOS did not indicate -EINVAL"); 639 if (s != -1) 640 xerror("expect socklen_t == -1"); 641 } 642 643 static int client(int pipefd) 644 { 645 int fd = -1; 646 647 alarm(15); 648 649 switch (pf) { 650 case AF_INET: 651 fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP); 652 break; 653 case AF_INET6: 654 fd = sock_connect_mptcp("::1", "15432", IPPROTO_MPTCP); 655 break; 656 default: 657 xerror("Unknown pf %d\n", pf); 658 } 659 660 test_ip_tos_sockopt(fd); 661 662 connect_one_server(fd, pipefd); 663 664 return 0; 665 } 666 667 static pid_t xfork(void) 668 { 669 pid_t p = fork(); 670 671 if (p < 0) 672 die_perror("fork"); 673 674 return p; 675 } 676 677 static int rcheck(int wstatus, const char *what) 678 { 679 if (WIFEXITED(wstatus)) { 680 if (WEXITSTATUS(wstatus) == 0) 681 return 0; 682 fprintf(stderr, "%s exited, status=%d\n", what, WEXITSTATUS(wstatus)); 683 return WEXITSTATUS(wstatus); 684 } else if (WIFSIGNALED(wstatus)) { 685 xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus)); 686 } else if (WIFSTOPPED(wstatus)) { 687 xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus)); 688 } 689 690 return 111; 691 } 692 693 static void init_rng(void) 694 { 695 int fd = open("/dev/urandom", O_RDONLY); 696 697 if (fd >= 0) { 698 unsigned int foo; 699 ssize_t ret; 700 701 /* can't fail */ 702 ret = read(fd, &foo, sizeof(foo)); 703 assert(ret == sizeof(foo)); 704 705 close(fd); 706 srand(foo); 707 } else { 708 srand(time(NULL)); 709 } 710 } 711 712 int main(int argc, char *argv[]) 713 { 714 int e1, e2, wstatus; 715 pid_t s, c, ret; 716 int pipefds[2]; 717 718 parse_opts(argc, argv); 719 720 init_rng(); 721 722 e1 = pipe(pipefds); 723 if (e1 < 0) 724 die_perror("pipe"); 725 726 s = xfork(); 727 if (s == 0) 728 return server(pipefds[1]); 729 730 close(pipefds[1]); 731 732 /* wait until server bound a socket */ 733 e1 = read(pipefds[0], &e1, 4); 734 assert(e1 == 4); 735 736 c = xfork(); 737 if (c == 0) 738 return client(pipefds[0]); 739 740 close(pipefds[0]); 741 742 ret = waitpid(s, &wstatus, 0); 743 if (ret == -1) 744 die_perror("waitpid"); 745 e1 = rcheck(wstatus, "server"); 746 ret = waitpid(c, &wstatus, 0); 747 if (ret == -1) 748 die_perror("waitpid"); 749 e2 = rcheck(wstatus, "client"); 750 751 return e1 ? e1 : e2; 752 } 753