123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716 |
- /* $Id: edit_packet.c 879 2004-11-07 03:32:31Z aturner $ */
- /*
- * Copyright (c) 2001-2004 Aaron Turner.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the names of the copyright owners nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "config.h"
- #include <libnet.h>
- #include <pcap.h>
- #include "tcpreplay.h"
- #include "edit_packet.h"
- #include "cidr.h"
- #include "sll.h"
- #include "err.h"
- #include "utils.h"
- extern int maxpacket;
- extern struct options options;
- extern CIDRMAP *cidrmap_data1, *cidrmap_data2;
- /*
- * this code re-calcs the IP and Layer 4 checksums
- * the IMPORTANT THING is that the Layer 4 header
- * is contiguious in memory after *ip_hdr we're actually
- * writing to the layer 4 header via the ip_hdr ptr.
- * (Yes, this sucks, but that's the way libnet works, and
- * I was too lazy to re-invent the wheel.
- */
- void
- fix_checksums(struct pcap_pkthdr *pkthdr, ip_hdr_t * ip_hdr, libnet_t * l)
- {
- /* calc the L4 checksum */
- if (libnet_do_checksum(l, (u_char *) ip_hdr, ip_hdr->ip_p,
- ntohs(ip_hdr->ip_len) - (ip_hdr->ip_hl << 2)) < 0)
- warnx("Layer 4 checksum failed: %s", libnet_geterror(l));
- /* calc IP checksum */
- if (libnet_do_checksum((libnet_t *) l, (u_char *) ip_hdr, IPPROTO_IP,
- ntohs(ip_hdr->ip_len)) < 0)
- warnx("IP checksum failed: %s", libnet_geterror(l));
- }
- /*
- * randomizes the source and destination IP addresses based on a
- * pseudo-random number which is generated via the seed.
- * return 1 since we changed one or more IP addresses
- */
- int
- randomize_ips(struct pcap_pkthdr *pkthdr, u_char * pktdata,
- ip_hdr_t * ip_hdr, libnet_t * l, int l2len)
- {
- /* randomize IP addresses based on the value of random */
- dbg(1, "Old Src IP: 0x%08lx\tOld Dst IP: 0x%08lx",
- ip_hdr->ip_src.s_addr, ip_hdr->ip_dst.s_addr);
- ip_hdr->ip_dst.s_addr =
- (ip_hdr->ip_dst.s_addr ^ options.seed) -
- (ip_hdr->ip_dst.s_addr & options.seed);
- ip_hdr->ip_src.s_addr =
- (ip_hdr->ip_src.s_addr ^ options.seed) -
- (ip_hdr->ip_src.s_addr & options.seed);
- dbg(1, "New Src IP: 0x%08lx\tNew Dst IP: 0x%08lx\n",
- ip_hdr->ip_src.s_addr, ip_hdr->ip_dst.s_addr);
- return(1);
- }
- /*
- * this code will untruncate a packet via padding it with null
- * or resetting the actual packet len to the snaplen. In either case
- * it will recalcuate the IP and transport layer checksums.
- * return 0 if no change, 1 if change
- */
- int
- untrunc_packet(struct pcap_pkthdr *pkthdr, u_char * pktdata,
- ip_hdr_t * ip_hdr, libnet_t * l, int l2len)
- {
- /* if actual len == cap len or there's no IP header, don't do anything */
- if ((pkthdr->caplen == pkthdr->len) || (ip_hdr == NULL)) {
- return(0);
- }
- /* Pad packet or truncate it */
- if (options.trunc == PAD_PACKET) {
- /*
- * this should be an unnecessary check
- * but I've gotten a report that sometimes the caplen > len
- * which seems like a corrupted pcap
- */
- if (pkthdr->len > pkthdr->caplen) {
- memset(pktdata + pkthdr->caplen, 0, pkthdr->len - pkthdr->caplen);
- pkthdr->caplen = pkthdr->len;
- } else {
- /* i guess this is necessary if we've got a bogus pcap */
- ip_hdr->ip_len = htons(pkthdr->caplen);
- }
- }
- else if (options.trunc == TRUNC_PACKET) {
- ip_hdr->ip_len = htons(pkthdr->caplen);
- }
- else {
- errx(1, "Hello! I'm not supposed to be here!");
- }
- /* fix checksums */
- fix_checksums(pkthdr, ip_hdr, l);
- return(1);
- }
- /*
- * Do all the layer 2 rewriting: via -2 and DLT_LINUX_SLL
- * return layer 2 length on success or 0 on fail (don't send packet)
- * we fill out pktdata using the nextpkt (original packet) and l2data (user
- * specified layer2 data)
- */
- int
- rewrite_l2(struct pcap_pkthdr *pkthdr, u_char * pktdata, const u_char * nextpkt,
- u_int32_t linktype, int l2enabled, char *l2data, int l2len)
- {
- struct sll_header *sllhdr = NULL; /* Linux cooked socket header */
- struct cisco_hdlc_header *hdlc_header = NULL; /*Cisco HDLC */
- eth_hdr_t *eth_hdr = NULL;
- /*
- * Depending on the DLT and the various user supplied flags (-2, -I, -J,
- * -k, -K) we need to rewrite the layer two header. Usually this means
- * we rewrite it to look like 802.3 ethernet, but the user can do crazy
- * stuff and make it look like anything else if they use -2
- */
- switch (linktype) {
- case DLT_EN10MB: /* Standard 802.3 Ethernet */
- if (l2enabled) {
- /*
- * is new packet too big?
- */
- if ((pkthdr->caplen - LIBNET_ETH_H + l2len) > maxpacket) {
- if (options.truncate) {
- warnx("Packet length (%u) is greater then MTU; "
- "truncating packet.",
- (pkthdr->caplen - LIBNET_ETH_H + l2len));
- pkthdr->caplen = maxpacket;
- }
- else {
- warnx("Packet length (%u) is greater then MTU; "
- "skipping packet.",
- (pkthdr->caplen - LIBNET_ETH_H + l2len));
- return (0);
- }
- }
- /*
- * remove ethernet header and copy our header back
- */
- dbg(3, "Rewriting 802.3 via -2...");
- memcpy(pktdata, l2data, l2len);
- memcpy(&pktdata[l2len], (nextpkt + LIBNET_ETH_H),
- (pkthdr->caplen - LIBNET_ETH_H));
- /* update pkthdr->caplen with the new size */
- pkthdr->caplen = pkthdr->caplen - LIBNET_ETH_H + l2len;
- }
- else { /* no need to replace L2 */
- /* verify that the packet isn't > maxpacket */
- if (pkthdr->caplen > maxpacket) {
- if (options.truncate) {
- warnx("Packet length (%u) is greater then MTU; "
- "truncating packet.",
- pkthdr->caplen);
- pkthdr->caplen = maxpacket;
- }
- else {
- warnx("Packet length (%u) is greater then MTU; "
- "skipping packet.",
- pkthdr->caplen);
- return (0);
- }
- }
- /*
- * since libpcap returns a pointer to a buffer
- * malloc'd to the snaplen which might screw up
- * an untruncate situation, we have to memcpy
- * the packet to a static buffer
- */
- memcpy(pktdata, nextpkt, pkthdr->caplen);
- }
- break;
- case DLT_LINUX_SLL: /* Linux Cooked sockets */
- if (l2enabled) {
-
- dbg(3, "Rewriting Linux SLL via -2...");
- if ((pkthdr->caplen - SLL_HDR_LEN + l2len) > maxpacket) {
- if (options.truncate) {
- warnx("New packet length (%u) is greater then MTU; "
- "truncating packet.",
- (pkthdr->caplen - SLL_HDR_LEN + l2len));
- pkthdr->caplen = maxpacket;
- }
- else {
- warnx
- ("New packet length (%u) is greater then MTU; "
- "skipping packet.",
- (pkthdr->caplen - SLL_HDR_LEN + l2len));
- return (0);
- }
- }
-
- /* copy over our new L2 data */
- memcpy(pktdata, l2data, l2len);
- /* copy over the packet data, minus the SLL header */
- memcpy(&pktdata[l2len], (nextpkt + SLL_HDR_LEN),
- (pkthdr->caplen - SLL_HDR_LEN));
- /* update pktdhr.caplen with new size */
- pkthdr->caplen = pkthdr->caplen - SLL_HDR_LEN + l2len;
- }
-
- else { /* no need to rewrite L2 */
- /* verify new packet isn't > maxpacket */
- if ((pkthdr->caplen - SLL_HDR_LEN + LIBNET_ETH_H) > maxpacket) {
- if (options.truncate) {
- warnx("Packet length (%u) is greater then MTU; "
- "truncating packet.",
- (pkthdr->caplen - SLL_HDR_LEN + LIBNET_ETH_H));
- pkthdr->caplen = maxpacket;
- }
- else {
- warnx("Packet length (%u) is greater then MTU; "
- "skipping packet.",
- (pkthdr->caplen - SLL_HDR_LEN + LIBNET_ETH_H));
- return (0);
- }
- }
-
- /* rewrite as a standard 802.3 header */
- sllhdr = (struct sll_header *)nextpkt;
-
- switch (ntohs(sllhdr->sll_hatype)) {
- case 0x1: /* out on the wire */
- dbg(3, "Rewriting ethernet Linux SLL header as 802.3...");
-
- /* nothing special to do here... */
-
- /* keep processing beyond case */
- break;
-
- case 0x304: /* loopback */
- /*
- * loopback packets don't have a src/dst MAC, but we don't
- * require the SRC mac for SLL (we do require DST mac)
- */
- if (memcmp(options.intf1_smac, NULL_MAC, ETHER_ADDR_LEN) == 0) {
- warnx("Skipping SLL loopback packet.");
- return (0);
- }
- break;
-
- default:
- /* who know what the hell this is */
- warnx("Unknown sll_hatype: 0x%x. Skipping packet.",
- ntohs(sllhdr->sll_hatype));
- return (0);
- break;
- }
-
- /*
- * Regardless of out on the wire or a loopback packet
- * there are certain things we've gotta do...
- */
- /* set the SRC MAC which may also get rewritten later */
- memcpy(&pktdata[ETHER_ADDR_LEN], options.intf1_smac,
- ETHER_ADDR_LEN);
-
- /* set the Protocol type (IP, ARP, etc) */
- memcpy(&pktdata[12], &sllhdr->sll_protocol, 2);
-
- /* update lengths */
- l2len = LIBNET_ETH_H;
-
- /* copy over the packet data, minus the SLL header */
- memcpy(&pktdata[l2len], (nextpkt + SLL_HDR_LEN),
- (pkthdr->caplen - SLL_HDR_LEN));
-
- pkthdr->caplen = pkthdr->caplen - SLL_HDR_LEN + LIBNET_ETH_H;
- pkthdr->len = pkthdr->len - SLL_HDR_LEN + LIBNET_ETH_H;
-
- }
- break;
-
- case DLT_RAW: /* No ethernet header */
- if (l2enabled) {
- /*
- * is new packet too big?
- */
- dbg(3, "Appending header to RAW frame via -2...");
- if ((pkthdr->caplen + l2len) > maxpacket) {
- if (options.truncate) {
- warnx("Packet length (%u) is greater then MTU; "
- "truncating packet.", (pkthdr->caplen + l2len));
- pkthdr->caplen = maxpacket;
- }
- else {
- warnx("Packet length (%u) is greater then MTU; "
- "skipping packet.", (pkthdr->caplen + l2len));
- return (0);
- }
-
- }
-
- memcpy(pktdata, l2data, l2len);
- memcpy(&pktdata[l2len], nextpkt, pkthdr->caplen);
- pkthdr->caplen += l2len;
-
- }
-
- else { /* no need to rewrite L2 */
- warnx("rewrite_l2(): WTF? We can't process DLT_RAW without -2!");
- return(0);
- }
- break;
-
- case DLT_CHDLC: /* Cisco HDLC */
- /*
- * is new packet too big?
- */
- if (l2enabled) {
- dbg(3, "Rewriting Cisco HDLC via -2...");
- if ((pkthdr->caplen - CISCO_HDLC_LEN + l2len) > maxpacket) {
- if (options.truncate) {
- warnx("Packet length (%u) is greater then MTU; "
- "truncating packet.",
- (pkthdr->caplen - CISCO_HDLC_LEN + l2len));
- pkthdr->caplen = maxpacket;
- }
- else {
- warnx("Packet length (%u) is greater then MTU; "
- "skipping packet.",
- (pkthdr->caplen - CISCO_HDLC_LEN + l2len));
- return(0);
- }
- }
-
- memcpy(pktdata, l2data, l2len);
- memcpy(&pktdata[l2len], (nextpkt + CISCO_HDLC_LEN), (pkthdr->caplen - CISCO_HDLC_LEN));
- pkthdr->caplen = pkthdr->caplen - CISCO_HDLC_LEN + l2len;
- }
- else {
-
- /*
- * Fill out the ethernet protocol field.
- * The source/dest mac addresses which get rewritten in
- * do_packets.c
- */
- hdlc_header = (struct cisco_hdlc_header *)nextpkt;
- eth_hdr = (eth_hdr_t *)pktdata;
- eth_hdr->ether_type = hdlc_header->protocol;
-
- /* copy over L3 and above */
- memcpy(&pktdata[LIBNET_ETH_H], (nextpkt + CISCO_HDLC_LEN),
- (pkthdr->caplen - CISCO_HDLC_LEN));
-
- pkthdr->caplen += LIBNET_ETH_H - CISCO_HDLC_LEN;
-
- /* update lengths */
- l2len = LIBNET_ETH_H;
- }
- break;
- } /* switch (linktype) */
- /* return the updated layer 2 len */
- return (l2len);
- }
- /*
- * Extracts the layer 7 data from the packet for TCP, UDP, ICMP
- * returns the number of bytes and a pointer to the layer 7 data.
- * Returns 0 for no data
- */
- int
- extract_data(u_char * pktdata, int caplen, int l2len, char *l7data[])
- {
- int datalen = 0;
- eth_hdr_t *eth_hdr = NULL;
- ip_hdr_t *ip_hdr = NULL;
- tcp_hdr_t *tcp_hdr = NULL;
- udp_hdr_t *udp_hdr = NULL;
- #ifdef FORCE_ALIGN
- u_char ipbuff[MAXPACKET];
- #endif
- char *dataptr = NULL;
- /* map the ethernet header */
- eth_hdr = (eth_hdr_t *) pktdata;
- /* return zero if not IP */
- if (ntohs(eth_hdr->ether_type) != ETHERTYPE_IP) {
- dbg(2, "Skipping non-IP frame");
- return 0;
- }
- #ifdef FORCE_ALIGN
- /*
- * copy layer 3 and up to our temp packet buffer
- * for now on, we have to edit the packetbuff because
- * just before we send the packet, we copy the packetbuff
- * back onto the pkt.data + l2len buffer
- * we do all this work to prevent byte alignment issues
- */
- ip_hdr = (ip_hdr_t *) & ipbuff;
- memcpy(ip_hdr, pktdata[l2len], caplen - l2len);
- #else
- /*
- * on non-strict byte align systems, don't need to memcpy(),
- * just point to 14 bytes into the existing buffer
- */
- ip_hdr = (ip_hdr_t *) (pktdata + l2len);
- #endif
- dataptr = (char *)ip_hdr;
- /* figure out the actual datalen which might be < the caplen
- * due to ethernet padding
- */
- if (caplen > ntohs(ip_hdr->ip_len)) {
- datalen = ntohs(ip_hdr->ip_len);
- }
- else {
- datalen = caplen - l2len;
- }
- /* update the datlen to not include the IP header len */
- datalen -= ip_hdr->ip_hl << 2;
- dataptr += ip_hdr->ip_hl << 2;
- if (datalen <= 0)
- goto nodata;
- /* TCP ? */
- if (ip_hdr->ip_p == IPPROTO_TCP) {
- tcp_hdr = (tcp_hdr_t *) get_layer4(ip_hdr);
- datalen -= tcp_hdr->th_off << 2;
- if (datalen <= 0)
- goto nodata;
- dataptr += tcp_hdr->th_off << 2;
- }
- /* UDP ? */
- else if (ip_hdr->ip_p == IPPROTO_UDP) {
- udp_hdr = (udp_hdr_t *) get_layer4(ip_hdr);
- datalen -= LIBNET_UDP_H;
- if (datalen <= 0)
- goto nodata;
- dataptr += LIBNET_UDP_H;
- }
- /* ICMP ? just ignore it for now */
- else if (ip_hdr->ip_p == IPPROTO_ICMP) {
- dbg(2, "Ignoring any possible data in ICMP packet");
- goto nodata;
- }
- /* unknown proto, just dump everything past the IP header */
- else {
- dbg(2, "Unknown protocol, dumping everything past the IP header");
- dataptr = (char *)ip_hdr;
- }
- dbg(2, "packet had %d bytes of layer 7 data", datalen);
- memcpy(l7data, dataptr, datalen);
- return datalen;
- nodata:
- dbg(2, "packet has no data, skipping...");
- return 0;
- }
- /*
- * takes a CIDR notation netblock and uses that to "remap" given IP
- * onto that netblock. ie: 10.0.0.0/8 and 192.168.55.123 -> 10.168.55.123
- * while 10.150.9.0/24 and 192.168.55.123 -> 10.150.9.123
- */
- u_int32_t
- remap_ip(CIDR *cidr, const u_int32_t original)
- {
- u_int32_t ipaddr = 0, network = 0, mask = 0, result = 0;
- mask = ~0; /* turn on all the bits */
- /* shift over by correct # of bits */
- mask = mask << (32 - cidr->masklen);
- /* apply the mask to the network */
- network = htonl(cidr->network) & mask;
- /* apply the reverse of the mask to the IP */
- mask = mask ^ ~0;
- ipaddr = ntohl(original) & mask;
- /* merge the network portion and ip portions */
- result = network ^ ipaddr;
-
- /* return the result in network byte order */
- return(htonl(result));
- }
- /*
- * rewrite IP address (layer3)
- * uses -N to rewrite (map) one subnet onto another subnet
- * return 0 if no change, 1 or 2 if changed
- */
- int
- rewrite_ipl3(ip_hdr_t * ip_hdr, libnet_t *l)
- {
- CIDRMAP *cidrmap1 = NULL, *cidrmap2 = NULL;
- int didsrc = 0, diddst = 0, loop = 1;
- /* anything to rewrite? */
- if (cidrmap_data1 == NULL)
- return(0);
- /* don't play with the main pointers */
- if (l == options.intf1) {
- cidrmap1 = cidrmap_data1;
- cidrmap2 = cidrmap_data2;
- } else {
- cidrmap1 = cidrmap_data2;
- cidrmap2 = cidrmap_data1;
- }
-
- /* loop through the cidrmap to rewrite */
- do {
- if ((! diddst) && ip_in_cidr(cidrmap2->from, ip_hdr->ip_dst.s_addr)) {
- ip_hdr->ip_dst.s_addr = remap_ip(cidrmap2->to, ip_hdr->ip_dst.s_addr);
- dbg(2, "Remapped dst addr to: %s", inet_ntoa(ip_hdr->ip_dst));
- diddst = 1;
- }
- if ((! didsrc) && ip_in_cidr(cidrmap1->from, ip_hdr->ip_src.s_addr)) {
- ip_hdr->ip_src.s_addr = remap_ip(cidrmap1->to, ip_hdr->ip_src.s_addr);
- dbg(2, "Remapped src addr to: %s", inet_ntoa(ip_hdr->ip_src));
- didsrc = 1;
- }
- /*
- * loop while we haven't modified both src/dst AND
- * at least one of the cidr maps have a next pointer
- */
- if ((! (diddst && didsrc)) &&
- (! ((cidrmap1->next == NULL) && (cidrmap2->next == NULL)))) {
- /* increment our ptr's if possible */
- if (cidrmap1->next != NULL)
- cidrmap1 = cidrmap1->next;
- if (cidrmap2->next != NULL)
- cidrmap2 = cidrmap2->next;
- } else {
- loop = 0;
- }
- /* Later on we should support various IP protocols which embed
- * the IP address in the application layer. Things like
- * DNS and FTP.
- */
- } while (loop);
- /* return how many changes we made */
- return (diddst + didsrc);
- }
- /*
- * rewrite IP address (arp)
- * uses -a to rewrite (map) one subnet onto another subnet
- * pointer must point to the WHOLE and CONTIGOUS memory buffer
- * because the arp_hdr_t doesn't have the space for the IP/MAC
- * addresses
- * return 0 if no change, 1 or 2 if changed
- */
- int
- rewrite_iparp(arp_hdr_t *arp_hdr, libnet_t *l)
- {
- u_char *add_hdr = NULL;
- u_int32_t *ip1 = NULL, *ip2 = NULL;
- u_int32_t newip = 0;
- CIDRMAP *cidrmap1 = NULL, *cidrmap2 = NULL;
- int didsrc = 0, diddst = 0, loop = 1;
- /* figure out what mapping to use */
- if (l == options.intf1) {
- cidrmap1 = cidrmap_data1;
- cidrmap2 = cidrmap_data2;
- } else if (l == options.intf2) {
- cidrmap1 = cidrmap_data2;
- cidrmap2 = cidrmap_data1;
- }
- /* anything to rewrite? */
- if (cidrmap1 == NULL || cidrmap2 == NULL)
- return(0);
- /* must be IPv4 and request or reply
- * Do other op codes use the same subheader stub?
- * If so we won't need to check the op code.
- */
- if ((ntohs(arp_hdr->ar_pro) == ETHERTYPE_IP) &&
- ((ntohs(arp_hdr->ar_op) == ARPOP_REQUEST) ||
- (ntohs(arp_hdr->ar_op) == ARPOP_REPLY)))
- {
- /* jump to the addresses */
- add_hdr = (u_char *)arp_hdr;
- add_hdr += sizeof(arp_hdr_t) + arp_hdr->ar_hln;
- ip1 = (u_int32_t *)add_hdr;
- add_hdr += arp_hdr->ar_pln + arp_hdr->ar_hln;
- ip2 = (u_int32_t *)add_hdr;
- /* loop through the cidrmap to rewrite */
- do {
- /* arp request ? */
- if (ntohs(arp_hdr->ar_op) == ARPOP_REQUEST) {
- if ((!diddst) && ip_in_cidr(cidrmap2->from, *ip1)) {
- newip = remap_ip(cidrmap2->to, *ip1);
- memcpy(ip1, &newip, 4);
- diddst = 1;
- }
- if ((!didsrc) && ip_in_cidr(cidrmap1->from, *ip2)) {
- newip = remap_ip(cidrmap1->to, *ip2);
- memcpy(ip2, &newip, 4);
- didsrc = 1;
- }
- }
- /* else it's an arp reply */
- else {
- if ((!diddst) && ip_in_cidr(cidrmap2->from, *ip2)) {
- newip = remap_ip(cidrmap2->to, *ip2);
- memcpy(ip2, &newip, 4);
- diddst = 1;
- }
- if ((!didsrc) && ip_in_cidr(cidrmap1->from, *ip1)) {
- newip = remap_ip(cidrmap1->to, *ip1);
- memcpy(ip1, &newip, 4);
- didsrc = 1;
- }
- }
-
- /*
- * loop while we haven't modified both src/dst AND
- * at least one of the cidr maps have a next pointer
- */
- if ((! (diddst && didsrc)) &&
- (! ((cidrmap1->next == NULL) && (cidrmap2->next == NULL)))) {
-
- /* increment our ptr's if possible */
- if (cidrmap1->next != NULL)
- cidrmap1 = cidrmap1->next;
-
- if (cidrmap2->next != NULL)
- cidrmap2 = cidrmap2->next;
-
- } else {
- loop = 0;
- }
- } while (loop);
-
- } else {
- warnx("ARP packet isn't for IPv4! Can't rewrite IP's");
- }
- return(didsrc + diddst);
- }
|