1 /******************************************************************************
2     (c) 2002-2008 Christine Caulfield                 christine.caulfield@googlemail.com
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 ******************************************************************************/
14 #include <sys/types.h>
15 #include <sys/uio.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <sys/ioctl.h>
19 #include <sys/wait.h>
20 #include <sys/stat.h>
21 #include <sys/time.h>
22 #include <sys/utsname.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <dirent.h>
30 #include <syslog.h>
31 #include <ctype.h>
32 #include <regex.h>
33 #include <stdlib.h>
34 // #include <utmp.h>
35 #include <grp.h>
36 #include <signal.h>
37 #include <assert.h>
38 #include <netinet/in.h>
39 #include <features.h>    /* for the glibc version number */
40 #if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || __GLIBC__ >= 3
41 #include <netpacket/packet.h>
42 #include <net/ethernet.h>     /* the L2 protocols */
43 #include <net/if_arp.h>
44 #include <linux/if.h>
45 #else
46 #include <asm/types.h>
47 #include <linux/if.h>
48 #include <linux/if_arp.h>
49 #include <linux/if_packet.h>
50 #include <linux/if_ether.h>   /* The L2 protocols */
51 #endif
52 
53 #include <list>
54 #include <queue>
55 #include <map>
56 #include <string>
57 #include <algorithm>
58 #include <iterator>
59 #include <sstream>
60 #include <iomanip>
61 
62 #include "utils.h"
63 #include "interfaces.h"
64 #include "interfaces-linux.h"
65 
66 int LATinterfaces::ProtoLAT = ETH_P_LAT;
67 int LATinterfaces::ProtoMOP = ETH_P_DNA_RC;
68 
Start(int proto)69 int LinuxInterfaces::Start(int proto)
70 {
71     protocol = proto;
72 
73     // Open raw socket on specified protocol
74     fd = socket(PF_PACKET, SOCK_DGRAM, htons(protocol));
75     if (fd < 0)
76     {
77 	syslog(LOG_ERR, "Can't create protocol socket: %m\n");
78 	return -1;
79     }
80     return 0;
81 }
82 
83 // Return a list of valid interface numbers and the count
get_all_interfaces(int * ifs,int & num)84 void LinuxInterfaces::get_all_interfaces(int *ifs, int &num)
85 {
86     struct ifreq ifr;
87     int iindex = 1;
88     int sock = socket(PF_PACKET, SOCK_RAW, 0);
89     num = 0;
90 
91     for (iindex = 1; iindex < 256; iindex++)
92     {
93 	ifr.ifr_ifindex = iindex;
94         if (ioctl(sock, SIOCGIFNAME, &ifr) == 0)
95 	{
96 	    // Only use ethernet interfaces
97 	    ioctl(sock, SIOCGIFHWADDR, &ifr);
98 	    if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER)
99 	    {
100 		debuglog(("interface %d: %d\n", num, iindex));
101 		ifs[num++] = iindex;
102 	    }
103 	}
104     }
105 
106     close(sock);
107 
108 }
109 
110 // Print the name of an interface
ifname(int ifn)111 std::string LinuxInterfaces::ifname(int ifn)
112 {
113     struct ifreq ifr;
114     int sock = socket(PF_PACKET, SOCK_RAW, 0);
115 
116     ifr.ifr_ifindex = ifn;
117 
118     if (ioctl(sock, SIOCGIFNAME, &ifr) == 0)
119     {
120 	close(sock);
121 	return std::string((char *)ifr.ifr_name);
122     }
123 
124     // Didn't find it
125     close(sock);
126     return std::string("");
127 }
128 
129 // Bind a socket to an interface
bind_socket(int interface)130 int LinuxInterfaces::bind_socket(int interface)
131 {
132     struct sockaddr_ll sock_info;
133 
134     sock_info.sll_family   = AF_PACKET;
135     sock_info.sll_protocol = htons(protocol);
136 
137     sock_info.sll_ifindex  = interface;
138     if (bind(fd, (struct sockaddr *)&sock_info, sizeof(sock_info)))
139     {
140         perror("can't bind socket to i/f %m\n");
141         return -1;
142     }
143     return 0;
144 }
145 
146 // Find an interface number by name, or
147 // use the first one if name is NULL.
find_interface(char * name)148 int LinuxInterfaces::find_interface(char *name)
149 {
150     struct ifreq ifr;
151     int iindex = 1;
152     int sock = socket(PF_PACKET, SOCK_RAW, 0);
153 
154     // Default "1st" interface
155     if (!name)
156 	    name = (char *)"eth0";
157 
158     ifr.ifr_ifindex = iindex;
159 
160     for (iindex = 1; iindex < 256; iindex++)
161     {
162 	ifr.ifr_ifindex = iindex;
163 	if (ioctl(sock, SIOCGIFNAME, &ifr) == 0)
164 	{
165 	    if (strcmp(ifr.ifr_name, name) == 0)
166 	    {
167 		// Also check it's ethernet while we are here
168 		ioctl(sock, SIOCGIFHWADDR, &ifr);
169 		if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
170 		{
171 		    syslog(LOG_ERR, "Device %s is not ethernet\n", name);
172 		    return -1;
173 		}
174 		close(sock);
175 		return iindex;
176 	    }
177 	}
178     }
179     // Didn't find it
180     close(sock);
181     return -1;
182 }
183 
184 // true if this class defines one FD for each active
185 // interface, false if one fd is used for all interfaces.
one_fd_per_interface()186 bool LinuxInterfaces::one_fd_per_interface()
187 {
188     return false;
189 }
190 
191 // Return the FD for this interface (will only be called once for
192 // select if above returns false)
get_fd(int ifn)193 int LinuxInterfaces::get_fd(int ifn)
194 {
195     return fd;
196 }
197 
198 // Send a packet to a given macaddr
send_packet(int ifn,unsigned char macaddr[],unsigned char * data,int len)199 int LinuxInterfaces::send_packet(int ifn, unsigned char macaddr[], unsigned char *data, int len)
200 {
201     struct sockaddr_ll sock_info;
202 
203     /* Build the sockaddr_ll structure */
204     sock_info.sll_family   = AF_PACKET;
205     sock_info.sll_protocol = htons(protocol);
206     sock_info.sll_ifindex  = ifn;
207     sock_info.sll_hatype   = 0;//ARPHRD_ETHER;
208     sock_info.sll_pkttype  = PACKET_MULTICAST;
209     sock_info.sll_halen    = 6;
210     memcpy(sock_info.sll_addr, macaddr, 6);
211 
212     return sendto(fd, data, len, 0,
213 		  (struct sockaddr *)&sock_info, sizeof(sock_info));
214 }
215 
216 // Receive a packet from a given interface
recv_packet(int sockfd,int & ifn,unsigned char macaddr[],unsigned char * data,int maxlen,bool & more)217 int LinuxInterfaces::recv_packet(int sockfd, int &ifn, unsigned char macaddr[], unsigned char *data, int maxlen, bool &more)
218 {
219     struct msghdr msg;
220     struct iovec iov;
221     struct sockaddr_ll sock_info;
222     int    len;
223 
224 /* Linux only returns 1 packet at a time */
225     more = false;
226 
227     memset(&msg, 0, sizeof(msg));
228     msg.msg_name = &sock_info;
229     msg.msg_namelen = sizeof(sock_info);
230     msg.msg_iovlen = 1;
231     msg.msg_iov = &iov;
232     iov.iov_len = maxlen;
233     iov.iov_base = data;
234 
235     len = recvmsg(sockfd, &msg, 0);
236 
237     ifn = sock_info.sll_ifindex;
238     memcpy(macaddr, sock_info.sll_addr, 6);
239 
240     // Ignore packets captured in promiscuous mode.
241     if (sock_info.sll_pkttype == PACKET_OTHERHOST)
242     {
243 	debuglog(("Got a rogue packet .. interface probably in promiscuous mode\n"));
244 	return 0;
245     }
246     return len;
247 }
248 
249 // Open a connection on an interface
250 // Only necessary for LAT sockets.
set_lat_multicast(int ifn)251 int LinuxInterfaces::set_lat_multicast(int ifn)
252 {
253     // Add Multicast membership for LAT on socket
254     struct packet_mreq pack_info;
255 
256     /* Fill in socket options */
257     pack_info.mr_type        = PACKET_MR_MULTICAST;
258     pack_info.mr_alen        = 6;
259     pack_info.mr_ifindex     = ifn;
260 
261     /* This is the LAT multicast address */
262     pack_info.mr_address[0]  = 0x09;
263     pack_info.mr_address[1]  = 0x00;
264     pack_info.mr_address[2]  = 0x2b;
265     pack_info.mr_address[3]  = 0x00;
266     pack_info.mr_address[4]  = 0x00;
267     pack_info.mr_address[5]  = 0x0f;
268 
269 
270     if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
271 		   &pack_info, sizeof(pack_info)))
272     {
273 	syslog(LOG_ERR, "can't add lat socket multicast : %m\n");
274 	return -1;
275     }
276 
277     /* This is the LAT solicit address */
278     pack_info.mr_address[0]  = 0x09;
279     pack_info.mr_address[1]  = 0x00;
280     pack_info.mr_address[2]  = 0x2b;
281     pack_info.mr_address[3]  = 0x02;
282     pack_info.mr_address[4]  = 0x01;
283     pack_info.mr_address[5]  = 0x04;
284 
285     if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
286 		   &pack_info, sizeof(pack_info)))
287     {
288 	syslog(LOG_ERR, "can't add lat socket multicast : %m\n");
289 	return -1;
290     }
291 
292     return 0;
293 }
294 
295 // Close an interface.
remove_lat_multicast(int ifn)296 int LinuxInterfaces::remove_lat_multicast(int ifn)
297 {
298     // Add Multicast membership for LAT on socket
299     struct packet_mreq pack_info;
300 
301     /* Fill in socket options */
302     pack_info.mr_type        = PACKET_MR_MULTICAST;
303     pack_info.mr_alen        = 6;
304     pack_info.mr_ifindex     = ifn;
305 
306     /* This is the LAT multicast address */
307     pack_info.mr_address[0]  = 0x09;
308     pack_info.mr_address[1]  = 0x00;
309     pack_info.mr_address[2]  = 0x2b;
310     pack_info.mr_address[3]  = 0x00;
311     pack_info.mr_address[4]  = 0x00;
312     pack_info.mr_address[5]  = 0x0f;
313 
314     if (setsockopt(fd, SOL_PACKET, PACKET_DROP_MEMBERSHIP,
315 		   &pack_info, sizeof(pack_info)))
316     {
317 	syslog(LOG_ERR, "can't remove socket multicast : %m\n");
318 	return -1;
319     }
320 
321     /* This is the LAT solicit address */
322     pack_info.mr_address[0]  = 0x09;
323     pack_info.mr_address[1]  = 0x00;
324     pack_info.mr_address[2]  = 0x2b;
325     pack_info.mr_address[3]  = 0x02;
326     pack_info.mr_address[4]  = 0x01;
327     pack_info.mr_address[5]  = 0x04;
328 
329     if (setsockopt(fd, SOL_PACKET, PACKET_DROP_MEMBERSHIP,
330 		   &pack_info, sizeof(pack_info)))
331     {
332 	syslog(LOG_ERR, "can't remove socket multicast : %m\n");
333 	return -1;
334     }
335 
336     return 0;
337 }
338 
339 // Here's where we know how to instantiate the class.
Create()340 LATinterfaces *LATinterfaces::Create()
341 {
342     return new LinuxInterfaces();
343 }
344