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>
79 #include <netinet/if_ether.h>
80 #include <netinet/in_systm.h>
81 #include <netinet/ip.h>
82 #include <netinet/ip_icmp.h>
83 #include <netinet/icmp_var.h>
84 #include <netinet/icmp6.h>
85 #include <netinet6/in6_var.h> /* For struct in6_ifreq */
88 #include <net80211/ieee80211.h>
89 #include <net80211/ieee80211_ioctl.h>
94 #include <net/if_var.h>
95 #include <net/ethernet.h>
96 #include <netinet/in_var.h>
98 #include <net80211/ieee80211.h>
99 #include <net80211/ieee80211_ioctl.h>
105 #include <net/if_var.h>
106 #include <net/ethernet.h>
107 #include <netinet/in_var.h>
110 #include <net/if_dl.h>
116 #define SIOCGIFGENERIC _IOWR('i', 58, struct ifreq) /* generic IF get op */
117 #define SIOCGWAVELAN SIOCGIFGENERIC
120 #include <sys/sysctl.h>
122 static int ignore_redir;
123 static int send_redir;
127 set_sysctl_int(const char *name, int new)
130 #if __MacOSX__ || __OpenBSD__
131 size_t len = sizeof(old);
133 unsigned int len = sizeof(old);
139 /* Set net.inet.ip.forwarding by default. */
143 mib[3] = IPCTL_FORWARDING;
145 if (!strcmp(name, "net.inet6.ip6.forwarding")) {
147 mib[2] = IPPROTO_IPV6;
148 } else if (!strcmp(name, "net.inet.icmp.rediraccept")) {
149 mib[2] = IPPROTO_ICMP;
150 mib[3] = ICMPCTL_REDIRACCEPT;
151 } else if (!strcmp(name, "net.inet6.icmp6.rediraccept")) {
152 mib[2] = IPPROTO_ICMPV6;
153 mib[3] = ICMPV6CTL_REDIRACCEPT;
154 } else if (!strcmp(name, "net.inet.ip.redirect")) {
155 mib[3] = IPCTL_SENDREDIRECTS;
156 } else if (!strcmp(name, "net.inet6.ip6.redirect")) {
158 mib[2] = IPPROTO_IPV6;
159 mib[3] = IPCTL_SENDREDIRECTS;
162 if (sysctl(mib, 4, &old, &len, &new, sizeof(new)) < 0)
166 if (sysctlbyname((const char *)name, &old, &len, &new, sizeof(new)) < 0)
174 enable_ip_forwarding(int version)
176 const char *name = version == AF_INET ? "net.inet.ip.forwarding" : "net.inet6.ip6.forwarding";
178 gateway = set_sysctl_int(name, 1);
180 fprintf(stderr, "Cannot enable IP forwarding. Please enable IP forwarding manually." " Continuing in 3 seconds...\n");
188 disable_redirects_global(int version)
192 /* do not accept ICMP redirects */
195 if (version == AF_INET)
196 name = "net.inet.icmp.rediraccept";
198 name = "net.inet6.icmp6.rediraccept";
200 ignore_redir = set_sysctl_int(name, 0);
201 #elif defined __FreeBSD__ || defined __MacOSX__
202 if (version == AF_INET) {
203 name = "net.inet.icmp.drop_redirect";
204 ignore_redir = set_sysctl_int(name, 1);
206 name = "net.inet6.icmp6.rediraccept";
207 ignore_redir = set_sysctl_int(name, 0);
210 if (version == AF_INET)
211 name = "net.inet.icmp.drop_redirect";
213 name = "net.inet6.icmp6.drop_redirect";
215 ignore_redir = set_sysctl_int(name, 1);
218 if (ignore_redir < 0) {
220 "Cannot disable incoming ICMP redirect messages. " "Please disable them manually. Continuing in 3 seconds...\n");
224 /* do not send ICMP redirects */
226 if (version == AF_INET)
227 name = "net.inet.ip.redirect";
229 name = "net.inet6.ip6.redirect";
231 send_redir = set_sysctl_int(name, 0);
232 if (send_redir < 0) {
234 "Cannot disable outgoing ICMP redirect messages. " "Please disable them manually. Continuing in 3 seconds...\n");
242 disable_redirects(const char *if_name __attribute__ ((unused)), struct interface *iface __attribute__ ((unused)), int version
243 __attribute__ ((unused)))
246 * this function gets called for each interface olsrd uses; however,
247 * FreeBSD can only globally control ICMP redirects, and not on a
248 * per-interface basis; hence, only disable ICMP redirects in the "global"
255 deactivate_spoof(const char *if_name __attribute__ ((unused)), struct interface *iface __attribute__ ((unused)), int version
256 __attribute__ ((unused)))
262 restore_settings(int version)
264 /* reset IP forwarding */
265 const char *name = version == AF_INET ? "net.inet.ip.forwarding" : "net.inet6.ip6.forwarding";
267 set_sysctl_int(name, gateway);
269 /* reset incoming ICMP redirects */
272 name = version == AF_INET ? "net.inet.icmp.rediraccept" : "net.inet6.icmp6.rediraccept";
273 #elif defined __FreeBSD__ || defined __MacOSX__
274 name = version == AF_INET ? "net.inet.icmp.drop_redirect" : "net.inet6.icmp6.rediraccept";
276 name = version == AF_INET ? "net.inet.icmp.drop_redirect" : "net.inet6.icmp6.drop_redirect";
278 set_sysctl_int(name, ignore_redir);
280 /* reset outgoing ICMP redirects */
281 name = version == AF_INET ? "net.inet.ip.redirect" : "net.inet6.ip6.redirect";
282 set_sysctl_int(name, send_redir);
287 *Creates a nonblocking broadcast socket.
288 *@param sa sockaddr struct. Used for bind(2).
289 *@return the FD of the socket or -1 on error.
292 gethemusocket(struct sockaddr_in *pin)
296 OLSR_PRINTF(1, " Connecting to switch daemon port 10150...");
298 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
300 syslog(LOG_ERR, "hcsocket: %m");
304 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
305 perror("SO_REUSEADDR failed");
309 /* connect to PORT on HOST */
310 if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
312 fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
313 printf("connection refused\n");
320 /* Keep TCP socket blocking */
325 getsocket(int bufspace, char *int_name __attribute__ ((unused)))
327 struct sockaddr_in sin;
329 int sock = socket(AF_INET, SOCK_DGRAM, 0);
332 syslog(LOG_ERR, "socket: %m");
337 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) {
338 perror("setsockopt");
339 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
344 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
345 perror("SO_REUSEADDR failed");
350 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) {
351 perror("SO_REUSEPORT failed");
356 if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, (char *)&on, sizeof(on)) < 0) {
357 perror("IP_RECVIF failed");
362 for (on = bufspace;; on -= 1024) {
363 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&on, sizeof(on)) == 0)
365 if (on <= 8 * 1024) {
366 perror("setsockopt");
367 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
372 memset(&sin, 0, sizeof(sin));
373 sin.sin_family = AF_INET;
374 sin.sin_port = htons(olsr_cnf->olsrport);
375 sin.sin_addr.s_addr = INADDR_ANY;
376 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
378 syslog(LOG_ERR, "bind: %m");
383 on = fcntl(sock, F_GETFL);
385 syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
387 if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
388 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
395 getsocket6(int bufspace, char *int_name __attribute__ ((unused)))
397 struct sockaddr_in6 sin;
399 int sock = socket(AF_INET6, SOCK_DGRAM, 0);
403 syslog(LOG_ERR, "socket: %m");
407 for (on = bufspace;; on -= 1024) {
408 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&on, sizeof(on)) == 0)
410 if (on <= 8 * 1024) {
411 perror("setsockopt");
412 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
417 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
418 perror("SO_REUSEADDR failed");
423 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) {
424 perror("SO_REUSEPORT failed");
428 #ifdef IPV6_RECVPKTINFO
429 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on, sizeof(on)) < 0) {
430 perror("IPV6_RECVPKTINFO failed");
434 #elif defined IPV6_PKTINFO
435 if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on, sizeof(on)) < 0) {
436 perror("IPV6_PKTINFO failed");
442 memset(&sin, 0, sizeof(sin));
443 sin.sin6_family = AF_INET6;
444 sin.sin6_port = htons(olsr_cnf->olsrport);
445 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
447 syslog(LOG_ERR, "bind: %m");
452 on = fcntl(sock, F_GETFL);
454 syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
456 if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
457 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
464 join_mcast(struct interface *ifs, int sock)
466 /* See netinet6/in6.h */
467 struct ipaddr_str addrstr;
468 struct ipv6_mreq mcastreq;
469 #ifdef IPV6_USE_MIN_MTU
473 mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
474 mcastreq.ipv6mr_interface = ifs->if_index;
476 OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name,
477 olsr_ip_to_string(&addrstr, (union olsr_ip_addr *)&ifs->int6_multaddr.sin6_addr));
480 #ifdef IPV6_JOIN_GROUP
481 /* Join reciever group */
482 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
483 #else /* rfc 2133, obsoleted */
484 /* Join receiver group */
485 if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
488 perror("Join multicast send");
492 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface)) < 0) {
493 perror("Set multicast if");
497 #ifdef IPV6_USE_MIN_MTU
499 * This allow multicast packets to use the full interface MTU and not
500 * be limited to 1280 bytes.
503 if (setsockopt(sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (char *)&on, sizeof(on)) < 0) {
504 perror("IPV6_USE_MIN_MTU failed");
510 OLSR_PRINTF(3, "OK\n");
515 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) {
525 OLSR_PRINTF(3, "get_ipv6_address: getifaddrs() failed.\n");
529 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
530 if ((ifa->ifa_addr->sa_family == AF_INET6) && (strcmp(ifa->ifa_name, ifname) == 0)) {
531 sin6 = (const struct sockaddr_in6 *)(ifa->ifa_addr);
532 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
534 strscpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
535 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
536 OLSR_PRINTF(3, "socket(AF_INET6,SOCK_DGRAM)");
539 ifr6.ifr_addr = *sin6;
540 if (ioctl(s6, SIOCGIFAFLAG_IN6, (int)&ifr6) < 0) {
541 OLSR_PRINTF(3, "ioctl(SIOCGIFAFLAG_IN6)");
546 flags6 = ifr6.ifr_ifru.ifru_flags6;
547 if ((flags6 & IN6_IFF_ANYCAST) != 0)
549 if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
551 memcpy(&saddr6->sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
557 memcpy(&saddr6->sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
572 * Wrapper for sendto(2)
576 static u_int16_t ip_id = 0;
580 olsr_sendto(int s, const void *buf, size_t len, int flags __attribute__ ((unused)), const struct sockaddr *to, socklen_t tolen)
586 char errbuf[LIBNET_ERRBUF_SIZE];
587 libnet_ptag_t udp_tag, ip_tag, ether_tag;
588 unsigned char enet_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
590 struct sockaddr_in *to_in = (struct sockaddr_in *)to;
592 struct interface *iface;
594 udp_tag = ip_tag = ether_tag = 0;
595 destip = to_in->sin_addr.s_addr;
596 iface = if_ifwithsock(s);
598 /* initialize libnet */
599 context = libnet_init(LIBNET_LINK, iface->int_name, errbuf);
600 if (context == NULL) {
601 OLSR_PRINTF(1, "libnet init: %s\n", libnet_geterror(context));
605 /* initialize IP ID field if necessary */
607 ip_id = (u_int16_t) (arc4random() & 0xffff);
610 udp_tag = libnet_build_udp(olsr_cnf->olsrport, /* src port */
611 olsr_cnf->olsrport, /* dest port */
612 LIBNET_UDP_H + len, /* length */
615 len, /* payload size */
616 context, /* context */
617 udp_tag); /* pblock */
619 OLSR_PRINTF(1, "libnet UDP header: %s\n", libnet_geterror(context));
623 ip_tag = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_UDP_H + len, /* len */
628 IPPROTO_UDP, /* protocol */
630 libnet_get_ipaddr4(context), /* src IP */
631 destip, /* dest IP */
634 context, /* context */
635 ip_tag); /* pblock */
637 OLSR_PRINTF(1, "libnet IP header: %s\n", libnet_geterror(context));
641 ether_tag = libnet_build_ethernet(enet_broadcast, /* ethernet dest */
642 libnet_get_hwaddr(context), /* ethernet source */
643 ETHERTYPE_IP, /* protocol type */
645 0, /* payload size */
646 context, /* libnet handle */
647 ether_tag); /* pblock tag */
648 if (ether_tag == -1) {
649 OLSR_PRINTF(1, "libnet ethernet header: %s\n", libnet_geterror(context));
653 status = libnet_write(context);
655 OLSR_PRINTF(1, "libnet packet write: %s\n", libnet_geterror(context));
659 libnet_destroy(context);
664 return sendto(s, buf, len, flags, (const struct sockaddr *)to, tolen);
669 * Wrapper for recvfrom(2)
673 olsr_recvfrom(int s, void *buf, size_t len, int flags __attribute__ ((unused)), struct sockaddr *from, socklen_t * fromlen)
679 unsigned char chdr[4096];
682 struct sockaddr_dl *sdl;
683 struct sockaddr_in *sin = (struct sockaddr_in *)from;
684 struct sockaddr_in6 *sin6;
685 struct in6_addr *iaddr6;
686 struct in6_pktinfo *pkti;
687 struct interface *ifc;
688 char addrstr[INET6_ADDRSTRLEN];
689 char iname[IFNAMSIZ];
692 memset(&mhdr, 0, sizeof(mhdr));
693 memset(&iov, 0, sizeof(iov));
695 mhdr.msg_name = (caddr_t) from;
696 mhdr.msg_namelen = *fromlen;
699 mhdr.msg_control = (caddr_t) & cmu;
700 mhdr.msg_controllen = sizeof(cmu);
705 count = recvmsg(s, &mhdr, MSG_DONTWAIT);
710 /* this needs to get communicated back to caller */
711 *fromlen = mhdr.msg_namelen;
712 if (olsr_cnf->ip_version == AF_INET6) {
713 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) {
714 if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO) {
715 pkti = (struct in6_pktinfo *)CMSG_DATA(cm);
716 iaddr6 = &pkti->ipi6_addr;
717 if_indextoname(pkti->ipi6_ifindex, iname);
722 sdl = (struct sockaddr_dl *)CMSG_DATA(cm);
723 memset(iname, 0, sizeof(iname));
724 memcpy(iname, sdl->sdl_data, sdl->sdl_nlen);
727 ifc = if_ifwithsock(s);
729 sin6 = (struct sockaddr_in6 *)from;
730 OLSR_PRINTF(4, "%d bytes from %s, socket associated %s really received on %s\n", count,
731 inet_ntop(olsr_cnf->ip_version, olsr_cnf->ip_version == AF_INET6 ? (char *)&sin6->sin6_addr : (char *)&sin->sin_addr,
732 addrstr, sizeof(addrstr)), ifc->int_name, iname);
734 if (strcmp(ifc->int_name, iname) != 0) {
742 * Wrapper for select(2)
746 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
748 return select(nfds, readfds, writefds, exceptfds, timeout);
752 check_wireless_interface(char *ifname)
754 #if defined __FreeBSD__ && !defined FBSD_NO_80211
756 /* From FreeBSD ifconfig/ifieee80211.c ieee80211_status() */
757 struct ieee80211req ireq;
760 memset(&ireq, 0, sizeof(ireq));
761 strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
763 ireq.i_type = IEEE80211_IOC_SSID;
765 return (ioctl(olsr_cnf->ioctl_s, SIOCG80211, &ireq) >= 0) ? 1 : 0;
766 #elif defined __OpenBSD__
767 struct ieee80211_nodereq nr;
768 bzero(&nr, sizeof(nr));
769 strlcpy(nr.nr_ifname, ifname, sizeof(nr.nr_ifname));
770 return (ioctl(olsr_cnf->ioctl_s, SIOCG80211FLAGS, &nr) >= 0) ? 1 : 0;
772 ifname = NULL; /* squelsh compiler warning */
777 #include <sys/sockio.h>
780 calculate_if_metric(char *ifname)
782 if (check_wireless_interface(ifname)) {
788 /* Andreas: Perhaps SIOCGIFMEDIA is the way to do this? */
789 struct ifmediareq ifm;
791 memset(&ifm, 0, sizeof(ifm));
792 strlcpy(ifm.ifm_name, ifname, sizeof(ifm.ifm_name));
794 if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMEDIA, &ifm) < 0) {
795 OLSR_PRINTF(1, "Error SIOCGIFMEDIA(%s)\n", ifm.ifm_name);
796 return WEIGHT_ETHERNET_DEFAULT;
799 OLSR_PRINTF(1, "%s: STATUS 0x%08x\n", ifm.ifm_name, ifm.ifm_status);
801 return WEIGHT_ETHERNET_DEFAULT;
808 * indent-tabs-mode: nil