/* * Mausezahn - A fast versatile traffic generator * Copyright (C) 2008-2010 Herbert Haas * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html * */ #include "mz.h" #include "mops.h" #include <netpacket/packet.h> #include <netinet/ether.h> // PURPOSE: Find usable network devices // // NOTE: // // 1. Ignores devices without IP address // 2. Ignores loopback (etc) // // RETURN VALUES: // // 0 if usable device found (device_list[] and tx.device set) // 1 if no usable device found // int lookupdev(void) { // char *tx.device is global, see as.h char ipaddress[IPADDRSIZE+1], errbuf[PCAP_ERRBUF_SIZE]; pcap_if_t *alldevs, *index = NULL; pcap_addr_t *pcap_addr; int i=0; // FIRST get a list of all available devices // if (pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr," mz: %s\n",errbuf); return 1; } index = (pcap_if_t *) alldevs; while (index) { if (index->addresses) { pcap_addr = index->addresses; while(pcap_addr) { if (pcap_addr->addr && (pcap_addr->addr->sa_family==AF_INET)) { if (inet_ntop(pcap_addr->addr->sa_family, (void *)&pcap_addr->addr->sa_data[2], ipaddress, IPADDRSIZE)) { if (verbose) { fprintf(stderr," mz: device %s got assigned %s ", index->name, ipaddress); } if (strncmp(ipaddress, "127", 3)==0) { if (verbose) fprintf(stderr, "(loopback)\n"); strncpy(device_list[i].dev, index->name, 9); strncpy(device_list[i].ip_str, ipaddress, IPADDRSIZE); device_list[i].phy=0; get_if_addr(index->name, device_list[i].ip, device_list[i].mac); get_if_addr(index->name, device_list[i].ip_mops, device_list[i].mac_mops); i++; } else if (strncmp(ipaddress, "169.254", 7)==0) { if (verbose) fprintf(stderr, "but IGNORED (cause: host-scope address)\n"); } else // FOUND VALID INTERFACE { if (verbose) fprintf(stderr, "and is a possible candidate.\n"); strncpy(device_list[i].dev, index->name, 9); strncpy(device_list[i].ip_str, ipaddress, IPADDRSIZE); device_list[i].phy=1; get_if_addr(index->name, device_list[i].ip, device_list[i].mac); get_if_addr(index->name, device_list[i].ip_mops, device_list[i].mac_mops); i++; } // Select only interfaces with IP addresses // but avoid those that start with 127 or 169.254 // Put the remaining on a list. If this list has more than one entry // ask the user which interface to listen to. } else { return 1; } } pcap_addr = pcap_addr->next; } // closes while(pcap_addr) } index = index->next; } // closes while (index) device_list_entries = i; /* if (verbose) { for (i=0; i<device_list_entries; i++) { fprintf(stderr, " mz: Found device %s with IP %s\n", device_list[i].dev, device_list[i].ip_str); } } */ // No device found: if (device_list_entries==0) return 1; // Else device found: // initialize tx.device with first entry of the device_list strncpy (tx.device, device_list[0].dev, 16); return 0; } // Determines ip and mac address of specified interface 'ifname' // Caller must provide an unsigned char ip[4], mac[6] // int get_if_addr (char *ifname, u_int8_t *ip, u_int8_t *mac) { int fd, i; struct ifreq ifr; struct sockaddr_in saddr; u_int8_t *x; ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name, ifname , IFNAMSIZ-1); // we must open a socket to get the addresses fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) return 1; // get mac ioctl(fd, SIOCGIFHWADDR, &ifr); for (i=0; i<6; i++) mac[i]= (u_int8_t) ifr.ifr_hwaddr.sa_data[i]; // get IP ioctl(fd, SIOCGIFADDR, &ifr); saddr=*((struct sockaddr_in *)(&(ifr.ifr_addr))); x = (u_int8_t*)&saddr.sin_addr; ip[0]=*x; ip[1]=*(x+1); ip[2]=*(x+2); ip[3]=*(x+3); close(fd); return 0; } // For a given device name, find out the following parameters: // // - MTU // - Network // - Mask // - Default GW (IP) // - Default GW (MAC) // - Open packet socket (if not already done) // int get_dev_params (char *name) { FILE *fd; char f[10][16], line[256]; int in=0, nw=1, gw=2, mk=7; // default columns in /proc/net/route for interface, network, gateway, and mask. unsigned int tmp[4], net[4]={0,0,0,0}, dgw[4], mask[4]={0,0,0,0}; int i=0, flag=0, nw_found=0, gw_found=0, devind=0, dev_found=0; struct ifreq si; struct sockaddr_ll psock; int ps, index, mtu; struct arp_table_struct *cur; // 1. Check if device is already present in our device_list for (i=0; i<device_list_entries; i++) { if (strncmp(device_list[i].dev, name, 16)==0) { devind=i; dev_found=1; break; } } if (dev_found==0) return 1; // ERROR: device name not found !!!! // 2. find network, gateway, and mask fd = fopen("/proc/net/route", "r"); while (fgets(line, 255, fd)!=NULL) { sscanf(line, " %s %s %s %s %s %s %s %s %s %s", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]); if (!flag) { // find columns (we do NOT assume that the order of columns is the same everywhere) for (i=0; i<10; i++) { if (strncasecmp(f[i],"iface", 16)==0) in=i; if (strncasecmp(f[i],"destination", 16)==0) nw=i; if (strncasecmp(f[i],"gateway", 16)==0) gw=i; if (strncasecmp(f[i],"mask", 16)==0) mk=i; } flag=1; } if (strncmp(f[in], name, 16)==0) { // interface found // Determine network if ((strncmp(f[nw],"00000000",8)!=0) && (strncmp(f[gw],"00000000",8)==0)) { // ignore 169.254 and 127 networks sscanf(f[nw],"%02x%02x%02x%02x",&tmp[3], &tmp[2], &tmp[1], &tmp[0]); if ((tmp[0]!=127) && (tmp[0]!=169)) { nw_found=1; net[0]=tmp[0]; net[1]=tmp[1]; net[2]=tmp[2]; net[3]=tmp[3]; // also get mask for that network sscanf(f[mk],"%02x%02x%02x%02x",&tmp[3], &tmp[2], &tmp[1], &tmp[0]); mask[0]=tmp[0]; mask[1]=tmp[1]; mask[2]=tmp[2]; mask[3]=tmp[3]; } } // Determine gateway if ((strncmp(f[nw],"00000000",8)==0) && (strncmp(f[gw],"00000000",8)!=0)) { sscanf(f[gw],"%02x%02x%02x%02x",&dgw[3], &dgw[2], &dgw[1], &dgw[0]); gw_found=1; } } } fclose(fd); // 3. Get device index, determine MTU, // and bind socket to device for later TX and RX // if socket is already open, then close and re-open it! if (device_list[devind].ps>=0) { close(device_list[devind].ps); device_list[devind].ps=-1; } if (device_list[devind].ps<0) { ps = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); //ETH_P_ALL, ETH_P_802_3); if (ps<0) { fprintf(stderr, " Warning: [lookupdev.c get_dev_params()] Cannot open socket!\n"); return 1; } // Get device index strncpy(si.ifr_name, name, IFNAMSIZ); if (ioctl(ps, SIOCGIFINDEX, &si)==-1) { perror("ioctl"); close(ps); return 1; } index=si.ifr_ifindex; // Get MTU if (ioctl(ps, SIOCGIFMTU, &si)==-1) { perror("ioctl"); close(ps); return 1; } mtu = si.ifr_mtu; // ***** bind socket for later TX and RX **** psock.sll_family = AF_PACKET; // evident // psock.sll_protocol = 0; // unsigned short - Physical layer protocol psock.sll_ifindex = index; // int - Interface number psock.sll_hatype = 0; // unsigned short - Header type //ARPHRD_ETHER psock.sll_pkttype = 0; // unsigned char - Packet type psock.sll_halen = 6; // unsigned char - Length of address bind(ps, (const struct sockaddr *) &psock, sizeof(psock)); // <= !!! device_list[devind].ps = ps; // Note that close(ps) must be done upon termination } // Get MAC of default gateway service_arp(name, device_list[devind].ip_gw, device_list[devind].mac_gw); usleep(200); // this is a VERY short delay but it usually works in today's LANs cur=device_list[devind].arp_table; while(cur!=NULL) { if ((cur->sip[0]==dgw[0]) && (cur->sip[1]==dgw[1]) && (cur->sip[2]==dgw[2]) && (cur->sip[3]==dgw[3])) { // entry found! for (i=0; i<6; i++) { device_list[devind].mac_gw[i] = cur->smac[i]; } } cur=cur->next; } // FINALLY: Copy findings in device_list if (device_list[devind].phy) { for (i=0; i<4; i++) { device_list[devind].net[i] = net[i]; device_list[devind].mask[i] = mask[i]; device_list[devind].ip_gw[i] = dgw[i]; } } else { for (i=0; i<4; i++) { device_list[devind].net[i] = 0; device_list[devind].mask[i] = 0; device_list[devind].ip_gw[i] = 0; } } device_list[devind].index = index; device_list[devind].mtu = mtu; return 0; }