2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
3 * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
16 * * Neither the name of olsr.org, olsrd nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
33 * Visit http://www.olsr.org for more information.
35 * If you find this software useful feel free to make a donation
36 * to the project. For more information see the website or contact
37 * the copyright holders.
39 * $Id: net.c,v 1.30 2007/02/04 23:36:35 bernd67 Exp $
44 #include "parser.h" /* dnc: needed for call to packet_parser() */
50 #include <sys/param.h>
51 #include <net/if_ether.h>
55 #include <netinet/if_ether.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_icmp.h>
59 #include <netinet/icmp_var.h>
60 #include <netinet/icmp6.h>
65 #include <net/if_var.h>
66 #include <net/ethernet.h>
67 #include <netinet/in_var.h>
69 #include <net80211/ieee80211.h>
70 #include <net80211/ieee80211_ioctl.h>
71 #include <dev/wi/if_wavelan_ieee.h>
72 #include <dev/wi/if_wireg.h>
76 #include <net/if_dl.h>
81 //#define SIOCGIFGENERIC _IOWR('i', 58, struct ifreq) /* generic IF get op */
82 //#define SIOCGWAVELAN SIOCGIFGENERIC
84 #include <sys/sysctl.h>
86 static int ignore_redir;
87 static int send_redir;
90 static int set_sysctl_int(char *name, int new)
93 unsigned int len = sizeof (old);
98 /* Set net.inet.ip.forwarding by default. */
102 mib[3] = IPCTL_FORWARDING;
104 if (!strcmp(name, "net.inet6.ip6.forwarding"))
107 mib[2] = IPPROTO_IPV6;
109 else if (!strcmp(name, "net.inet.icmp.rediraccept"))
111 mib[2] = IPPROTO_ICMP;
112 mib[3] = ICMPCTL_REDIRACCEPT;
114 else if (!strcmp(name, "net.inet6.icmp6.rediraccept"))
116 mib[2] = IPPROTO_ICMPV6;
117 mib[3] = ICMPV6CTL_REDIRACCEPT;
119 else if (!strcmp(name, "net.inet.ip.redirect"))
121 mib[3] = IPCTL_SENDREDIRECTS;
123 else if (!strcmp(name, "net.inet6.ip6.redirect"))
126 mib[2] = IPPROTO_IPV6;
127 mib[3] = IPCTL_SENDREDIRECTS;
130 if (sysctl(mib, 4, &old, &len, &new, sizeof (new)) < 0)
134 if (sysctlbyname(name, &old, &len, &new, sizeof (new)) < 0)
141 int enable_ip_forwarding(int version)
145 if (olsr_cnf->ip_version == AF_INET)
146 name = "net.inet.ip.forwarding";
149 name = "net.inet6.ip6.forwarding";
151 gateway = set_sysctl_int(name, 1);
155 fprintf(stderr, "Cannot enable IP forwarding. Please enable IP forwarding manually. Continuing in 3 seconds...\n");
163 disable_redirects_global(int version)
167 // do not accept ICMP redirects
170 if (olsr_cnf->ip_version == AF_INET)
171 name = "net.inet.icmp.rediraccept";
174 name = "net.inet6.icmp6.rediraccept";
176 ignore_redir = set_sysctl_int(name, 0);
177 #elif defined __FreeBSD__
178 if (olsr_cnf->ip_version == AF_INET)
180 name = "net.inet.icmp.drop_redirect";
181 ignore_redir = set_sysctl_int(name, 1);
185 name = "net.inet6.icmp6.rediraccept";
186 ignore_redir = set_sysctl_int(name, 0);
189 if (olsr_cnf->ip_version == AF_INET)
190 name = "net.inet.icmp.drop_redirect";
193 name = "net.inet6.icmp6.drop_redirect";
195 ignore_redir = set_sysctl_int(name, 1);
198 if (ignore_redir < 0)
200 fprintf(stderr, "Cannot disable incoming ICMP redirect messages. Please disable them manually. Continuing in 3 seconds...\n");
204 // do not send ICMP redirects
206 if (olsr_cnf->ip_version == AF_INET)
207 name = "net.inet.ip.redirect";
210 name = "net.inet6.ip6.redirect";
212 send_redir = set_sysctl_int(name, 0);
216 fprintf(stderr, "Cannot disable outgoing ICMP redirect messages. Please disable them manually. Continuing in 3 seconds...\n");
223 int disable_redirects(char *if_name, struct interface *iface, int version)
225 // this function gets called for each interface olsrd uses; however,
226 // FreeBSD can only globally control ICMP redirects, and not on a
227 // per-interface basis; hence, only disable ICMP redirects in the "global"
232 int deactivate_spoof(char *if_name, struct interface *iface, int version)
237 int restore_settings(int version)
241 // reset IP forwarding
243 if (olsr_cnf->ip_version == AF_INET)
244 name = "net.inet.ip.forwarding";
247 name = "net.inet6.ip6.forwarding";
249 set_sysctl_int(name, gateway);
251 // reset incoming ICMP redirects
254 if (olsr_cnf->ip_version == AF_INET)
255 name = "net.inet.icmp.rediraccept";
257 name = "net.inet6.icmp6.rediraccept";
259 #elif defined __FreeBSD__
260 if (olsr_cnf->ip_version == AF_INET)
261 name = "net.inet.icmp.drop_redirect";
264 name = "net.inet6.icmp6.rediraccept";
266 if (olsr_cnf->ip_version == AF_INET)
267 name = "net.inet.icmp.drop_redirect";
270 name = "net.inet6.icmp6.drop_redirect";
273 set_sysctl_int(name, ignore_redir);
275 // reset outgoing ICMP redirects
277 if (olsr_cnf->ip_version == AF_INET)
278 name = "net.inet.ip.redirect";
281 name = "net.inet6.ip6.redirect";
283 set_sysctl_int(name, send_redir);
290 *Creates a nonblocking broadcast socket.
291 *@param sa sockaddr struct. Used for bind(2).
292 *@return the FD of the socket or -1 on error.
295 gethemusocket(struct sockaddr_in *pin)
299 OLSR_PRINTF(1, " Connecting to switch daemon port 10150...");
302 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
305 syslog(LOG_ERR, "hcsocket: %m");
309 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
311 perror("SO_REUSEADDR failed");
315 /* connect to PORT on HOST */
316 if (connect(sock,(struct sockaddr *) pin, sizeof(*pin)) < 0)
319 fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
320 printf("connection refused\n");
327 /* Keep TCP socket blocking */
333 getsocket(struct sockaddr *sa, int bufspace, char *int_name)
335 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
338 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
341 syslog(LOG_ERR, "socket: %m");
345 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
347 perror("setsockopt");
348 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
353 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
355 perror("SO_REUSEADDR failed");
360 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0)
362 perror("SO_REUSEPORT failed");
367 if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
369 perror("IP_RECVIF failed");
374 for (on = bufspace; ; on -= 1024)
376 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
377 &on, sizeof (on)) == 0)
381 perror("setsockopt");
382 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
387 if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0)
390 syslog(LOG_ERR, "bind: %m");
395 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
396 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
401 int getsocket6(struct sockaddr_in6 *sin, int bufspace, char *int_name)
405 if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
408 syslog(LOG_ERR, "socket: %m");
412 for (on = bufspace; ; on -= 1024)
414 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
415 &on, sizeof (on)) == 0)
419 perror("setsockopt");
420 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
425 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
427 perror("SO_REUSEADDR failed");
432 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0)
434 perror("SO_REUSEPORT failed");
438 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0)
440 perror("IPV6_RECVPKTINFO failed");
444 if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0)
447 syslog(LOG_ERR, "bind: %m");
452 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
453 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
461 join_mcast(struct interface *ifs, int sock)
463 /* See netinet6/in6.h */
465 struct ipv6_mreq mcastreq;
467 COPY_IP(&mcastreq.ipv6mr_multiaddr, &ifs->int6_multaddr.sin6_addr);
468 mcastreq.ipv6mr_interface = ifs->if_index;
470 OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, olsr_ip_to_string((union olsr_ip_addr *)&ifs->int6_multaddr.sin6_addr))
473 #ifdef IPV6_JOIN_GROUP
474 /* Join reciever group */
479 sizeof(struct ipv6_mreq))
481 #else /* rfc 2133, obsoleted */
482 /* Join receiver group */
487 sizeof(struct ipv6_mreq))
491 perror("Join multicast send");
499 (char *)&mcastreq.ipv6mr_interface,
500 sizeof(mcastreq.ipv6mr_interface))
503 perror("Set multicast if");
508 OLSR_PRINTF(3, "OK\n")
515 int get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
517 struct ifaddrs *ifap, *ifa;
518 const struct sockaddr_in6 *sin6 = NULL;
519 struct in6_ifreq ifr6;
524 if (getifaddrs(&ifap) != 0)
526 OLSR_PRINTF(3, "get_ipv6_address: getifaddrs() failed.\n")
530 for (ifa = ifap; ifa; ifa = ifa->ifa_next)
532 if (ifa->ifa_addr->sa_family == AF_INET6 &&
533 strcmp(ifa->ifa_name, ifname) == 0)
535 sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
536 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
538 strncpy(ifr6.ifr_name, ifname, sizeof(ifname));
539 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
541 OLSR_PRINTF(3, "socket(AF_INET6,SOCK_DGRAM)");
544 ifr6.ifr_addr = *sin6;
545 if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0)
547 OLSR_PRINTF(3, "ioctl(SIOCGIFAFLAG_IN6)");
552 flags6 = ifr6.ifr_ifru.ifru_flags6;
553 if ((flags6 & IN6_IFF_ANYCAST) != 0)
555 if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
559 memcpy(&saddr6->sin6_addr, &sin6->sin6_addr,
560 sizeof(struct in6_addr));
569 memcpy(&saddr6->sin6_addr, &sin6->sin6_addr,
570 sizeof(struct in6_addr));
588 * Wrapper for sendto(2)
592 static u_int16_t ip_id = 0;
600 const struct sockaddr *to,
607 char errbuf[LIBNET_ERRBUF_SIZE];
608 libnet_ptag_t udp_tag, ip_tag, ether_tag;
609 unsigned char enet_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
611 struct sockaddr_in *to_in = (struct sockaddr_in *) to;
613 struct interface *iface;
615 udp_tag = ip_tag = ether_tag = 0;
616 destip = to_in->sin_addr.s_addr;
617 iface = if_ifwithsock (s);
619 /* initialize libnet */
620 context = libnet_init(LIBNET_LINK, iface->int_name, errbuf);
623 OLSR_PRINTF (1, "libnet init: %s\n", libnet_geterror (context))
627 /* initialize IP ID field if necessary */
630 ip_id = (u_int16_t) (arc4random () & 0xffff);
633 udp_tag = libnet_build_udp (698, /* src port */
635 LIBNET_UDP_H + len, /* length */
638 len, /* payload size */
639 context, /* context */
640 udp_tag); /* pblock */
643 OLSR_PRINTF (1, "libnet UDP header: %s\n", libnet_geterror (context))
647 ip_tag = libnet_build_ipv4 (LIBNET_IPV4_H + LIBNET_UDP_H + len, /* len */
652 IPPROTO_UDP, /* protocol */
654 libnet_get_ipaddr4 (context), /* src IP */
655 destip, /* dest IP */
658 context, /* context */
659 ip_tag); /* pblock */
662 OLSR_PRINTF (1, "libnet IP header: %s\n", libnet_geterror (context))
666 ether_tag = libnet_build_ethernet (enet_broadcast, /* ethernet dest */
667 libnet_get_hwaddr (context), /* ethernet source */
668 ETHERTYPE_IP, /* protocol type */
670 0, /* payload size */
671 context, /* libnet handle */
672 ether_tag); /* pblock tag */
675 OLSR_PRINTF (1, "libnet ethernet header: %s\n", libnet_geterror (context))
679 status = libnet_write (context);
682 OLSR_PRINTF (1, "libnet packet write: %s\n", libnet_geterror (context))
686 libnet_destroy (context);
691 return sendto(s, buf, len, flags, to, tolen);
697 * Wrapper for recvfrom(2)
705 struct sockaddr *from,
711 struct sockaddr_dl *sdl;
712 struct sockaddr_in *sin = (struct sockaddr_in *) from; //XXX
713 struct sockaddr_in6 *sin6;
714 struct in6_addr *iaddr6;
715 struct in6_pktinfo *pkti;
716 struct interface *ifc;
717 char addrstr[INET6_ADDRSTRLEN];
718 char iname[IFNAMSIZ];
719 unsigned char chdr[4096];
722 bzero(&mhdr, sizeof(mhdr));
723 bzero(&iov, sizeof(iov));
725 mhdr.msg_name = (caddr_t) from;
726 mhdr.msg_namelen = *fromlen;
729 mhdr.msg_control = (caddr_t) chdr;
730 mhdr.msg_controllen = sizeof (chdr);
732 iov.iov_len = MAXMESSAGESIZE;
735 count = recvmsg (s, &mhdr, MSG_DONTWAIT);
741 /* this needs to get communicated back to caller */
742 *fromlen = mhdr.msg_namelen;
743 if (olsr_cnf->ip_version == AF_INET6)
745 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm;
746 cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm))
748 if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
750 pkti = (struct in6_pktinfo *) CMSG_DATA(cm);
751 iaddr6 = &pkti->ipi6_addr;
752 if_indextoname(pkti->ipi6_ifindex, iname);
758 cm = (struct cmsghdr *) chdr;
759 sdl = (struct sockaddr_dl *) CMSG_DATA (cm);
760 bzero (iname, sizeof (iname));
761 memcpy (iname, sdl->sdl_data, sdl->sdl_nlen);
764 ifc = if_ifwithsock (s);
766 sin6 = (struct sockaddr_in6 *)from;
767 OLSR_PRINTF (4, "%d bytes from %s, socket associated %s really received on %s\n",
769 (olsr_cnf->ip_version == AF_INET6) ?
770 inet_ntop(AF_INET6, (char *)&sin6->sin6_addr, addrstr,
772 inet_ntoa (sin->sin_addr),
776 if (strcmp (ifc->int_name, iname) != 0)
785 * Wrapper for select(2)
789 olsr_select(int nfds,
793 struct timeval *timeout)
804 check_wireless_interface(char *ifname)
806 #if defined __FreeBSD__ && !defined FBSD_NO_80211
810 memset((char *)&wreq, 0, sizeof(wreq));
811 memset((char *)&ifr, 0, sizeof(ifr));
813 wreq.wi_len = WI_MAX_DATALEN;
814 wreq.wi_type = WI_RID_IFACE_STATS;
816 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
817 ifr.ifr_data = (caddr_t)&wreq;
819 return (ioctl(olsr_cnf->ioctl_s, SIOCGWAVELAN, &ifr) >= 0) ? 1 : 0;
825 #include <sys/sockio.h>
828 calculate_if_metric(char *ifname)
830 if(check_wireless_interface(ifname))
839 /* Andreas: Perhaps SIOCGIFMEDIA is the way to do this? */
840 struct ifmediareq ifm;
842 memset(&ifm, 0, sizeof(ifm));
843 strlcpy(ifm.ifm_name, ifname, sizeof(ifm.ifm_name));
845 if(ioctl(olsr_cnf->ioctl_s, SIOCGIFMEDIA, &ifm) < 0)
847 OLSR_PRINTF(1, "Error SIOCGIFMEDIA(%s)\n", ifm.ifm_name)
848 return WEIGHT_ETHERNET_DEFAULT;
851 OLSR_PRINTF(1, "%s: STATUS 0x%08x\n", ifm.ifm_name, ifm.ifm_status)
853 return WEIGHT_ETHERNET_DEFAULT;