3 * The olsr.org Optimized Link-State Routing daemon(olsrd)
4 * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 * Visit http://www.olsr.org for more information.
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.
43 #include "../net_os.h"
44 #include "../ipcalc.h"
45 #include "../parser.h" /* dnc: needed for call to packet_parser() */
46 #include "../olsr_protocol.h"
47 #include "../olsr_cfg.h"
49 #include <sys/types.h>
50 #include <sys/socket.h>
55 #include <sys/ioctl.h>
58 #include <netinet/in.h>
63 #include "wrn/coreip/netinet6/in6_var.h"
65 #include <sys/socket.h>
66 #include "wrn/coreip/net/ifaddrs.h"
67 #include <selectLib.h>
69 #define syslog(a, b) fdprintf(a, b);
71 #include <sys/param.h>
75 #include <net/if_ether.h>
76 #include <netinet6/in6_var.h> /* For struct in6_ifreq */
77 #include <net80211/ieee80211_ioctl.h>
82 #include <netinet/if_ether.h>
83 #include <netinet/in_systm.h>
84 #include <netinet/ip.h>
85 #include <netinet/ip_icmp.h>
86 #include <netinet/icmp_var.h>
87 #include <netinet/icmp6.h>
88 #include <netinet6/in6_var.h> /* For struct in6_ifreq */
91 #include <net80211/ieee80211.h>
92 #include <net80211/ieee80211_ioctl.h>
97 #include <net/if_var.h>
98 #include <net/ethernet.h>
99 #include <netinet/in_var.h>
100 #ifndef FBSD_NO_80211
101 #include <net80211/ieee80211.h>
102 #include <net80211/ieee80211_ioctl.h>
108 #include <net/if_var.h>
109 #include <net/ethernet.h>
110 #include <netinet/in_var.h>
113 #include <net/if_dl.h>
119 #define SIOCGIFGENERIC _IOWR('i', 58, struct ifreq) /* generic IF get op */
120 #define SIOCGWAVELAN SIOCGIFGENERIC
123 #include <sys/sysctl.h>
125 static int ignore_redir;
126 static int send_redir;
130 set_sysctl_int(const char *name, int new)
133 #if defined(__MacOSX__) || defined(__OpenBSD__) || defined(__NetBSD__)
134 size_t len = sizeof(old);
136 unsigned int len = sizeof(old);
142 /* Set net.inet.ip.forwarding by default. */
146 mib[3] = IPCTL_FORWARDING;
148 if (!strcmp(name, "net.inet6.ip6.forwarding")) {
150 mib[2] = IPPROTO_IPV6;
151 } else if (!strcmp(name, "net.inet.icmp.rediraccept")) {
152 mib[2] = IPPROTO_ICMP;
153 mib[3] = ICMPCTL_REDIRACCEPT;
154 } else if (!strcmp(name, "net.inet6.icmp6.rediraccept")) {
155 mib[2] = IPPROTO_ICMPV6;
156 mib[3] = ICMPV6CTL_REDIRACCEPT;
157 } else if (!strcmp(name, "net.inet.ip.redirect")) {
158 mib[3] = IPCTL_SENDREDIRECTS;
159 } else if (!strcmp(name, "net.inet6.ip6.redirect")) {
161 mib[2] = IPPROTO_IPV6;
162 mib[3] = IPCTL_SENDREDIRECTS;
165 if (sysctl(mib, 4, &old, &len, &new, sizeof(new)) < 0)
169 if (sysctlbyname((const char *)name, &old, &len, &new, sizeof(new)) < 0)
177 enable_ip_forwarding(int version)
179 const char *name = version == AF_INET ? "net.inet.ip.forwarding" : "net.inet6.ip6.forwarding";
181 gateway = set_sysctl_int(name, 1);
183 fprintf(stderr, "Cannot enable IP forwarding. Please enable IP forwarding manually." " Continuing in 3 seconds...\n");
191 disable_redirects_global(int version)
195 /* do not accept ICMP redirects */
197 #if defined(__OpenBSD__) || defined(__NetBSD__)
198 if (version == AF_INET)
199 name = "net.inet.icmp.rediraccept";
201 name = "net.inet6.icmp6.rediraccept";
203 ignore_redir = set_sysctl_int(name, 0);
204 #elif defined __FreeBSD__ || defined __MacOSX__
205 if (version == AF_INET) {
206 name = "net.inet.icmp.drop_redirect";
207 ignore_redir = set_sysctl_int(name, 1);
209 name = "net.inet6.icmp6.rediraccept";
210 ignore_redir = set_sysctl_int(name, 0);
213 if (version == AF_INET)
214 name = "net.inet.icmp.drop_redirect";
216 name = "net.inet6.icmp6.drop_redirect";
218 ignore_redir = set_sysctl_int(name, 1);
221 if (ignore_redir < 0) {
223 "Cannot disable incoming ICMP redirect messages. " "Please disable them manually. Continuing in 3 seconds...\n");
227 /* do not send ICMP redirects */
229 if (version == AF_INET)
230 name = "net.inet.ip.redirect";
232 name = "net.inet6.ip6.redirect";
234 send_redir = set_sysctl_int(name, 0);
235 if (send_redir < 0) {
237 "Cannot disable outgoing ICMP redirect messages. " "Please disable them manually. Continuing in 3 seconds...\n");
245 disable_redirects(const char *if_name __attribute__ ((unused)), struct interface *iface __attribute__ ((unused)), int version
246 __attribute__ ((unused)))
249 * this function gets called for each interface olsrd uses; however,
250 * FreeBSD can only globally control ICMP redirects, and not on a
251 * per-interface basis; hence, only disable ICMP redirects in the "global"
258 deactivate_spoof(const char *if_name __attribute__ ((unused)), struct interface *iface __attribute__ ((unused)), int version
259 __attribute__ ((unused)))
265 restore_settings(int version)
267 /* reset IP forwarding */
268 const char *name = version == AF_INET ? "net.inet.ip.forwarding" : "net.inet6.ip6.forwarding";
270 set_sysctl_int(name, gateway);
272 /* reset incoming ICMP redirects */
275 name = version == AF_INET ? "net.inet.icmp.rediraccept" : "net.inet6.icmp6.rediraccept";
276 #elif defined __FreeBSD__ || defined __MacOSX__
277 name = version == AF_INET ? "net.inet.icmp.drop_redirect" : "net.inet6.icmp6.rediraccept";
279 name = version == AF_INET ? "net.inet.icmp.drop_redirect" : "net.inet6.icmp6.drop_redirect";
281 set_sysctl_int(name, ignore_redir);
283 /* reset outgoing ICMP redirects */
284 name = version == AF_INET ? "net.inet.ip.redirect" : "net.inet6.ip6.redirect";
285 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...");
301 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
303 syslog(LOG_ERR, "hcsocket: %m");
307 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
308 perror("SO_REUSEADDR failed");
312 /* connect to PORT on HOST */
313 if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
315 fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
316 printf("connection refused\n");
323 /* Keep TCP socket blocking */
328 getsocket(int bufspace, char *int_name __attribute__ ((unused)))
330 struct sockaddr_in sin;
332 int sock = socket(AF_INET, SOCK_DGRAM, 0);
335 syslog(LOG_ERR, "socket: %m");
340 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) {
341 perror("setsockopt");
342 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
347 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
348 perror("SO_REUSEADDR failed");
353 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) {
354 perror("SO_REUSEPORT failed");
359 if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, (char *)&on, sizeof(on)) < 0) {
360 perror("IP_RECVIF failed");
365 for (on = bufspace;; on -= 1024) {
366 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&on, sizeof(on)) == 0)
368 if (on <= 8 * 1024) {
369 perror("setsockopt");
370 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
375 memset(&sin, 0, sizeof(sin));
376 sin.sin_family = AF_INET;
377 sin.sin_port = htons(olsr_cnf->olsrport);
378 sin.sin_addr.s_addr = INADDR_ANY;
379 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
381 syslog(LOG_ERR, "bind: %m");
386 on = fcntl(sock, F_GETFL);
388 syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
390 if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
391 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
398 getsocket6(int bufspace, char *int_name __attribute__ ((unused)))
400 struct sockaddr_in6 sin;
402 int sock = socket(AF_INET6, SOCK_DGRAM, 0);
406 syslog(LOG_ERR, "socket: %m");
410 for (on = bufspace;; on -= 1024) {
411 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&on, sizeof(on)) == 0)
413 if (on <= 8 * 1024) {
414 perror("setsockopt");
415 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
420 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
421 perror("SO_REUSEADDR failed");
426 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) {
427 perror("SO_REUSEPORT failed");
431 #ifdef IPV6_RECVPKTINFO
432 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on, sizeof(on)) < 0) {
433 perror("IPV6_RECVPKTINFO failed");
437 #elif defined IPV6_PKTINFO
438 if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on, sizeof(on)) < 0) {
439 perror("IPV6_PKTINFO failed");
445 memset(&sin, 0, sizeof(sin));
446 sin.sin6_family = AF_INET6;
447 sin.sin6_port = htons(olsr_cnf->olsrport);
448 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
450 syslog(LOG_ERR, "bind: %m");
455 on = fcntl(sock, F_GETFL);
457 syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
459 if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
460 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
467 join_mcast(struct interface *ifs, int sock)
469 /* See netinet6/in6.h */
470 struct ipaddr_str addrstr;
471 struct ipv6_mreq mcastreq;
472 #ifdef IPV6_USE_MIN_MTU
476 mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
477 mcastreq.ipv6mr_interface = ifs->if_index;
479 OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name,
480 olsr_ip_to_string(&addrstr, (union olsr_ip_addr *)&ifs->int6_multaddr.sin6_addr));
483 #ifdef IPV6_JOIN_GROUP
484 /* Join reciever group */
485 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
486 #else /* rfc 2133, obsoleted */
487 /* Join receiver group */
488 if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
491 perror("Join multicast send");
495 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface)) < 0) {
496 perror("Set multicast if");
500 #ifdef IPV6_USE_MIN_MTU
502 * This allow multicast packets to use the full interface MTU and not
503 * be limited to 1280 bytes.
506 if (setsockopt(sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (char *)&on, sizeof(on)) < 0) {
507 perror("IPV6_USE_MIN_MTU failed");
513 OLSR_PRINTF(3, "OK\n");
518 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
520 struct ifaddrs *ifap, *ifa;
521 const struct sockaddr_in6 *sin6 = NULL;
522 struct in6_ifreq ifr6;
527 if (getifaddrs(&ifap) != 0) {
528 OLSR_PRINTF(3, "get_ipv6_address: getifaddrs() failed.\n");
532 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
533 if ((ifa->ifa_addr->sa_family == AF_INET6) && (strcmp(ifa->ifa_name, ifname) == 0)) {
534 sin6 = (const struct sockaddr_in6 *)(ifa->ifa_addr);
535 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
537 strscpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
538 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
539 OLSR_PRINTF(3, "socket(AF_INET6,SOCK_DGRAM)");
542 ifr6.ifr_addr = *sin6;
543 if (ioctl(s6, SIOCGIFAFLAG_IN6, (int)&ifr6) < 0) {
544 OLSR_PRINTF(3, "ioctl(SIOCGIFAFLAG_IN6)");
549 flags6 = ifr6.ifr_ifru.ifru_flags6;
550 if ((flags6 & IN6_IFF_ANYCAST) != 0)
552 if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
554 memcpy(&saddr6->sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
560 memcpy(&saddr6->sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
575 * Wrapper for sendto(2)
579 static u_int16_t ip_id = 0;
583 olsr_sendto(int s, const void *buf, size_t len, int flags __attribute__ ((unused)), const struct sockaddr *to, socklen_t tolen)
589 char errbuf[LIBNET_ERRBUF_SIZE];
590 libnet_ptag_t udp_tag, ip_tag, ether_tag;
591 unsigned char enet_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
593 struct sockaddr_in *to_in = (struct sockaddr_in *)to;
595 struct interface *iface;
597 udp_tag = ip_tag = ether_tag = 0;
598 destip = to_in->sin_addr.s_addr;
599 iface = if_ifwithsock(s);
601 /* initialize libnet */
602 context = libnet_init(LIBNET_LINK, iface->int_name, errbuf);
603 if (context == NULL) {
604 OLSR_PRINTF(1, "libnet init: %s\n", libnet_geterror(context));
608 /* initialize IP ID field if necessary */
610 ip_id = (u_int16_t) (arc4random() & 0xffff);
613 udp_tag = libnet_build_udp(olsr_cnf->olsrport, /* src port */
614 olsr_cnf->olsrport, /* dest port */
615 LIBNET_UDP_H + len, /* length */
618 len, /* payload size */
619 context, /* context */
620 udp_tag); /* pblock */
622 OLSR_PRINTF(1, "libnet UDP header: %s\n", libnet_geterror(context));
626 ip_tag = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_UDP_H + len, /* len */
631 IPPROTO_UDP, /* protocol */
633 libnet_get_ipaddr4(context), /* src IP */
634 destip, /* dest IP */
637 context, /* context */
638 ip_tag); /* pblock */
640 OLSR_PRINTF(1, "libnet IP header: %s\n", libnet_geterror(context));
644 ether_tag = libnet_build_ethernet(enet_broadcast, /* ethernet dest */
645 libnet_get_hwaddr(context), /* ethernet source */
646 ETHERTYPE_IP, /* protocol type */
648 0, /* payload size */
649 context, /* libnet handle */
650 ether_tag); /* pblock tag */
651 if (ether_tag == -1) {
652 OLSR_PRINTF(1, "libnet ethernet header: %s\n", libnet_geterror(context));
656 status = libnet_write(context);
658 OLSR_PRINTF(1, "libnet packet write: %s\n", libnet_geterror(context));
662 libnet_destroy(context);
667 return sendto(s, buf, len, flags, (const struct sockaddr *)to, tolen);
672 * Wrapper for recvfrom(2)
676 olsr_recvfrom(int s, void *buf, size_t len, int flags __attribute__ ((unused)), struct sockaddr *from, socklen_t * fromlen)
682 unsigned char chdr[4096];
685 struct sockaddr_dl *sdl;
686 struct sockaddr_in *sin = (struct sockaddr_in *)from;
687 struct sockaddr_in6 *sin6;
688 struct in6_addr *iaddr6;
689 struct in6_pktinfo *pkti;
690 struct interface *ifc;
691 char addrstr[INET6_ADDRSTRLEN];
692 char iname[IFNAMSIZ];
695 memset(&mhdr, 0, sizeof(mhdr));
696 memset(&iov, 0, sizeof(iov));
698 mhdr.msg_name = (caddr_t) from;
699 mhdr.msg_namelen = *fromlen;
702 mhdr.msg_control = (caddr_t) & cmu;
703 mhdr.msg_controllen = sizeof(cmu);
708 count = recvmsg(s, &mhdr, MSG_DONTWAIT);
713 /* this needs to get communicated back to caller */
714 *fromlen = mhdr.msg_namelen;
715 if (olsr_cnf->ip_version == AF_INET6) {
716 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) {
717 if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO) {
718 pkti = (struct in6_pktinfo *)CMSG_DATA(cm);
719 iaddr6 = &pkti->ipi6_addr;
720 if_indextoname(pkti->ipi6_ifindex, iname);
725 sdl = (struct sockaddr_dl *)CMSG_DATA(cm);
726 memset(iname, 0, sizeof(iname));
727 memcpy(iname, sdl->sdl_data, sdl->sdl_nlen);
730 ifc = if_ifwithsock(s);
732 sin6 = (struct sockaddr_in6 *)from;
733 OLSR_PRINTF(4, "%d bytes from %s, socket associated %s really received on %s\n", count,
734 inet_ntop(olsr_cnf->ip_version, olsr_cnf->ip_version == AF_INET6 ? (char *)&sin6->sin6_addr : (char *)&sin->sin_addr,
735 addrstr, sizeof(addrstr)), ifc->int_name, iname);
738 if (strcmp(ifc->int_name, iname) != 0) {
747 * Wrapper for select(2)
751 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
753 return select(nfds, readfds, writefds, exceptfds, timeout);
757 check_wireless_interface(char *ifname)
759 #if defined __FreeBSD__ && !defined FBSD_NO_80211
761 /* From FreeBSD ifconfig/ifieee80211.c ieee80211_status() */
762 struct ieee80211req ireq;
765 memset(&ireq, 0, sizeof(ireq));
766 strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
768 ireq.i_type = IEEE80211_IOC_SSID;
770 return (ioctl(olsr_cnf->ioctl_s, SIOCG80211, &ireq) >= 0) ? 1 : 0;
771 #elif defined __OpenBSD__
772 struct ieee80211_nodereq nr;
773 bzero(&nr, sizeof(nr));
774 strlcpy(nr.nr_ifname, ifname, sizeof(nr.nr_ifname));
775 return (ioctl(olsr_cnf->ioctl_s, SIOCG80211FLAGS, &nr) >= 0) ? 1 : 0;
776 #elif defined __NetBSD__
778 struct ieee80211_nwid data;
781 memset(&ireq, 0, sizeof(ireq));
782 strlcpy(ireq.ifr_name, ifname, sizeof(ireq.ifr_name));
783 ireq.ifr_data = &data;
784 ret = ioctl(olsr_cnf->ioctl_s, SIOCG80211NWID, &ireq);
789 ifname = NULL; /* squelsh compiler warning */
794 #include <sys/sockio.h>
797 calculate_if_metric(char *ifname)
799 if (check_wireless_interface(ifname)) {
805 /* Andreas: Perhaps SIOCGIFMEDIA is the way to do this? */
806 struct ifmediareq ifm;
808 memset(&ifm, 0, sizeof(ifm));
809 strlcpy(ifm.ifm_name, ifname, sizeof(ifm.ifm_name));
811 if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMEDIA, &ifm) < 0) {
812 OLSR_PRINTF(1, "Error SIOCGIFMEDIA(%s)\n", ifm.ifm_name);
813 return WEIGHT_ETHERNET_DEFAULT;
816 OLSR_PRINTF(1, "%s: STATUS 0x%08x\n", ifm.ifm_name, ifm.ifm_status);
818 return WEIGHT_ETHERNET_DEFAULT;
825 * indent-tabs-mode: nil