/* macrewrite - rewrite MAC addresses in a PCAP file */ /* * Copyright 2007, Brian St. Pierre, * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose, without fee, and without a * written agreement is hereby granted, provided that the above * copyright notice and this paragraph and the following two * paragraphs appear in all copies. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS * DOCUMENTATION, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER * IS ON AN "AS IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR * MODIFICATIONS. * */ /* * * Compile this file using: * * gcc -g -Wall -Werror macrewrite.c -o macrewrite -lpopt -lpcap * * (The -g is optional.) * * Tested using gcc 4.1.2, libpcap0.7-0.7.2-7, libpopt0-1.10-3 on * debian etch, 2007-9-14. */ /* * Usage: * * macrewrite FROM,TO FROM2,TO2 FROM3,TO3 < orig.pcap > new.pcap * * All "from" MAC addresses in orig.pcap will be replaced by * corresponding "to" MAC addresses in new.pcap. * * If you can't use stdin/stdout, try the -i/--input and -o/--output * options. */ #include #include #include #include #include #include #include #include void usage(poptContext optCon, int exitcode, char* error, char* addl) { poptPrintUsage(optCon, stderr, 0); if(error) { fprintf(stderr, "%s: %s\n", error, addl); } exit(exitcode); } void printmac(u_char* packetSegment) { int i = ETHER_ADDR_LEN; for(i = 0; i < ETHER_ADDR_LEN; i++) { fprintf(stderr, "%s%02x",(i == 0) ? "" : ":", *packetSegment++); } } void parsemac(const char* macStr, u_char* mac) { int binary[6]; sscanf(macStr, "%x:%x:%x:%x:%x:%x", &binary[0], &binary[1], &binary[2], &binary[3], &binary[4], &binary[5]); mac[0] = binary[0]; mac[1] = binary[1]; mac[2] = binary[2]; mac[3] = binary[3]; mac[4] = binary[4]; mac[5] = binary[5]; } int main(int argc, char** argv) { int status = 0; const int MAX_SUBS = 20; struct { u_char to[6]; u_char from[6]; int valid; } substitutions[MAX_SUBS]; const char* inputFilename = "-"; const char* outputFilename = "-"; poptContext optCon; const char* subst = NULL; int i = 0; struct poptOption optionsTable[] = { { "input", 'i', POPT_ARG_STRING, &inputFilename, 0, "Input PCAP file, defaults to '-'", "FILE" }, { "output", 'o', POPT_ARG_STRING, &outputFilename, 0, "Output PCAP file, defaults to '-'", "FILE" }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } }; pcap_t* pcapInputFile = NULL; pcap_dumper_t* pcapOutputFile = NULL; char errbuf[PCAP_ERRBUF_SIZE] = ""; /* Help from * http://www.cet.nau.edu/~mc8/Socket/Tutorials/section2.html */ const u_char* packet = NULL; struct pcap_pkthdr hdr; struct ether_header* eptr = NULL; /* * Process arguments. */ memset(substitutions, 0, sizeof(substitutions)); optCon = poptGetContext(NULL, argc, (const char**)argv, optionsTable, 0); poptSetOtherOptionHelp(optCon, "[OPTIONS]* [SUBS]\n" "Each SUB is a pair of SRC,DST " "MAC address substitutions"); if (argc < 2) { poptPrintUsage(optCon, stderr, 0); exit(1); } poptGetNextOpt(optCon); subst = poptGetArg(optCon); while(subst != NULL && i < MAX_SUBS) { char* comma = strchr(subst, ','); if(comma == NULL) { poptPrintUsage(optCon, stderr, 0); exit(1); } *comma = '\0'; parsemac(subst, substitutions[i].from); parsemac(comma + 1, substitutions[i].to); substitutions[i].valid = 1; i++; subst = poptGetArg(optCon); } poptFreeContext(optCon); /* * NOW, process the pcap file. */ pcapInputFile = pcap_open_offline(inputFilename, errbuf); pcapOutputFile = pcap_dump_open(pcapInputFile, outputFilename); packet = pcap_next(pcapInputFile, &hdr); while(packet != NULL) { /* struct pcap_pkthdr { struct timeval ts; time stamp bpf_u_int32 caplen; length of portion present bpf_u_int32; lebgth this packet (off wire) } */ eptr = (struct ether_header *)packet; for(i = 0; i < MAX_SUBS && substitutions[i].to != NULL; i++) { if(!memcmp(eptr->ether_dhost, substitutions[i].from, 6)) { memcpy(eptr->ether_dhost, substitutions[i].to, 6); } if(!memcmp(eptr->ether_shost, substitutions[i].from, 6)) { memcpy(eptr->ether_shost, substitutions[i].to, 6); } } pcap_dump((u_char*)pcapOutputFile, &hdr, packet); packet = pcap_next(pcapInputFile, &hdr); } pcap_close(pcapInputFile); pcap_dump_close(pcapOutputFile); return status; }