static void fragroute_process(const struct pcap_pkthdr *hdr, void *buf, size_t len, void *arg) { struct pktq pktq; struct pkt *pkt, *next; if ((pkt = pkt_new()) == NULL) { warn("pkt_new"); return; } if (ETH_HDR_LEN + len > PKT_BUF_LEN) { warn("dropping oversized packet"); return; } memcpy(pkt->pkt_data + ETH_HDR_LEN, buf, len); pkt->pkt_end = pkt->pkt_data + ETH_HDR_LEN + len; pkt_decorate(pkt); if (pkt->pkt_ip == NULL) { warn("dropping non-IP packet"); return; } eth_pack_hdr(pkt->pkt_eth, ctx.dmac.addr_eth, ctx.smac.addr_eth, ETH_TYPE_IP); pkt->pkt_ip->ip_src = ctx.src.addr_ip; ip_checksum(pkt->pkt_ip, len); /* Forward this packet along as is. */ if(ctx.dfile && eth_send(ctx.eth, pkt->pkt_data, pkt->pkt_end - pkt->pkt_data) < 0) warn("eth_send"); TAILQ_INIT(&pktq); TAILQ_INSERT_TAIL(&pktq, pkt, pkt_next); mod_apply(&pktq); for (pkt = TAILQ_FIRST(&pktq); pkt != TAILQ_END(&pktq); pkt = next) { next = TAILQ_NEXT(pkt, pkt_next); _resend_outgoing(pkt); } }
int ip_opt_apply(void *d, struct pktq *pktq) { struct ip_opt *opt = (struct ip_opt *)d; struct pkt *pkt; size_t len; TAILQ_FOREACH(pkt, pktq, pkt_next) { len = ip_add_option(pkt->pkt_ip, PKT_BUF_LEN - ETH_HDR_LEN, IP_PROTO_IP, opt, opt->opt_len); if (len > 0) { pkt->pkt_end += len; pkt_decorate(pkt); ip_checksum(pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); } }
int tcp_opt_apply(void *d, struct pktq *pktq, struct rule **next_rule) { struct tcp_opt *opt = (struct tcp_opt *)d; struct pkt *pkt; size_t len; TAILQ_FOREACH(pkt, pktq, pkt_next) { uint16_t eth_type = htons(pkt->pkt_eth->eth_type); len = inet_add_option(eth_type, pkt->pkt_ip, sizeof(pkt->pkt_data) - ETH_HDR_LEN, IP_PROTO_TCP, opt, opt->opt_len); if (len > 0) { pkt->pkt_end += len; pkt_decorate(pkt); inet_checksum(eth_type, pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); } }
static struct pkt * recv_pkt(struct timeval *tv) { struct pcap_pkthdr phdr; struct timeval now, start; struct pkt *pkt; u_char *p; long timeout_usec; int i; timeout_usec = tv->tv_sec * 1000000 + tv->tv_usec; gettimeofday(&start, NULL); /* * XXX - can't select() on pcap_fileno on Solaris, * seems to be unreliable on Linux as well. *sigh* */ for (;;) { gettimeofday(&now, NULL); if ((p = (u_char *)pcap_next(ctx.pcap, &phdr)) != NULL || (now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec > timeout_usec) break; } if (p == NULL) return (NULL); p += ctx.dloff; i = phdr.caplen - ctx.dloff; pkt = pkt_new(); memcpy(pkt->pkt_eth_data, p, i); pkt->pkt_end = pkt->pkt_eth_data + i; pkt_decorate(pkt); tv->tv_sec = phdr.ts.tv_sec - start.tv_sec; tv->tv_usec = phdr.ts.tv_usec - start.tv_usec; return (pkt); }
int ip6_opt_apply(void *d, struct pktq *pktq) { struct ip6_opt_data *opt = (struct ip6_opt_data *)d; struct __ip6_ext_data_routing* route; struct ip6_ext_hdr* ext; int offset, len; struct pkt *pkt; uint8_t nxt, iph_nxt; uint8_t* p; int i; TAILQ_FOREACH(pkt, pktq, pkt_next) { uint16_t eth_type = htons(pkt->pkt_eth->eth_type); if (eth_type != ETH_TYPE_IPV6) { continue; } nxt = pkt->pkt_ip6->ip6_nxt; ext = (struct ip6_ext_hdr*)(((u_char*)pkt->pkt_ip6) + IP6_HDR_LEN); if (opt->type == OPT6_TYPE_ROUTE) { offset = 8 + IP6_ADDR_LEN * opt->u.route.segments; memmove(((u_char*)ext) + offset, ext, pkt->pkt_end - (u_char*)ext); pkt->pkt_end += offset; pkt->pkt_ip_data += offset; len = (IP6_ADDR_LEN / 8) * opt->u.route.segments; route = (struct __ip6_ext_data_routing*)ext; ext->ext_data.routing.type = 0; ext->ext_data.routing.segleft = opt->u.route.segments; ((uint32_t*)ext)[1] = 0; /* reserved */ iph_nxt = IP_PROTO_ROUTING; p = (uint8_t*)(ext) + 8; for (i = 0; i < opt->u.route.segments; ++i, p += IP6_ADDR_LEN) { memcpy(p, opt->u.route.addr[i].addr_data8, IP6_ADDR_LEN); } } else if (opt->type == OPT6_TYPE_RAW) { offset = opt->u.raw.len; memmove(((u_char*)ext) + offset, ext, pkt->pkt_end - (u_char*)ext); pkt->pkt_end += offset; pkt->pkt_ip_data += offset; iph_nxt = opt->u.raw.proto; p = (uint8_t*)ext; memcpy(p, opt->u.raw.data8, opt->u.raw.len); #if 0 printf("len: %d, data %02x %02x %02x %02x %02x %02x %02x %02x\n", opt->u.raw.len, opt->u.raw.data8[0], opt->u.raw.data8[1], opt->u.raw.data8[2], opt->u.raw.data8[3], opt->u.raw.data8[4], opt->u.raw.data8[5], opt->u.raw.data8[6], opt->u.raw.data8[7]); #endif len = (opt->u.raw.len - 8) / 8; } else { continue; } ext->ext_nxt = nxt; ext->ext_len = len; pkt->pkt_ip6->ip6_nxt = iph_nxt; pkt->pkt_ip6->ip6_plen = htons(htons(pkt->pkt_ip6->ip6_plen) + offset); /* XXX: do we need it? */ pkt_decorate(pkt); /* ip6_checksum(pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); */ }
int main(int argc, char *argv[]) { struct intf_entry ifent; intf_t *intf; int i, tests; char *cmd; if (argc < 3) usage(); for (tests = 0, i = 1; i < argc - 1; i++) { cmd = argv[i]; if (strcmp(cmd, "all") == 0) tests = ~0; else if (strcmp(cmd, "ping") == 0) tests |= TEST_PING; else if (strcmp(cmd, "ip-opt") == 0) tests |= TEST_IP_OPT; else if (strcmp(cmd, "ip-tracert") == 0) tests |= TEST_IP_TRACERT; else if (strcmp(cmd, "frag") == 0) tests |= TEST_FRAG; else if (strcmp(cmd, "frag-new") == 0) tests |= TEST_FRAG_NEW; else if (strcmp(cmd, "frag-old") == 0) tests |= TEST_FRAG_OLD; else if (strcmp(cmd, "frag-timeout") == 0) tests |= TEST_FRAG_TIMEOUT; else usage(); } if (addr_aton(argv[i], &ctx.dst) < 0) err(1, "invalid host %s", argv[i]); if ((intf = intf_open()) == NULL) err(1, "couldn't open interface handle"); ifent.intf_len = sizeof(ifent); if (intf_get_dst(intf, &ifent, &ctx.dst) < 0) err(1, "couldn't find interface for %s", addr_ntoa(&ctx.dst)); memcpy(&ctx.src, &ifent.intf_addr, sizeof(ctx.src)); ctx.src.addr_bits = IP_ADDR_BITS; intf_close(intf); if ((ctx.ip = ip_open()) == NULL) err(1, "couldn't open raw IP interface"); if ((ctx.pcap = pcap_open(ifent.intf_name)) == NULL) err(1, "couldn't open %s for sniffing", ifent.intf_name); if ((ctx.dloff = pcap_dloff(ctx.pcap)) < 0) err(1, "couldn't determine link layer offset"); ctx.rnd = rand_open(); pkt_init(16); TAILQ_INIT(&ctx.pktq); ping = pkt_new(); ip_pack_hdr(ping->pkt_ip, 0, IP_HDR_LEN + 8 + 24, 666, 0, IP_TTL_DEFAULT, IP_PROTO_ICMP, ctx.src.addr_ip, ctx.dst.addr_ip); icmp_pack_hdr_echo(ping->pkt_icmp, ICMP_ECHO, ICMP_CODE_NONE, 666, 1, "AAAAAAAABBBBBBBBCCCCCCCC", 24); ping->pkt_end = ping->pkt_eth_data + IP_HDR_LEN + 8 + 24; pkt_decorate(ping); if ((tests & TEST_PING) != 0) test_ping(); if ((tests & TEST_IP_OPT) != 0) test_ip_opt(); if ((tests & TEST_IP_TRACERT) != 0) test_ip_tracert(); if ((tests & TEST_FRAG) != 0) test_frag(NULL, 0); if ((tests & TEST_FRAG_NEW) != 0) test_frag("new", 0); if ((tests & TEST_FRAG_OLD) != 0) test_frag("old", 0); if ((tests & TEST_FRAG_TIMEOUT) != 0) test_frag(NULL, 1); rand_close(ctx.rnd); pcap_close(ctx.pcap); ip_close(ctx.ip); exit(0); }