6fb7854b6d09a1b7d26c025feab2ec2e35264321
[olsrd.git] / src / unix / ifnet.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
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 olsr.org, olsrd 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
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42
43 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
44 #define ifr_netmask ifr_addr
45 #endif
46
47 #include "ipcalc.h"
48 #include "interfaces.h"
49 #include "defs.h"
50 #include "olsr.h"
51 #include "os_net.h"
52 #include "net_olsr.h"
53 #include "parser.h"
54 #include "scheduler.h"
55 #include "olsr_time.h"
56 #include "lq_packet.h"
57 #include "link_set.h"
58 #include "mid_set.h"
59 #include "hna_set.h"
60 #include "common/string.h"
61
62 #include <assert.h>
63 #include <signal.h>
64 #include <sys/types.h>
65 #include <net/if.h>
66 #include <net/if_arp.h>
67 #include <netinet/in_systm.h>
68 #include <netinet/ip.h>
69 #include <arpa/inet.h>
70 #include <netdb.h>
71 #include <unistd.h>
72 #include <errno.h>
73
74 #define BUFSPACE  (127*1024)    /* max. input buffer size to request */
75
76 #if 0
77 int
78 set_flag(char *ifname, short flag __attribute__ ((unused)))
79 {
80   struct ifreq ifr;
81
82   /* Get flags */
83   strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
84   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
85     fprintf(stderr, "ioctl (get interface flags)");
86     return -1;
87   }
88
89   strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
90   //printf("Setting flags for if \"%s\"\n", ifr.ifr_name);
91   if ((ifr.ifr_flags & (IFF_UP | IFF_RUNNING)) == 0) {
92     /* Add UP */
93     ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
94     /* Set flags + UP */
95     if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
96       fprintf(stderr, "ERROR(%s): %s\n", ifr.ifr_name, strerror(errno));
97       return -1;
98     }
99   }
100   return 1;
101 }
102 #endif
103
104 /**
105  * Checks if an initialized interface is changed
106  * that is if it has been set down or the address
107  * has been changed.
108  *
109  *@param iface the olsr_if_config struct describing the interface
110  */
111 int
112 chk_if_changed(struct olsr_if_config *iface)
113 {
114 #if !defined REMOVE_LOG_DEBUG || !defined REMOVE_LOG_INFO
115   struct ipaddr_str buf;
116 #endif
117   struct interface *ifp;
118   struct ifreq ifr;
119   int if_changes = 0;
120   int int_flags;
121
122   OLSR_DEBUG(LOG_INTERFACE, "Checking if %s is set down or changed\n", iface->name);
123
124   ifp = iface->interf;
125   if (!ifp) {
126     return 0;
127   }
128
129   memset(&ifr, 0, sizeof(ifr));
130   strscpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
131   /* Get flags (and check if interface exists) */
132   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
133     OLSR_WARN(LOG_INTERFACE, "No such interface: %s\n", iface->name);
134     remove_interface(&iface->interf);
135     return 0;
136   }
137   int_flags = ifr.ifr_flags;
138
139   /*
140    * First check if the interface is set DOWN
141    */
142   if ((int_flags & IFF_UP) == 0) {
143     OLSR_DEBUG(LOG_INTERFACE, "\tInterface %s not up - removing it...\n", iface->name);
144     remove_interface(&iface->interf);
145     return 0;
146   }
147
148   /*
149    * We do all the interface type checks over.
150    * This is because the interface might be a PCMCIA card. Therefore
151    * it might not be the same physical interface as we configured earlier.
152    */
153
154   /* Check broadcast */
155   if (olsr_cnf->ip_version == AF_INET && !iface->cnf->ipv4_broadcast.v4.s_addr &&       /* Skip if fixed bcast */
156       ((int_flags & IFF_BROADCAST)) == 0) {
157     OLSR_DEBUG(LOG_INTERFACE, "\tNo broadcast - removing\n");
158     remove_interface(&iface->interf);
159     return 0;
160   }
161
162   if (int_flags & IFF_LOOPBACK) {
163     OLSR_DEBUG(LOG_INTERFACE, "\tThis is a loopback interface - removing it...\n");
164     remove_interface(&iface->interf);
165     return 0;
166   }
167
168   /* Get MTU */
169   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMTU, &ifr) < 0) {
170     ifp->int_mtu = 0;
171   } else {
172     ifr.ifr_mtu -= olsr_cnf->ip_version == AF_INET6 ? UDP_IPV6_HDRSIZE : UDP_IPV4_HDRSIZE;
173     if (ifp->int_mtu != ifr.ifr_mtu) {
174       ifp->int_mtu = ifr.ifr_mtu;
175       /* Create new outputbuffer */
176       net_remove_buffer(ifp);   /* Remove old */
177       net_add_buffer(ifp);
178     }
179   }
180
181   /* Get interface index */
182   ifp->if_index = if_nametoindex(ifr.ifr_name);
183
184   /*
185    * Now check if the IP has changed
186    */
187
188   /* IP version 6 */
189   if (olsr_cnf->ip_version == AF_INET6) {
190     struct sockaddr_in6 tmp_saddr6;
191
192     /* Get interface address */
193     if (get_ipv6_address(ifr.ifr_name, &tmp_saddr6, iface->cnf->ipv6_addrtype) <= 0) {
194       if (iface->cnf->ipv6_addrtype == OLSR_IP6T_SITELOCAL)
195         OLSR_WARN(LOG_INTERFACE, "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
196       else if (iface->cnf->ipv6_addrtype == OLSR_IP6T_UNIQUELOCAL)
197         OLSR_WARN(LOG_INTERFACE, "\tCould not find unique-local IPv6 address for %s\n", ifr.ifr_name);
198       else if (iface->cnf->ipv6_addrtype == OLSR_IP6T_GLOBAL)
199         OLSR_WARN(LOG_INTERFACE, "\tCould not find global IPv6 address for %s\n", ifr.ifr_name);
200       else
201         OLSR_WARN(LOG_INTERFACE, "\tCould not find an IPv6 address for %s\n", ifr.ifr_name);
202       remove_interface(&iface->interf);
203       return 0;
204     }
205
206     OLSR_DEBUG(LOG_INTERFACE, "\tAddress: %s\n", ip6_to_string(&buf, &tmp_saddr6.sin6_addr));
207
208     if (ip6cmp(&tmp_saddr6.sin6_addr, &ifp->int_src.v6.sin6_addr) != 0) {
209       OLSR_DEBUG(LOG_INTERFACE, "New IP address for %s:\n"
210                  "\tOld: %s\n\tNew: %s\n",
211                  ifr.ifr_name, ip6_to_string(&buf, &ifp->int_src.v6.sin6_addr), ip6_to_string(&buf, &tmp_saddr6.sin6_addr));
212
213       /* Update address */
214       ifp->int_src.v6.sin6_addr = tmp_saddr6.sin6_addr;
215       ifp->ip_addr.v6 = tmp_saddr6.sin6_addr;
216
217       if_changes = 1;
218     }
219   } else {
220     /* IP version 4 */
221     const struct sockaddr_in *tmp_saddr4 = (struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_addr));
222
223     /* Check interface address (IPv4) */
224     if (ioctl(olsr_cnf->ioctl_s, SIOCGIFADDR, &ifr) < 0) {
225       OLSR_DEBUG(LOG_INTERFACE, "\tCould not get address of interface - removing it\n");
226       remove_interface(&iface->interf);
227       return 0;
228     }
229
230     OLSR_DEBUG(LOG_INTERFACE, "\tAddress:%s\n", ip4_to_string(&buf, ifp->int_src.v4.sin_addr));
231
232     if (ip4cmp(&ifp->int_src.v4.sin_addr, &tmp_saddr4->sin_addr) != 0) {
233       /* New address */
234       OLSR_DEBUG(LOG_INTERFACE, "IPv4 address changed for %s\n"
235                  "\tOld:%s\n\tNew:%s\n",
236                  ifr.ifr_name, ip4_to_string(&buf, ifp->int_src.v4.sin_addr), ip4_to_string(&buf, tmp_saddr4->sin_addr));
237
238       ifp->int_src.v4 = *(struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_addr));
239       ifp->ip_addr.v4 = tmp_saddr4->sin_addr;
240
241       if_changes = 1;
242     }
243
244     /* Check netmask */
245     if (ioctl(olsr_cnf->ioctl_s, SIOCGIFNETMASK, &ifr) < 0) {
246       OLSR_WARN(LOG_INTERFACE, "%s: ioctl (get broadaddr) failed", ifr.ifr_name);
247       remove_interface(&iface->interf);
248       return 0;
249     }
250
251     OLSR_DEBUG(LOG_INTERFACE, "\tNetmask:%s\n", ip4_to_string(&buf, ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_netmask)))->sin_addr));
252
253     if (!iface->cnf->ipv4_broadcast.v4.s_addr) {
254       /* Check broadcast address */
255       if (ioctl(olsr_cnf->ioctl_s, SIOCGIFBRDADDR, &ifr) < 0) {
256         OLSR_WARN(LOG_INTERFACE, "%s: ioctl (get broadaddr) failed", ifr.ifr_name);
257         return 0;
258       }
259
260       OLSR_DEBUG(LOG_INTERFACE, "\tBroadcast address:%s\n",
261                  ip4_to_string(&buf, ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr)))->sin_addr));
262
263       if (ifp->int_multicast.v4.sin_addr.s_addr != ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr)))->sin_addr.s_addr) {
264         /* New address */
265         OLSR_DEBUG(LOG_INTERFACE, "IPv4 broadcast changed for %s\n"
266                    "\tOld:%s\n\tNew:%s\n",
267                    ifr.ifr_name,
268                    ip4_to_string(&buf, ifp->int_multicast.v4.sin_addr),
269                    ip4_to_string(&buf, ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr)))->sin_addr));
270
271         ifp->int_multicast.v4 = *(struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr));
272         if_changes = 1;
273       }
274     }
275   }
276   if (if_changes) {
277     run_ifchg_cbs(ifp, IFCHG_IF_UPDATE);
278   }
279   return if_changes;
280 }
281
282 static char basenamestr[32];
283 static const char *if_basename(const char *name);
284 static const char *
285 if_basename(const char *name)
286 {
287   const char *p = strchr(name, ':');
288   if (NULL == p || p - name >= (int)(ARRAYSIZE(basenamestr) - 1)) {
289     return name;
290   }
291   memcpy(basenamestr, name, p - name);
292   basenamestr[p - name] = 0;
293   return basenamestr;
294 }
295
296 /**
297  * Initializes a interface described by iface,
298  * if it is set up and is of the correct type.
299  *
300  *@param iface the olsr_if_config struct describing the interface
301  *@param so the socket to use for ioctls
302  *
303  */
304 int
305 os_init_interface(struct interface *ifp, struct olsr_if_config *iface)
306 {
307   struct ifreq ifr;
308   const char *ifr_basename;
309   int int_flags;
310 #if !defined REMOVE_LOG_DEBUG || !defined REMOVE_LOG_INFO
311   struct ipaddr_str buf;
312 #endif
313
314   /*
315    * Sanity check.
316    */
317   assert (iface->interf == NULL);
318   assert (ifp);
319
320    /*
321    * Setup query block.
322    */
323   memset(&ifr, 0, sizeof(ifr));
324   strscpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
325
326   OLSR_DEBUG(LOG_INTERFACE, "Checking %s:\n", ifr.ifr_name);
327
328   /* Get flags (and check if interface exists) */
329   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
330     OLSR_DEBUG(LOG_INTERFACE, "\tNo such interface!\n");
331     return -1;
332   }
333
334   int_flags = ifr.ifr_flags;
335   if ((int_flags & IFF_UP) == 0) {
336     OLSR_DEBUG(LOG_INTERFACE, "\tInterface not up - skipping it...\n");
337     return -1;
338   }
339
340   /* Check broadcast */
341   if (olsr_cnf->ip_version == AF_INET && !iface->cnf->ipv4_broadcast.v4.s_addr &&       /* Skip if fixed bcast */
342       (int_flags & IFF_BROADCAST) == 0) {
343     OLSR_DEBUG(LOG_INTERFACE, "\tNo broadcast - skipping\n");
344     return -1;
345   }
346
347   if (int_flags & IFF_LOOPBACK) {
348     OLSR_DEBUG(LOG_INTERFACE, "\tThis is a loopback interface - skipping it...\n");
349     return -1;
350   }
351
352   ifr_basename = if_basename(ifr.ifr_name);
353
354   /* IP version 6 */
355   if (olsr_cnf->ip_version == AF_INET6) {
356     /* Get interface address */
357     int result;
358
359     memset(&ifp->int_src, 0, sizeof(ifp->int_multicast));
360     ifp->int_src.v6.sin6_family = AF_INET6;
361     ifp->int_src.v6.sin6_flowinfo = htonl(0);
362     ifp->int_src.v6.sin6_scope_id = if_nametoindex(ifr.ifr_name);
363     ifp->int_src.v6.sin6_port = htons(olsr_cnf->olsr_port);
364
365     if (iface->cnf->ipv6_addrtype == OLSR_IP6T_AUTO) {
366       if ((result = get_ipv6_address(ifr.ifr_name, &ifp->int_src.v6, OLSR_IP6T_SITELOCAL)) > 0) {
367         iface->cnf->ipv6_addrtype = OLSR_IP6T_SITELOCAL;
368       } else {
369         if ((result = get_ipv6_address(ifr.ifr_name, &ifp->int_src.v6, OLSR_IP6T_UNIQUELOCAL)) > 0) {
370           iface->cnf->ipv6_addrtype = OLSR_IP6T_UNIQUELOCAL;
371         } else {
372           if ((result = get_ipv6_address(ifr.ifr_name, &ifp->int_src.v6, OLSR_IP6T_GLOBAL)) > 0) {
373             iface->cnf->ipv6_addrtype = OLSR_IP6T_GLOBAL;
374           }
375         }
376       }
377     } else {
378       result = get_ipv6_address(ifr.ifr_name, &ifp->int_src.v6, iface->cnf->ipv6_addrtype);
379     }
380
381     if (result <= 0) {
382       if (iface->cnf->ipv6_addrtype == OLSR_IP6T_SITELOCAL)
383         OLSR_DEBUG(LOG_INTERFACE, "\tCould not find site-local IPv6 address for %s\n", ifr.ifr_name);
384       else if (iface->cnf->ipv6_addrtype == OLSR_IP6T_UNIQUELOCAL)
385         OLSR_DEBUG(LOG_INTERFACE, "\tCould not find unique-local IPv6 address for %s\n", ifr.ifr_name);
386       else if (iface->cnf->ipv6_addrtype == OLSR_IP6T_GLOBAL)
387         OLSR_DEBUG(LOG_INTERFACE, "\tCould not find global IPv6 address for %s\n", ifr.ifr_name);
388       else
389         OLSR_DEBUG(LOG_INTERFACE, "\tCould not find an IPv6 address for %s\n", ifr.ifr_name);
390       return -1;
391     }
392
393     OLSR_DEBUG(LOG_INTERFACE, "\tAddress: %s\n", ip6_to_string(&buf, &ifp->int_src.v6.sin6_addr));
394
395     /* Multicast */
396     memset(&ifp->int_multicast, 0, sizeof(ifp->int_multicast));
397     ifp->int_multicast.v6.sin6_family = AF_INET6;
398     ifp->int_multicast.v6.sin6_flowinfo = htonl(0);
399     ifp->int_multicast.v6.sin6_scope_id = if_nametoindex(ifr.ifr_name);
400     ifp->int_multicast.v6.sin6_port = htons(olsr_cnf->olsr_port);
401     ifp->int_multicast.v6.sin6_addr = iface->cnf->ipv6_addrtype == OLSR_IP6T_SITELOCAL
402       ? iface->cnf->ipv6_multi_site.v6 : iface->cnf->ipv6_multi_glbl.v6;
403
404 #ifdef __MacOSX__
405     ifp->int6_multaddr.sin6_scope_id = 0;
406 #endif
407
408     OLSR_DEBUG(LOG_INTERFACE, "\tMulticast: %s\n", ip6_to_string(&buf, &ifp->int_multicast.v6.sin6_addr));
409
410     ifp->ip_addr.v6 = ifp->int_src.v6.sin6_addr;
411   } else {
412     /* IP version 4 */
413     memset(&ifp->int_src, 0, sizeof(ifp->int_src));
414     memset(&ifp->int_multicast, 0, sizeof(ifp->int_multicast));
415
416     /* Get interface address (IPv4) */
417     if (ioctl(olsr_cnf->ioctl_s, SIOCGIFADDR, &ifr) < 0) {
418       OLSR_WARN(LOG_INTERFACE, "\tCould not get address of interface - skipping it\n");
419       return -1;
420     }
421
422     ifp->int_src.v4 = *(struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_addr));
423
424     /* Find broadcast address */
425     if (iface->cnf->ipv4_broadcast.v4.s_addr) {
426       /* Specified broadcast */
427       ifp->int_multicast.v4.sin_addr = iface->cnf->ipv4_broadcast.v4;
428     } else {
429       /* Autodetect */
430       if (ioctl(olsr_cnf->ioctl_s, SIOCGIFBRDADDR, &ifr) < 0) {
431         OLSR_WARN(LOG_INTERFACE, "%s: ioctl (get broadaddr) failed", ifr.ifr_name);
432         return -1;
433       }
434
435       ifp->int_multicast.v4 = *(struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr));
436     }
437
438     /* Deactivate IP spoof filter */
439     deactivate_spoof(ifr_basename, ifp, olsr_cnf->ip_version);
440
441     /* Disable ICMP redirects */
442     disable_redirects(ifr_basename, ifp, olsr_cnf->ip_version);
443
444     ifp->int_src.v4.sin_family = AF_INET;
445     ifp->int_src.v4.sin_port = htons(olsr_cnf->olsr_port);
446     ifp->int_multicast.v4.sin_family = AF_INET;
447     ifp->int_multicast.v4.sin_port = htons(olsr_cnf->olsr_port);
448
449     ifp->ip_addr.v4 = ifp->int_src.v4.sin_addr;
450   }
451
452   /* check if interface with this IP already exists */
453   if (if_ifwithaddr(&ifp->ip_addr)) {
454     OLSR_ERROR(LOG_INTERFACE, "Warning, multiple interfaces with the same IP are deprecated. Use 'OriginatorAddress'"
455                " option if you fear a changing main address. Future versions of OLSR might block using multiple"
456                " interfaces with the same IP\n");
457   }
458
459   /* Get interface index */
460   ifp->if_index = if_nametoindex(ifr.ifr_name);
461
462   /* Get MTU */
463   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMTU, &ifr) < 0) {
464     ifp->int_mtu = OLSR_DEFAULT_MTU;
465   } else {
466     ifp->int_mtu = ifr.ifr_mtu;
467   }
468   ifp->int_mtu -= olsr_cnf->ip_version == AF_INET6 ? UDP_IPV6_HDRSIZE : UDP_IPV4_HDRSIZE;
469
470   OLSR_DEBUG(LOG_INTERFACE, "\tMTU - IPhdr: %d\n", ifp->int_mtu);
471
472   OLSR_INFO(LOG_INTERFACE, "Adding interface %s\n", iface->name);
473   OLSR_DEBUG(LOG_INTERFACE, "\tIndex %d\n", ifp->if_index);
474
475   if (olsr_cnf->ip_version == AF_INET) {
476     OLSR_DEBUG(LOG_INTERFACE, "\tAddress:%s\n", ip4_to_string(&buf, ifp->int_src.v4.sin_addr));
477     OLSR_DEBUG(LOG_INTERFACE, "\tBroadcast address:%s\n", ip4_to_string(&buf, ifp->int_multicast.v4.sin_addr));
478   } else {
479     OLSR_DEBUG(LOG_INTERFACE, "\tAddress: %s\n", ip6_to_string(&buf, &ifp->int_src.v6.sin6_addr));
480     OLSR_DEBUG(LOG_INTERFACE, "\tMulticast: %s\n", ip6_to_string(&buf, &ifp->int_multicast.v6.sin6_addr));
481   }
482
483   /*
484    * Clone interface name.
485    */
486   ifp->int_name = olsr_strdup(ifr_basename);
487
488 #if 0
489   ifp->gen_properties = NULL;
490 #endif
491   return 0;
492 }
493
494 /*
495  * Local Variables:
496  * c-basic-offset: 2
497  * indent-tabs-mode: nil
498  * End:
499  */