DF-0743 / live_trigger.c
/* * DF-0743 — live discriminator trigger (runs as root). * * Sends two GRE packets to a configured gre0 and tags the INNER * (decapsulated) IP packets with distinct ip_id values so tcpdump on * gre0 can tell them apart. gre_input2 BPF-taps the inner packet at * ip_gre.c:184-189 ONLY when decapsulation succeeds (i.e. the ptype * switch at ip_gre.c:164 did not fall through to return(0)). * * Packet A: ip_hl=5, real GRE ptype @20 = ETHERTYPE_IP. * inner ip_id = 0xAAAA. * -> BOTH buggy and fixed: ptype read correctly -> decapsulated * -> tcpdump on gre0 captures inner (id 0xAAAA). * * Packet B: ip_hl=7 (8 bytes options @20..27). Real GRE ptype @28 = * ETHERTYPE_IP, but option bytes @22-23 = 0x0000. * inner ip_id = 0xBBBB. * -> BUGGY: gi_ptype reads @22 = 0x0000 -> switch default -> * return(0) -> NOT decapsulated -> tcpdump captures nothing. * -> FIXED : reads ptype @28 = 0x0800 -> decapsulated -> * tcpdump captures inner (id 0xBBBB). * * Discriminator (capture count for id 0xBBBB): * buggy : 0 (packet B dropped by the misparse) * fixed : 1 (packet B decapsulated) * * Build: cc -O2 -Wall -o live_trigger live_trigger.c * Run: (root) see live_run.sh */ #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 <string.h> #include <unistd.h> #define IPPROTO_GRE 47 #define ETHERTYPE_IP 0x0800 struct gre_h { uint16_t flags; uint16_t ptype; } __attribute__((__packed__)); static uint16_t cksum16(const void *p, size_t len) { uint32_t s = 0; const uint16_t *w = p; int n = len >> 1; while (n-- > 0) s += *w++; if (len & 1) s += htons(((const uint8_t *)p)[len - 1]); s = (s >> 16) + (s & 0xffff); s += (s >> 16); return (uint16_t)(~s); } static void build_outer(uint8_t *buf, int hlen, int totlen) { memset(buf, 0, hlen); struct ip *ip = (struct ip *)buf; ip->ip_v = 4; ip->ip_hl = hlen/4; ip->ip_len = htons(totlen); ip->ip_ttl = 64; ip->ip_p = IPPROTO_GRE; inet_pton(AF_INET, "127.0.0.1", &ip->ip_src); inet_pton(AF_INET, "127.0.0.1", &ip->ip_dst); for (int i = 20; i < hlen; i++) buf[i] = 0x01; /* NOP options */ ip->ip_sum = 0; ip->ip_sum = cksum16(buf, hlen); } static void send_one(int s, int outer_hlen, int gre_off, uint16_t inner_id, uint16_t poison_ptype_at22) { uint8_t pkt[64]; build_outer(pkt, outer_hlen, sizeof(pkt)); if (poison_ptype_at22) { /* corrupt would-be gi_ptype @22-23 */ pkt[22] = (poison_ptype_at22 >> 8) & 0xff; pkt[23] = poison_ptype_at22 & 0xff; pkt[10] = 0; pkt[11] = 0; uint16_t c = cksum16(pkt, outer_hlen); memcpy(pkt+10, &c, 2); } struct gre_h *g = (struct gre_h *)(pkt + gre_off); g->flags = htons(0); g->ptype = htons(ETHERTYPE_IP); struct ip *inner = (struct ip *)(pkt + gre_off + 4); inner->ip_v = 4; inner->ip_hl = 5; inner->ip_len = htons(sizeof(pkt)-(gre_off+4)); inner->ip_id = htons(inner_id); inner->ip_ttl = 64; inner->ip_p = 1; /*ICMP*/ inet_pton(AF_INET, "127.0.0.1", &inner->ip_src); inet_pton(AF_INET, "127.0.0.1", &inner->ip_dst); inner->ip_sum = 0; inner->ip_sum = cksum16(inner, 20); struct sockaddr_in dst; memset(&dst,0,sizeof(dst)); dst.sin_family = AF_INET; inet_pton(AF_INET,"127.0.0.1",&dst.sin_addr); ssize_t n = sendto(s, pkt, sizeof(pkt), 0,(struct sockaddr*)&dst,sizeof(dst)); printf("sent %zd bytes (outer_hlen=%d gre_off=%d inner_id=0x%04x poison@22=0x%04x)\n", n, outer_hlen, gre_off, inner_id, poison_ptype_at22); } int main(void) { int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (s < 0) { perror("socket"); return 2; } int one = 1; setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)); printf("=== Packet A: ip_hl=5, ptype@20=IP, inner_id=0xAAAA ===\n"); send_one(s, 20, 20, 0xAAAA, 0); /* no poison: ip_hl=5, GRE@20 */ usleep(400000); printf("=== Packet B: ip_hl=7, ptype@28=IP, option@22=0x0000, inner_id=0xBBBB ===\n"); send_one(s, 28, 28, 0xBBBB, 0x0000);/* poison @22-23 = 0x0000 */ close(s); usleep(300000); return 0; } |