// Passes the received forward to the appropriate handler void ethernet_recv_frame(char *buf, int len) { ethernet_header *head = (ethernet_header*)buf; dprintf("received frame of length %d\n", len); //printf("type: %02x%02x", head->ether_type[0], head->ether_type[1]); //if ( memcmp(ethernet_opt_address, head->dest_addr, 6) != 0 ) // return; // ARP if ( head->ether_type[0] == 0x08 && head->ether_type[1] == 0x06 ) { arp_recv(buf, len); } // IP else if ( head->ether_type[0] == 0x08 && head->ether_type[1] == 0x00 ) { // Pass over the IP packet without the ethernet header and checksum ip_input(buf+sizeof(ethernet_header), len-sizeof(ethernet_header)-4); } }
static int arp_proc(struct netbuf *buf) { int ret = 0; switch (buf->cmd) { case ARP_CMD_MACADDR: memcpy(my_macaddr, buf->option.common.macaddr.addr, MACADDR_SIZE); break; case ARP_CMD_IPADDR: my_ipaddr = buf->option.common.ipaddr.addr; break; case ARP_CMD_RECV: ret = arp_recv(buf); break; case ARP_CMD_SEND: ret = arp_send(buf); break; default: break; } return ret; }
void *arp(char *ifname) { int sock,i; struct sockaddr_ll ifs; struct ifreq ifr; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); if(sock == -1) { fprintf(stderr, "Socket error %d.\n", errno); exit(1); } /* Get the hwaddr and ifindex of the interface */ memset(ifr.ifr_name, 0, IFNAMSIZ); strncpy(ifr.ifr_name, (char *) ifname, IFNAMSIZ); if(ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) { syslog(LOG_ERR, "error: ioctl SIOCGIFHWADDR for %s: %s\n", (char *) ifname, strerror(errno)); abort(); } memset(ifs.sll_addr, 0, ETH_ALEN); memcpy(ifs.sll_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0) { syslog(LOG_ERR, "error: ioctl SIOCGIFINDEX for %s: %s", (char *) ifname, strerror(errno)); abort(); } ifs.sll_family = AF_PACKET; ifs.sll_protocol = htons(ETH_P_ARP); ifs.sll_ifindex = ifr.ifr_ifindex; ifs.sll_hatype = ARPHRD_ETHER; ifs.sll_pkttype = PACKET_BROADCAST; ifs.sll_halen = ETH_ALEN; if(bind(sock, (struct sockaddr *)&ifs, sizeof(struct sockaddr_ll)) < 0) { fprintf(stderr, "Bind %s: %d\n", (char *) ifname, errno); abort(); } while (1) { ether_arp_frame frame; unsigned long src; unsigned long dst; struct in_addr sia; struct in_addr dia; do { pthread_testcancel(); /* Sleep a bit in order not to overload the system */ usleep(300); if (arp_recv(sock, &frame) <= 0) continue; /* Insert all the replies into ARP table */ if (frame.arp.arp_op == ntohs(ARPOP_REPLY)) { /* Received frame is an ARP reply */ struct arpreq k_arpreq; int arpsock; struct sockaddr_in *sin; if ((arpsock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "error: ARP socket for %s: %s", (char *) ifname, strerror(errno)); continue; } k_arpreq.arp_ha.sa_family = ARPHRD_ETHER; memcpy(&k_arpreq.arp_ha.sa_data, &frame.arp.arp_sha, sizeof(frame.arp.arp_sha)); k_arpreq.arp_flags = ATF_COM; if (option_arpperm) k_arpreq.arp_flags = k_arpreq.arp_flags | ATF_PERM; strncpy(k_arpreq.arp_dev, ifname, sizeof(k_arpreq.arp_dev)); k_arpreq.arp_pa.sa_family = AF_INET; sin = (struct sockaddr_in *) &k_arpreq.arp_pa; memcpy(&sin->sin_addr.s_addr, &frame.arp.arp_spa, sizeof(sin->sin_addr)); /* Update kernel ARP table with the data from reply */ if (debug) printf("Received reply: updating kernel ARP table for %s(%s).\n", inet_ntoa(sin->sin_addr), (char *) ifname); if (ioctl(arpsock, SIOCSARP, &k_arpreq) < 0) { syslog(LOG_ERR, "error: ioctl SIOCSARP for %s(%s): %s", inet_ntoa(sin->sin_addr), (char *) ifname, strerror(errno)); close(arpsock); continue; } close(arpsock); /* Check if reply is for one of the requests in request queue */ rq_process(sin->sin_addr, ifs.sll_ifindex); /* send gratuitous arp request to all other interfaces to let them * update their ARP tables quickly */ for (i=0; i <= last_iface_idx; i++) { if (strcmp(ifaces[i], ifname)) { arp_req(ifaces[i], sin->sin_addr, 1); } } } } while (frame.arp.arp_op != htons(ARPOP_REQUEST)); /* Received frame is an ARP request */ memcpy(&src,(char *)frame.arp.arp_spa,4); memcpy(&dst,(char *)frame.arp.arp_tpa,4); dia.s_addr = dst; sia.s_addr = src; if (debug) printf("Received ARP request for %s on iface %s\n", inet_ntoa(dia), (char *) ifname); if (memcmp(&dia,&sia,sizeof(dia)) && dia.s_addr != 0) { pthread_mutex_lock(&arptab_mutex); /* Relay the ARP request to all other interfaces */ for (i=0; i <= last_iface_idx; i++) { if (strcmp(ifaces[i], ifname)) { arp_req(ifaces[i], dia, 0); } } /* Add the request to the request queue */ if (debug) printf("Adding %s to request queue\n", inet_ntoa(sia)); rq_add(&frame, &ifs); pthread_mutex_unlock(&arptab_mutex); } } }