2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
25 #include <netpacket/packet.h>
26 #include <netinet/ether.h>
29 // PURPOSE: Find usable network devices
33 // 1. Ignores devices without IP address
34 // 2. Ignores loopback (etc)
38 // 0 if usable device found (device_list[] and tx.device set)
39 // 1 if no usable device found
43 // char *tx.device is global, see as.h
46 ipaddress
[IPADDRSIZE
+1],
47 errbuf
[PCAP_ERRBUF_SIZE
];
53 pcap_addr_t
*pcap_addr
;
58 // FIRST get a list of all available devices
60 if (pcap_findalldevs(&alldevs
, errbuf
) == -1)
62 fprintf(stderr
," mz: %s\n",errbuf
);
66 index
= (pcap_if_t
*) alldevs
;
72 pcap_addr
= index
->addresses
;
75 if (pcap_addr
->addr
&& (pcap_addr
->addr
->sa_family
==AF_INET
))
77 if (inet_ntop(pcap_addr
->addr
->sa_family
,
78 (void *)&pcap_addr
->addr
->sa_data
[2],
84 fprintf(stderr
," mz: device %s got assigned %s ",
85 index
->name
, ipaddress
);
88 if (strncmp(ipaddress
, "127", 3)==0)
90 if (verbose
) fprintf(stderr
, "(loopback)\n");
91 strncpy(device_list
[i
].dev
, index
->name
, 9);
92 strncpy(device_list
[i
].ip_str
, ipaddress
, IPADDRSIZE
);
94 get_if_addr(index
->name
, device_list
[i
].ip
, device_list
[i
].mac
);
95 get_if_addr(index
->name
, device_list
[i
].ip_mops
, device_list
[i
].mac_mops
);
98 else if (strncmp(ipaddress
, "169.254", 7)==0)
100 if (verbose
) fprintf(stderr
, "but IGNORED (cause: host-scope address)\n");
102 else // FOUND VALID INTERFACE
104 if (verbose
) fprintf(stderr
, "and is a possible candidate.\n");
105 strncpy(device_list
[i
].dev
, index
->name
, 9);
106 strncpy(device_list
[i
].ip_str
, ipaddress
, IPADDRSIZE
);
107 device_list
[i
].phy
=1;
108 get_if_addr(index
->name
, device_list
[i
].ip
, device_list
[i
].mac
);
109 get_if_addr(index
->name
, device_list
[i
].ip_mops
, device_list
[i
].mac_mops
);
113 // Select only interfaces with IP addresses
114 // but avoid those that start with 127 or 169.254
115 // Put the remaining on a list. If this list has more than one entry
116 // ask the user which interface to listen to.
123 pcap_addr
= pcap_addr
->next
;
124 } // closes while(pcap_addr)
127 } // closes while (index)
129 device_list_entries
= i
;
134 for (i=0; i<device_list_entries; i++)
136 fprintf(stderr, " mz: Found device %s with IP %s\n", device_list[i].dev, device_list[i].ip_str);
142 if (device_list_entries
==0) return 1;
144 // Else device found:
145 // initialize tx.device with first entry of the device_list
146 strncpy (tx
.device
, device_list
[0].dev
, 16);
158 // Determines ip and mac address of specified interface 'ifname'
159 // Caller must provide an unsigned char ip[4], mac[6]
161 int get_if_addr (char *ifname
, u_int8_t
*ip
, u_int8_t
*mac
)
165 struct sockaddr_in saddr
;
168 ifr
.ifr_addr
.sa_family
= AF_INET
;
169 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
-1);
171 // we must open a socket to get the addresses
172 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
173 if (fd
== -1) return 1;
176 ioctl(fd
, SIOCGIFHWADDR
, &ifr
);
177 for (i
=0; i
<6; i
++) mac
[i
]= (u_int8_t
) ifr
.ifr_hwaddr
.sa_data
[i
];
180 ioctl(fd
, SIOCGIFADDR
, &ifr
);
181 saddr
=*((struct sockaddr_in
*)(&(ifr
.ifr_addr
)));
182 x
= (u_int8_t
*)&saddr
.sin_addr
;
183 ip
[0]=*x
; ip
[1]=*(x
+1); ip
[2]=*(x
+2); ip
[3]=*(x
+3);
194 // For a given device name, find out the following parameters:
200 // - Default GW (MAC)
201 // - Open packet socket (if not already done)
203 int get_dev_params (char *name
)
207 char f
[10][16], line
[256];
208 int in
=0, nw
=1, gw
=2, mk
=7; // default columns in /proc/net/route for interface, network, gateway, and mask.
209 unsigned int tmp
[4], net
[4]={0,0,0,0}, dgw
[4], mask
[4]={0,0,0,0};
210 int i
=0, flag
=0, nw_found
=0, gw_found
=0, devind
=0, dev_found
=0;
213 struct sockaddr_ll psock
;
215 struct arp_table_struct
*cur
;
216 // 1. Check if device is already present in our device_list
218 for (i
=0; i
<device_list_entries
; i
++) {
219 if (strncmp(device_list
[i
].dev
, name
, 16)==0) {
225 if (dev_found
==0) return 1; // ERROR: device name not found !!!!
229 // 2. find network, gateway, and mask
231 fd
= fopen("/proc/net/route", "r");
232 while (fgets(line
, 255, fd
)!=NULL
) {
233 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]);
234 if (!flag
) { // find columns (we do NOT assume that the order of columns is the same everywhere)
235 for (i
=0; i
<10; i
++) {
236 if (strncasecmp(f
[i
],"iface", 16)==0) in
=i
;
237 if (strncasecmp(f
[i
],"destination", 16)==0) nw
=i
;
238 if (strncasecmp(f
[i
],"gateway", 16)==0) gw
=i
;
239 if (strncasecmp(f
[i
],"mask", 16)==0) mk
=i
;
244 if (strncmp(f
[in
], name
, 16)==0) { // interface found
246 if ((strncmp(f
[nw
],"00000000",8)!=0) && (strncmp(f
[gw
],"00000000",8)==0)) {
247 // ignore 169.254 and 127 networks
248 sscanf(f
[nw
],"%02x%02x%02x%02x",&tmp
[3], &tmp
[2], &tmp
[1], &tmp
[0]);
249 if ((tmp
[0]!=127) && (tmp
[0]!=169)) {
255 // also get mask for that network
256 sscanf(f
[mk
],"%02x%02x%02x%02x",&tmp
[3], &tmp
[2], &tmp
[1], &tmp
[0]);
264 if ((strncmp(f
[nw
],"00000000",8)==0) && (strncmp(f
[gw
],"00000000",8)!=0)) {
265 sscanf(f
[gw
],"%02x%02x%02x%02x",&dgw
[3], &dgw
[2], &dgw
[1], &dgw
[0]);
274 // 3. Get device index, determine MTU,
275 // and bind socket to device for later TX and RX
277 // if socket is already open, then close and re-open it!
278 if (device_list
[devind
].ps
>=0) {
279 close(device_list
[devind
].ps
);
280 device_list
[devind
].ps
=-1;
283 if (device_list
[devind
].ps
<0) {
284 ps
= socket (PF_PACKET
, SOCK_RAW
, htons(ETH_P_IP
)); //ETH_P_ALL, ETH_P_802_3);
286 fprintf(stderr
, " Warning: [lookupdev.c get_dev_params()] Cannot open socket!\n");
291 strncpy(si
.ifr_name
, name
, IFNAMSIZ
);
292 if (ioctl(ps
, SIOCGIFINDEX
, &si
)==-1) {
297 index
=si
.ifr_ifindex
;
300 if (ioctl(ps
, SIOCGIFMTU
, &si
)==-1) {
307 // ***** bind socket for later TX and RX ****
308 psock
.sll_family
= AF_PACKET
; // evident
309 // psock.sll_protocol = 0; // unsigned short - Physical layer protocol
310 psock
.sll_ifindex
= index
; // int - Interface number
311 psock
.sll_hatype
= 0; // unsigned short - Header type //ARPHRD_ETHER
312 psock
.sll_pkttype
= 0; // unsigned char - Packet type
313 psock
.sll_halen
= 6; // unsigned char - Length of address
314 bind(ps
, (const struct sockaddr
*) &psock
, sizeof(psock
)); // <= !!!
315 device_list
[devind
].ps
= ps
; // Note that close(ps) must be done upon termination
318 // Get MAC of default gateway
319 service_arp(name
, device_list
[devind
].ip_gw
, device_list
[devind
].mac_gw
);
321 usleep(200); // this is a VERY short delay but it usually works in today's LANs
322 cur
=device_list
[devind
].arp_table
;
324 if ((cur
->sip
[0]==dgw
[0]) &&
325 (cur
->sip
[1]==dgw
[1]) &&
326 (cur
->sip
[2]==dgw
[2]) &&
327 (cur
->sip
[3]==dgw
[3])) { // entry found!
328 for (i
=0; i
<6; i
++) {
329 device_list
[devind
].mac_gw
[i
] = cur
->smac
[i
];
335 // FINALLY: Copy findings in device_list
337 if (device_list
[devind
].phy
) {
338 for (i
=0; i
<4; i
++) {
339 device_list
[devind
].net
[i
] = net
[i
];
340 device_list
[devind
].mask
[i
] = mask
[i
];
341 device_list
[devind
].ip_gw
[i
] = dgw
[i
];
345 for (i
=0; i
<4; i
++) {
346 device_list
[devind
].net
[i
] = 0;
347 device_list
[devind
].mask
[i
] = 0;
348 device_list
[devind
].ip_gw
[i
] = 0;
352 device_list
[devind
].index
= index
;
353 device_list
[devind
].mtu
= mtu
;