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