static void dump_packet(void) { memcpy(dump, &dump[DUMP_WIDTH], DUMP_WIDTH * (DUMP_HEIGHT - 1)); tcpdump_print(&dump[DUMP_WIDTH * (DUMP_HEIGHT - 1)], DUMP_WIDTH); CTK_WIDGET_REDRAW(&dumplabel); }
/** * Main loop to rewrite packets */ int rewrite_packets(tcpedit_t *tcpedit, pcap_t *pin, pcap_dumper_t *pout) { tcpr_dir_t cache_result = TCPR_DIR_C2S; /* default to primary */ struct pcap_pkthdr pkthdr, *pkthdr_ptr; /* packet header */ const u_char *pktconst = NULL; /* packet from libpcap */ u_char **pktdata = NULL; static u_char *pktdata_buff; static char *frag = NULL; COUNTER packetnum = 0; int rcode, frag_len, i, proto; pkthdr_ptr = &pkthdr; if (pktdata_buff == NULL) pktdata_buff = (u_char *)safe_malloc(MAXPACKET); pktdata = &pktdata_buff; if (frag == NULL) frag = (char *)safe_malloc(MAXPACKET); /* MAIN LOOP * Keep sending while we have packets or until * we've sent enough packets */ while ((pktconst = pcap_next(pin, pkthdr_ptr)) != NULL) { packetnum++; dbgx(2, "packet " COUNTER_SPEC " caplen %d", packetnum, pkthdr.caplen); /* * copy over the packet so we can pad it out if necessary and * because pcap_next() returns a const ptr */ memcpy(*pktdata, pktconst, pkthdr.caplen); #ifdef ENABLE_VERBOSE if (options.verbose) tcpdump_print(&tcpdump, pkthdr_ptr, *pktdata); #endif /* Dual nic processing? */ if (options.cachedata != NULL) { cache_result = check_cache(options.cachedata, packetnum); } /* sometimes we should not send the packet, in such cases * no point in editing this packet at all, just write it to the * output file (note, we can't just remove it, or the tcpprep cache * file will loose it's indexing */ if (cache_result == TCPR_DIR_NOSEND) goto WRITE_PACKET; /* still need to write it so cache stays in sync */ if ((rcode = tcpedit_packet(tcpedit, &pkthdr_ptr, pktdata, cache_result)) == TCPEDIT_ERROR) { return -1; } else if ((rcode == TCPEDIT_SOFT_ERROR) && HAVE_OPT(SKIP_SOFT_ERRORS)) { /* don't write packet */ dbgx(1, "Packet " COUNTER_SPEC " is suppressed from being written due to soft errors", packetnum); continue; } WRITE_PACKET: #ifdef ENABLE_FRAGROUTE if (options.frag_ctx == NULL) { /* write the packet when there's no fragrouting to be done */ pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata); } else { /* get the L3 protocol of the packet */ proto = tcpedit_l3proto(tcpedit, AFTER_PROCESS, *pktdata, pkthdr_ptr->caplen); /* packet is IPv4/IPv6 AND needs to be fragmented */ if ((proto == ETHERTYPE_IP || proto == ETHERTYPE_IP6) && ((options.fragroute_dir == FRAGROUTE_DIR_BOTH) || (cache_result == TCPR_DIR_C2S && options.fragroute_dir == FRAGROUTE_DIR_C2S) || (cache_result == TCPR_DIR_S2C && options.fragroute_dir == FRAGROUTE_DIR_S2C))) { if (fragroute_process(options.frag_ctx, *pktdata, pkthdr_ptr->caplen) < 0) errx(-1, "Error processing packet via fragroute: %s", options.frag_ctx->errbuf); i = 0; while ((frag_len = fragroute_getfragment(options.frag_ctx, &frag)) > 0) { /* frags get the same timestamp as the original packet */ dbgx(1, "processing packet " COUNTER_SPEC " frag: %u (%d)", packetnum, i++, frag_len); pkthdr_ptr->caplen = frag_len; pkthdr_ptr->len = frag_len; pcap_dump((u_char *)pout, pkthdr_ptr, (u_char *)frag); } } else { /* write the packet without fragroute */ pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata); } } #else /* write the packet when there's no fragrouting to be done */ pcap_dump((u_char *)pout, pkthdr_ptr, *pktdata); #endif } /* while() */ return 0; }
/** * This is the callback we use with pcap_dispatch to process * each packet recieved by libpcap on the two interfaces. * Need to return > 0 to denote success */ static int live_callback(struct live_data_t *livedata, struct pcap_pkthdr *pkthdr, const u_char * nextpkt) { ipv4_hdr_t *ip_hdr = NULL; ipv6_hdr_t *ip6_hdr = NULL; pcap_t *send = NULL; static u_char *pktdata = NULL; /* full packet buffer */ int cache_mode, retcode; static unsigned long packetnum = 0; struct macsrc_t *node, finder; /* rb tree nodes */ #ifdef DEBUG u_char dstmac[ETHER_ADDR_LEN]; #endif u_int16_t l2proto; packetnum++; dbgx(2, "packet %lu caplen %d", packetnum, pkthdr->caplen); /* only malloc the first time */ if (pktdata == NULL) { /* create packet buffers */ pktdata = (u_char *)safe_malloc(MAXPACKET); } else { /* zero out the old packet info */ memset(pktdata, '\0', MAXPACKET); } /* copy the packet to our buffer */ memcpy(pktdata, nextpkt, pkthdr->caplen); #ifdef ENABLE_VERBOSE /* decode packet? */ if (livedata->options->verbose) tcpdump_print(livedata->options->tcpdump, pkthdr, nextpkt); #endif /* lookup our source MAC in the tree */ memcpy(&finder.key, &pktdata[ETHER_ADDR_LEN], ETHER_ADDR_LEN); #ifdef DEBUG memcpy(&dstmac, pktdata, ETHER_ADDR_LEN); dbgx(1, "SRC MAC: " MAC_FORMAT "\tDST MAC: " MAC_FORMAT, MAC_STR(finder.key), MAC_STR(dstmac)); #endif /* first, is this a packet sent locally? If so, ignore it */ if ((memcmp(livedata->options->intf1_mac, &finder.key, ETHER_ADDR_LEN)) == 0) { dbgx(1, "Packet matches the MAC of %s, skipping.", livedata->options->intf1); return (1); } else if ((memcmp(livedata->options->intf2_mac, &finder.key, ETHER_ADDR_LEN)) == 0) { dbgx(1, "Packet matches the MAC of %s, skipping.", livedata->options->intf2); return (1); } node = RB_FIND(macsrc_tree, &macsrc_root, &finder); /* if we can't find the node, build a new one */ if (node == NULL) { dbg(1, "Unable to find MAC in the tree"); node = new_node(); node->source = livedata->source; memcpy(&node->key, &finder.key, ETHER_ADDR_LEN); RB_INSERT(macsrc_tree, &macsrc_root, node); } /* otherwise compare sources */ else if (node->source != livedata->source) { dbg(1, "Found the dest MAC in the tree and it doesn't match this source NIC... skipping packet"); /* * IMPORTANT!!! * Never send a packet out the same interface we sourced it on! */ return (1); } /* what is our cache mode? */ cache_mode = livedata->source == PCAP_INT1 ? TCPR_DIR_C2S : TCPR_DIR_S2C; l2proto = tcpedit_l3proto(livedata->tcpedit, BEFORE_PROCESS, pktdata, pkthdr->len); dbgx(2, "Packet protocol: %04hx", l2proto); /* should we skip this packet based on CIDR match? */ if (l2proto == ETHERTYPE_IP) { dbg(3, "Packet is IPv4"); ip_hdr = (ipv4_hdr_t *)tcpedit_l3data(livedata->tcpedit, BEFORE_PROCESS, pktdata, pkthdr->len); /* look for include or exclude CIDR match */ if (livedata->options->xX.cidr != NULL) { if (!process_xX_by_cidr_ipv4(livedata->options->xX.mode, livedata->options->xX.cidr, ip_hdr)) { dbg(2, "Skipping IPv4 packet due to CIDR match"); return (1); } } } else if (l2proto == ETHERTYPE_IP6) { dbg(3, "Packet is IPv6"); ip6_hdr = (ipv6_hdr_t *)tcpedit_l3data(livedata->tcpedit, BEFORE_PROCESS, pktdata, pkthdr->len); /* look for include or exclude CIDR match */ if (livedata->options->xX.cidr != NULL) { if (!process_xX_by_cidr_ipv6(livedata->options->xX.mode, livedata->options->xX.cidr, ip6_hdr)) { dbg(2, "Skipping IPv6 packet due to CIDR match"); return (1); } } } if ((retcode = tcpedit_packet(livedata->tcpedit, &pkthdr, &pktdata, cache_mode)) < 0) { if (retcode == TCPEDIT_SOFT_ERROR) { return 1; } else { /* TCPEDIT_ERROR */ return -1; } } /* * send packets out the OTHER interface * and update the dst mac if necessary */ switch(node->source) { case PCAP_INT1: dbgx(2, "Packet source was %s... sending out on %s", livedata->options->intf1, livedata->options->intf2); send = livedata->options->pcap2; break; case PCAP_INT2: dbgx(2, "Packet source was %s... sending out on %s", livedata->options->intf2, livedata->options->intf1); send = livedata->options->pcap1; break; default: errx(-1, "wtf? our node->source != PCAP_INT1 and != PCAP_INT2: %c", node->source); } /* * write packet out on the network */ if (pcap_sendpacket(send, pktdata, pkthdr->caplen) < 0) errx(-1, "Unable to send packet out %s: %s", send == livedata->options->pcap1 ? livedata->options->intf1 : livedata->options->intf2, pcap_geterr(send)); stats.bytes_sent += pkthdr->caplen; stats.pkts_sent++; dbgx(1, "Sent packet " COUNTER_SPEC, stats.pkts_sent); return (1); } /* live_callback() */