linux/tools/testing/selftests/net/reuseaddr_conflict.c
<<
>>
Prefs
   1/*
   2 * Test for the regression introduced by
   3 *
   4 * b9470c27607b ("inet: kill smallest_size and smallest_port")
   5 *
   6 * If we open an ipv4 socket on a port with reuseaddr we shouldn't reset the tb
   7 * when we open the ipv6 conterpart, which is what was happening previously.
   8 */
   9#include <errno.h>
  10#include <error.h>
  11#include <arpa/inet.h>
  12#include <netinet/in.h>
  13#include <stdbool.h>
  14#include <stdio.h>
  15#include <sys/socket.h>
  16#include <sys/types.h>
  17#include <unistd.h>
  18
  19#define PORT 9999
  20
  21int open_port(int ipv6, int any)
  22{
  23        int fd = -1;
  24        int reuseaddr = 1;
  25        int v6only = 1;
  26        int addrlen;
  27        int ret = -1;
  28        struct sockaddr *addr;
  29        int family = ipv6 ? AF_INET6 : AF_INET;
  30
  31        struct sockaddr_in6 addr6 = {
  32                .sin6_family = AF_INET6,
  33                .sin6_port = htons(PORT),
  34                .sin6_addr = in6addr_any
  35        };
  36        struct sockaddr_in addr4 = {
  37                .sin_family = AF_INET,
  38                .sin_port = htons(PORT),
  39                .sin_addr.s_addr = any ? htonl(INADDR_ANY) : inet_addr("127.0.0.1"),
  40        };
  41
  42
  43        if (ipv6) {
  44                addr = (struct sockaddr*)&addr6;
  45                addrlen = sizeof(addr6);
  46        } else {
  47                addr = (struct sockaddr*)&addr4;
  48                addrlen = sizeof(addr4);
  49        }
  50
  51        if ((fd = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  52                perror("socket");
  53                goto out;
  54        }
  55
  56        if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only,
  57                               sizeof(v6only)) < 0) {
  58                perror("setsockopt IPV6_V6ONLY");
  59                goto out;
  60        }
  61
  62        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
  63                       sizeof(reuseaddr)) < 0) {
  64                perror("setsockopt SO_REUSEADDR");
  65                goto out;
  66        }
  67
  68        if (bind(fd, addr, addrlen) < 0) {
  69                perror("bind");
  70                goto out;
  71        }
  72
  73        if (any)
  74                return fd;
  75
  76        if (listen(fd, 1) < 0) {
  77                perror("listen");
  78                goto out;
  79        }
  80        return fd;
  81out:
  82        close(fd);
  83        return ret;
  84}
  85
  86int main(void)
  87{
  88        int listenfd;
  89        int fd1, fd2;
  90
  91        fprintf(stderr, "Opening 127.0.0.1:%d\n", PORT);
  92        listenfd = open_port(0, 0);
  93        if (listenfd < 0)
  94                error(1, errno, "Couldn't open listen socket");
  95        fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT);
  96        fd1 = open_port(0, 1);
  97        if (fd1 >= 0)
  98                error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket");
  99        fprintf(stderr, "Opening in6addr_any:%d\n", PORT);
 100        fd1 = open_port(1, 1);
 101        if (fd1 < 0)
 102                error(1, errno, "Couldn't open ipv6 reuseport");
 103        fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT);
 104        fd2 = open_port(0, 1);
 105        if (fd2 >= 0)
 106                error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket");
 107        close(fd1);
 108        fprintf(stderr, "Opening INADDR_ANY:%d after closing ipv6 socket\n", PORT);
 109        fd1 = open_port(0, 1);
 110        if (fd1 >= 0)
 111                error(1, 0, "Was allowed to create an ipv4 reuseport on an already bound non-reuseport socket with no ipv6");
 112        fprintf(stderr, "Success");
 113        return 0;
 114}
 115