8bbad8b7d6e70b49ef38e208d08595932452f210
[olsrd.git] / lib / bmf / src / NetworkInterfaces.c
1 /*
2  * OLSR Basic Multicast Forwarding (BMF) plugin.
3  * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
4  * Written by Erik Tromp.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without 
8  * modification, are permitted provided that the following conditions 
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright 
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright 
14  *   notice, this list of conditions and the following disclaimer in 
15  *   the documentation and/or other materials provided with the 
16  *   distribution.
17  * * Neither the name of Thales, BMF nor the names of its 
18  *   contributors may be used to endorse or promote products derived 
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
24  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
28  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
29  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /* $Id: NetworkInterfaces.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
34
35 #include "NetworkInterfaces.h"
36
37 /* System includes */
38 #include <syslog.h> /* syslog() */
39 #include <string.h> /* strerror() */
40 #include <errno.h> /* errno */
41 #include <unistd.h> /* close() */
42 #include <sys/ioctl.h> /* ioctl() */
43 #include <fcntl.h> /* fcntl() */
44 #include <assert.h> /* assert() */
45 #include <net/if.h> /* if_indextoname() */
46 #include <netinet/in.h> /* htons() */
47 #include <linux/if_ether.h> /* ETH_P_ALL */
48 #include <linux/if_packet.h> /* packet_mreq, PACKET_MR_PROMISC, PACKET_ADD_MEMBERSHIP */
49 #include <linux/if_tun.h> /* IFF_TAP */
50
51 /* OLSRD includes */
52 #include "olsr.h" /* olsr_printf */
53 #include "defs.h" /* olsr_cnf */
54
55 /* Plugin includes */
56 #include "Packet.h" /* IFHWADDRLEN */
57 #include "Bmf.h" /* PLUGIN_NAME */
58
59 /* List of network interfaces used by BMF plugin */
60 struct TBmfInterface* BmfInterfaces = NULL;
61
62 /* File descriptor of EtherTunTap device */
63 int EtherTunTapFd = -1;
64
65 /* Network interface name of EtherTunTap device. If the name starts with "tun", an
66  * IP tunnel interface will be used. Otherwise, an EtherTap device will be used. */
67 const char* EtherTunTapIfName = "tun0"; /* "tap0"; */
68
69 /* If the network interface name starts with "tun", an IP tunnel interface will be
70  * used, and this variable will be set to TUN. Otherwise, an EtherTap device will
71  * be used, and this variable will be set to TAP. */
72 enum TTunOrTap TunOrTap;
73
74 /* Create raw packet socket for capturing multicast IP traffic. Returns
75  * the socket descriptor, or -1 if an error occurred. */
76 static int CreateCaptureSocket(int ifIndex)
77 {
78   struct packet_mreq mreq;
79   struct ifreq req;
80   struct sockaddr_ll iface_addr;
81
82   /* Open raw packet socket */
83   int skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
84   if (skfd < 0)
85   {
86     olsr_printf(1, "%s: socket(PF_PACKET) error: %s\n", PLUGIN_NAME, strerror(errno));
87     return -1;
88   }
89
90   /* Set interface to promiscuous mode */
91   memset(&mreq, 0, sizeof(struct packet_mreq));
92   mreq.mr_ifindex = ifIndex;
93   mreq.mr_type = PACKET_MR_PROMISC;
94   if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
95   {
96     olsr_printf(1, "%s: setsockopt(PACKET_MR_PROMISC) error: %s\n", PLUGIN_NAME, strerror(errno));
97     close(skfd);
98     return -1;
99   }
100
101   /* Get hardware (MAC) address */
102   memset(&req, 0, sizeof(struct ifreq));
103   if (if_indextoname(ifIndex, req.ifr_name) == NULL ||
104       ioctl(skfd, SIOCGIFHWADDR, &req) < 0)
105   {
106     olsr_printf(1, "%s: error retrieving MAC address: %s\n", PLUGIN_NAME, strerror(errno));
107     close(skfd);
108     return -1;
109   }
110    
111   /* Bind the socket to the specified interface */
112   memset(&iface_addr, 0, sizeof(iface_addr));
113   iface_addr.sll_protocol = htons(ETH_P_ALL);
114   iface_addr.sll_ifindex = ifIndex;
115   iface_addr.sll_family = AF_PACKET;
116   memcpy(iface_addr.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
117   iface_addr.sll_halen = IFHWADDRLEN;
118     
119   if (bind(skfd, (struct sockaddr*)&iface_addr, sizeof(iface_addr)) < 0)
120   {
121     olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
122     close(skfd);
123     return -1;
124   }
125
126   /* Set socket to blocking operation */
127   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
128   {
129     olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno));
130     close(skfd);
131     return -1;
132   }
133
134   return skfd;
135 }
136
137 /* Create UDP (datagram) over IP socket to send encapsulated multicast packets over.
138  * Returns the socket descriptor, or -1 if an error occurred. */
139 static int CreateEncapsulateSocket(int ifIndex)
140 {
141   int on = 1;
142   char ifName[IFNAMSIZ];
143   struct sockaddr_in sin;
144
145   /* Open UDP-IP socket */
146   int skfd = socket(PF_INET, SOCK_DGRAM, 0);
147   if (skfd < 0)
148   {
149     olsr_printf(1, "%s: socket(PF_INET) error: %s\n", PLUGIN_NAME, strerror(errno));
150     return -1;
151   }
152
153   /* Enable sending to broadcast addresses */
154   if (setsockopt(skfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
155   {
156     olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno));
157     close(skfd);
158     return -1;
159   }
160         
161   /* Bind to the specific network interfaces indicated by ifIndex */
162   if (if_indextoname(ifIndex, ifName) == NULL ||
163       setsockopt(skfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, strlen(ifName) + 1) < 0)
164   {
165     olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno));
166     close(skfd);
167     return -1;
168   }
169     
170   memset(&sin, 0, sizeof(sin));
171   sin.sin_family = AF_INET;
172   sin.sin_port = htons(BMF_ENCAP_PORT);
173   sin.sin_addr.s_addr = htonl(INADDR_ANY);
174       
175   if (bind(skfd, (struct sockaddr*)&sin, sizeof(sin)) < 0) 
176   {
177     olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
178     close(skfd);
179     return -1;
180   }
181
182   /* Set socket to blocking operation */
183   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
184   {
185     olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno));
186     close(skfd);
187     return -1;
188   }
189
190   return skfd;
191 }
192
193 /* To save the state of the IP spoof filter for the EtherTunTap device */
194 static char EthTapSpoofState = '1';
195
196 static int DeactivateSpoofFilter(const char* ifName)
197 {
198   FILE* procSpoof;
199   char procFile[FILENAME_MAX];
200
201   assert(ifName != NULL);
202
203   /* Generate the procfile name */
204   sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", ifName);
205
206   procSpoof = fopen(procFile, "r");
207   if (procSpoof == NULL)
208   {
209     fprintf(
210       stderr,
211       "WARNING! Could not open the %s file to check/disable the IP spoof filter!\n"
212       "Are you using the procfile filesystem?\n"
213       "Does your system support IPv4?\n"
214       "I will continue (in 3 sec) - but you should manually ensure that IP spoof\n"
215       "filtering is disabled!\n\n",
216       procFile);
217       
218     sleep(3);
219     return 0;
220   }
221
222   EthTapSpoofState = fgetc(procSpoof);
223   fclose(procSpoof);
224
225   procSpoof = fopen(procFile, "w");
226   if (procSpoof == NULL)
227   {
228     fprintf(stderr, "Could not open %s for writing!\n", procFile);
229     fprintf(
230       stderr,
231       "I will continue (in 3 sec) - but you should manually ensure that IP"
232       " spoof filtering is disabled!\n\n");
233     sleep(3);
234     return 0;
235   }
236
237   syslog(LOG_INFO, "Writing \"0\" to %s", procFile);
238   fputs("0", procSpoof);
239
240   fclose(procSpoof);
241
242   return 1;
243 }
244
245 static void RestoreSpoofFilter(const char* ifName)
246 {
247   FILE* procSpoof;
248   char procFile[FILENAME_MAX];
249
250   assert(ifName != NULL);
251
252   /* Generate the procfile name */
253   sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", ifName);
254
255   procSpoof = fopen(procFile, "w");
256   if (procSpoof == NULL)
257   {
258     fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procFile);
259   }
260   else
261   {
262     syslog(LOG_INFO, "Resetting %s to %c\n", procFile, EthTapSpoofState);
263
264     fputc(EthTapSpoofState, procSpoof);
265     fclose(procSpoof);
266   }
267 }
268
269 /* Creates and brings up an EtherTunTap device e.g. "tun0" or "tap0"
270  * (as specified in const char* EtherTunTapIfName) */
271 static int CreateLocalEtherTunTap(void)
272 {
273   struct ifreq ifreq;
274   int etfd = open("/dev/net/tun", O_RDWR);
275   int skfd;
276   int ioctlres = 0;
277
278   if (etfd < 0)
279   {
280     olsr_printf(1, "%s: open() error: %s\n", PLUGIN_NAME, strerror(errno));
281     return -1;
282   }
283
284   memset(&ifreq, 0, sizeof(ifreq));
285
286   /* Specify either the IFF_TAP flag for Ethernet frames, or the IFF_TUN flag for IP.
287    * Specify IFF_NO_PI for not receiving extra meta packet information. */
288   if (strncmp(EtherTunTapIfName, "tun", 3) == 0)
289   {
290     ifreq.ifr_flags = IFF_TUN;
291     TunOrTap = TT_TUN;
292   }
293   else
294   {
295     ifreq.ifr_flags = IFF_TAP;
296     TunOrTap = TT_TAP;
297   }
298   ifreq.ifr_flags |= IFF_NO_PI;
299
300   strcpy(ifreq.ifr_name, EtherTunTapIfName);
301   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0)
302   {
303     olsr_printf(1, "%s: ioctl() error: %s\n", PLUGIN_NAME, strerror(errno));
304     close(etfd);
305     return -1;
306   }
307
308   memset(&ifreq, 0, sizeof(ifreq));
309   strcpy(ifreq.ifr_name, EtherTunTapIfName);
310   ifreq.ifr_addr.sa_family = AF_INET;
311   skfd = socket(PF_INET, SOCK_DGRAM, 0);
312   if (skfd >= 0)
313   {
314     if (ioctl(skfd, SIOCGIFADDR, &ifreq) < 0)
315     {
316       /* EtherTunTap interface does not yet have an IP address.
317        * Give it a dummy IP address "1.2.3.4". */
318       struct sockaddr_in *inaddr = (struct sockaddr_in *)&ifreq.ifr_addr;
319       inet_aton("1.2.3.4", &inaddr->sin_addr);
320       ioctlres = ioctl(skfd, SIOCSIFADDR, &ifreq);
321
322       if (ioctlres >= 0)
323       {
324         /* Bring EtherTunTap interface up (if not already) */
325         ioctlres = ioctl(skfd, SIOCGIFFLAGS, &ifreq);
326         if (ioctlres >= 0)
327         {
328           ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING);
329           ioctlres = ioctl(skfd, SIOCSIFFLAGS, &ifreq);
330         }
331       } /* if (ioctlres >= 0) */
332     } /* if (ioctl...) */
333   } /* if (skfd >= 0) */
334   if (skfd < 0 || ioctlres < 0)
335   {
336     olsr_printf(
337       1,
338       "%s: Error bringing up EtherTunTap interface: %s\n",
339       PLUGIN_NAME,
340       strerror(errno));
341
342     close(etfd);
343     if (skfd >= 0)
344     {
345       close(skfd);
346     }
347     return -1;
348   } /* if (skfd < 0 || ioctlres < 0) */
349
350   /* Set the multicast flag on the interface. TODO: Maybe also set
351    * IFF_ALLMULTI. */
352   memset(&ifreq, 0, sizeof(ifreq));
353   strcpy(ifreq.ifr_name, EtherTunTapIfName);
354   ioctlres = ioctl(skfd, SIOCGIFFLAGS, &ifreq);
355   if (ioctlres >= 0)
356   {
357     ifreq.ifr_flags |= IFF_MULTICAST;
358     ioctlres = ioctl(skfd, SIOCSIFFLAGS, &ifreq);
359   }
360   if (ioctlres < 0)
361   {
362     olsr_printf(
363       1,
364       "%s: Error setting the multicast flag on EtherTunTap interface: %s\n",
365       PLUGIN_NAME,
366       strerror(errno));
367   }
368   close(skfd);
369   
370   /* Deactivate IP spoof filter for EtherTunTap device */
371   DeactivateSpoofFilter(ifreq.ifr_name);
372
373   return etfd;
374 }
375
376 static int IsNullMacAddress(char* mac)
377 {
378   int i;
379
380   assert(mac != NULL);
381
382   for (i = 0; i < IFHWADDRLEN; i++)
383   {
384     if (mac[i] != 0) return 0;
385   }
386   return 1;
387 }
388
389 int CreateBmfNetworkInterfaces(void)
390 {
391   int skfd;
392   struct ifconf ifc;
393   int numreqs = 30;
394   struct ifreq* ifr;
395   int n;
396
397   EtherTunTapFd = CreateLocalEtherTunTap();
398   if (EtherTunTapFd < 0)
399   {
400     olsr_printf(1, "%s: error creating local EtherTunTap\n", PLUGIN_NAME);
401     return -1;    
402   }
403
404   skfd = socket(PF_INET, SOCK_DGRAM, 0);
405   if (skfd < 0)
406   {
407     olsr_printf(
408       1,
409       "%s: No inet socket available: %s\n",
410       PLUGIN_NAME,
411       strerror(errno));
412     return -1;
413   }
414
415   /* Retrieve the network interface configuration list */
416   ifc.ifc_buf = NULL;
417   for (;;)
418   {
419     ifc.ifc_len = sizeof(struct ifreq) * numreqs;
420     ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
421
422     if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
423     {
424       olsr_printf(1, "%s: SIOCGIFCONF error: %s\n", PLUGIN_NAME, strerror(errno));
425
426       close(skfd);
427       free(ifc.ifc_buf);
428       return -1;
429     }
430     if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs)
431     {
432       /* Assume it overflowed; double the space and try again */
433       numreqs *= 2;
434       assert(numreqs < 1024);
435       continue; /* for (;;) */
436     }
437     break; /* for (;;) */
438   } /* for (;;) */
439
440   /* For each item in the interface configuration list... */
441   ifr = ifc.ifc_req;
442   for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++)
443   {
444     struct interface* olsrIntf;
445     struct ifreq ifrAddr;
446     int capturingSkfd;
447     int encapsulatingSkfd = -1;
448     struct TBmfInterface* newBmfInterface;
449
450     /* ...find the OLSR interface structure, if any */
451     union olsr_ip_addr ipAddr;
452     COPY_IP(&ipAddr, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr.s_addr);
453     olsrIntf = if_ifwithaddr(&ipAddr);
454
455     if (olsrIntf == NULL && ! IsNonOlsrBmfIf(ifr->ifr_name))
456     {
457       /* Interface is neither OLSR interface, nor specified as non-OLSR BMF
458        * interface in the BMF plugin parameter list */
459       continue; /* for (n = ...) */
460     }
461
462     /* Retrieve the MAC address */
463     memset(&ifrAddr, 0, sizeof(struct ifreq));
464     strcpy(ifrAddr.ifr_name, ifr->ifr_name); 
465     if (ioctl(skfd, SIOCGIFHWADDR, &ifrAddr) < 0)
466     {
467       olsr_printf(
468         1,
469         "%s: SIOCGIFHWADDR error for device \"%s\": %s\n",
470         PLUGIN_NAME,
471         ifrAddr.ifr_name,
472         strerror(errno));
473       continue; /* for (n = ...) */
474     }
475
476     if (IsNullMacAddress(ifrAddr.ifr_hwaddr.sa_data))
477     {
478       continue; /* for (n = ...) */
479     }
480
481     /* Create socket for capturing and sending multicast packets */
482     capturingSkfd = CreateCaptureSocket(if_nametoindex(ifr->ifr_name));
483     if (capturingSkfd < 0)
484     {
485       continue; /* for (n = ...) */
486     }
487
488     if (olsrIntf != NULL)
489     {
490       /* Create socket for encapsulating and forwarding multicast packets */
491       encapsulatingSkfd = CreateEncapsulateSocket(olsrIntf->if_index);
492       if (encapsulatingSkfd < 0)
493       {
494         close(capturingSkfd);
495         continue; /* for (n = ...) */
496       }
497     }
498
499     newBmfInterface = malloc(sizeof(struct TBmfInterface));
500     if (newBmfInterface == NULL)
501     {
502       close(capturingSkfd);
503       close(encapsulatingSkfd);
504       continue; /* for (n = ...) */
505     }
506
507     newBmfInterface->capturingSkfd = capturingSkfd;
508     newBmfInterface->encapsulatingSkfd = encapsulatingSkfd;
509     memcpy(newBmfInterface->macAddr, ifrAddr.ifr_hwaddr.sa_data, IFHWADDRLEN);
510     memcpy(newBmfInterface->ifName, ifr->ifr_name, IFNAMSIZ);
511     newBmfInterface->olsrIntf = olsrIntf;
512     newBmfInterface->next = BmfInterfaces;
513     BmfInterfaces = newBmfInterface;
514   } /* for (n = ...) */
515   
516   if (BmfInterfaces == NULL)
517   {
518     olsr_printf(1, "%s: could not initialize any network interface\n", PLUGIN_NAME);
519     return -1;
520   }
521
522   close(skfd);
523   free(ifc.ifc_buf);
524   return 0;
525 }
526
527 /* Closes every socket on each network interface used by BMF:
528  * -- the local EtherTunTap interface (e.g. "tun0" or "tap0")
529  * -- for each OLSR-enabled interface:
530  *    - the socket used for capturing multicast packets
531  *    - the socket used for encapsulating packets
532  * Also restores the network state to the situation before OLSR was
533  * started */
534 void CloseBmfNetworkInterfaces()
535 {
536   int nClosed = 0;
537   
538   /* Close all opened sockets */
539   struct TBmfInterface* nextBmfIf = BmfInterfaces;
540   while (nextBmfIf != NULL)
541   {
542     struct TBmfInterface* bmfIf = nextBmfIf;
543     nextBmfIf = bmfIf->next;
544
545     close(bmfIf->capturingSkfd);
546     nClosed++;
547     if (bmfIf->encapsulatingSkfd >= 0) 
548     {
549       close(bmfIf->encapsulatingSkfd);
550       nClosed++;
551     }
552
553     free(bmfIf);
554   }
555   
556   /* Restore IP spoof filter for EtherTunTap device */
557   RestoreSpoofFilter(EtherTunTapIfName);
558
559   close(EtherTunTapFd);
560   nClosed++;
561
562   olsr_printf(1, "%s: closed %d sockets\n", PLUGIN_NAME, nClosed);
563 }
564
565 #define MAX_NON_OLSR_IFS 10
566 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
567 static int nNonOlsrIfs = 0;
568
569 int AddNonOlsrBmfIf(const char* ifName)
570 {
571   assert(ifName != NULL);
572
573   if (nNonOlsrIfs >= MAX_NON_OLSR_IFS)
574   {
575     olsr_printf(
576       1,
577       "%s: too many non-OLSR interfaces specified, maximum %d\n",
578       PLUGIN_NAME,
579       MAX_NON_OLSR_IFS);
580     return 0;
581   }
582
583   strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ);
584   nNonOlsrIfs++;
585   return 1;
586 }
587
588 int IsNonOlsrBmfIf(const char* ifName)
589 {
590   int i;
591
592   assert(ifName != NULL);
593
594   for (i = 0; i < nNonOlsrIfs; i++)
595   {
596     if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0) return 1;
597   }
598   return 0;
599 }