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.
47 #include "common/string.h"
48 #include "olsr_protocol.h"
49 #include "olsr_logging.h"
51 #include "os_kernel_tunnel.h"
53 #include "linux/linux_net.h"
56 #include <netinet/ip.h>
58 #include <sys/ioctl.h>
59 #include <sys/utsname.h>
68 * Fix bug in GLIBC, see https://bugzilla.redhat.com/show_bug.cgi?id=635260
73 #define IPTOS_CLASS(class) ((class) & IPTOS_CLASS_MASK)
75 #define IPV6_ADDR_LOOPBACK 0x0010U
76 #define IPV6_ADDR_LINKLOCAL 0x0020U
77 #define IPV6_ADDR_SITELOCAL 0x0040U
80 #define PROC_IPFORWARD_V4 "/proc/sys/net/ipv4/ip_forward"
81 #define PROC_IPFORWARD_V6 "/proc/sys/net/ipv6/conf/all/forwarding"
83 /* Redirect proc entry */
84 #define PROC_IF_REDIRECT "/proc/sys/net/ipv4/conf/%s/send_redirects"
85 #define PROC_ALL_REDIRECT "/proc/sys/net/ipv4/conf/all/send_redirects"
87 /* IP spoof proc entry */
88 #define PROC_IF_SPOOF "/proc/sys/net/ipv4/conf/%s/rp_filter"
89 #define PROC_ALL_SPOOF "/proc/sys/net/ipv4/conf/all/rp_filter"
92 /* list of IPv6 interfaces */
93 #define PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
96 *Wireless definitions for ioctl calls
97 *(from linux/wireless.h)
99 #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
100 #define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */
102 /* The original state of the IP forwarding proc entry */
103 static char orig_fwd_state;
104 static char orig_global_redirect_state;
105 static char orig_global_rp_filter;
106 static char orig_tunnel_rp_filter;
107 #if 0 // should not be necessary for IPv6 */
108 static char orig_tunnel6_rp_filter;
111 static int writeToProc(const char *file, char *old, char value) {
115 if ((fd = open(file, O_RDWR)) < 0) {
116 OLSR_WARN(LOG_INTERFACE, "Cannot open proc entry %s: %s (%d)\n", file, strerror(errno), errno);
120 if (read(fd, &rv, 1) != 1) {
121 OLSR_WARN(LOG_INTERFACE, "Cannot read proc entry %s: %s (%d)\n", file, strerror(errno), errno);
126 if (lseek(fd, SEEK_SET, 0) == -1) {
127 OLSR_WARN(LOG_INTERFACE, "Cannot rewind proc entry %s: %s (%d)\n", file, strerror(errno), errno);
131 if (write(fd, &value, 1) != 1) {
132 OLSR_WARN(LOG_INTERFACE, "Cannot write proc entry %s: %s (%d)\n", file, strerror(errno), errno);
137 if (close(fd) != 0) {
138 OLSR_WARN(LOG_INTERFACE, "Cannot close proc entry %s: %s (%d)\n", file, strerror(errno), errno);
145 OLSR_DEBUG(LOG_INTERFACE, "Writing '%c' (was %c) to %s", value, rv, file);
149 static bool is_at_least_linuxkernel_2_6_31(void) {
152 memset(&uts, 0, sizeof(uts));
154 OLSR_WARN(LOG_NETWORKING, "Cannot not read kernel version: %s (%d)\n", strerror(errno), errno);
158 if (strncmp(uts.release, "2.6.",4) != 0) {
161 return atoi(&uts.release[4]) >= 31;
165 * Setup global interface options (icmp redirect, ip forwarding, rp_filter)
166 * @return 1 on success 0 on failure
169 os_init_global_ifoptions(void) {
170 if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, &orig_fwd_state, '1')) {
171 OLSR_WARN(LOG_INTERFACE, "Warning, could not enable IP forwarding!\n"
172 "you should manually ensure that IP forwarding is enabled!\n\n");
173 // TODO olsr_startup_sleep(3);
176 if (olsr_cnf->smart_gw_active) {
177 char procfile[FILENAME_MAX];
179 /* Generate the procfile name */
180 if (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) {
181 snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
182 if (writeToProc(procfile, &orig_tunnel_rp_filter, '0')) {
183 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable the IP spoof filter for tunnel!\n"
184 "you should mannually ensure that IP spoof filtering is disabled!\n\n");
186 // TODO olsr_startup_sleep(3);
191 if (olsr_cnf->ip_version == AF_INET) {
192 if (writeToProc(PROC_ALL_REDIRECT, &orig_global_redirect_state, '0')) {
193 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable ICMP redirects!\n"
194 "you should manually ensure that ICMP redirects are disabled!\n\n");
196 // TODO olsr_startup_sleep(3);
199 /* check kernel version and disable global rp_filter */
200 if (is_at_least_linuxkernel_2_6_31()) {
201 if (writeToProc(PROC_ALL_SPOOF, &orig_global_rp_filter, '0')) {
202 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable global rp_filter (necessary for kernel 2.6.31 and higher!\n"
203 "you should manually ensure that rp_filter is disabled!\n\n");
205 // TODO olsr_startup_sleep(3);
214 *@return 1 on sucess 0 on failiure
217 net_os_set_ifoptions(const char *if_name, struct interface *iface)
219 char procfile[FILENAME_MAX];
220 if (olsr_cnf->ip_version == AF_INET6)
223 /* Generate the procfile name */
224 snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, if_name);
226 if (writeToProc(procfile, &iface->nic_state.redirect, '0')) {
227 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable ICMP redirects!\n"
228 "you should mannually ensure that ICMP redirects are disabled!\n\n");
229 // TODO olsr_startup_sleep(3);
233 /* Generate the procfile name */
234 snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, if_name);
236 if (writeToProc(procfile, &iface->nic_state.spoof, '0')) {
237 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable the IP spoof filter!\n"
238 "you should mannually ensure that IP spoof filtering is disabled!\n\n");
240 // TODO olsr_startup_sleep(3);
246 void net_os_restore_ifoption(struct interface *ifs) {
247 char procfile[FILENAME_MAX];
250 snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, ifs->int_name);
251 if (writeToProc(procfile, NULL, ifs->nic_state.redirect)) {
252 OLSR_WARN(LOG_INTERFACE, "Could not restore icmp_redirect for interface %s\n", ifs->int_name);
256 sprintf(procfile, PROC_IF_SPOOF, ifs->int_name);
257 if (writeToProc(procfile, NULL, ifs->nic_state.spoof)) {
258 OLSR_WARN(LOG_INTERFACE, "Could not restore rp_filter for interface %s\n", ifs->int_name);
262 *Resets the spoof filter and ICMP redirect settings
265 os_cleanup_global_ifoptions(void)
267 char procfile[FILENAME_MAX];
268 OLSR_DEBUG(LOG_INTERFACE, "Restoring network state\n");
270 /* Restore IP forwarding to "off" */
271 if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, NULL, orig_fwd_state)) {
272 OLSR_WARN(LOG_INTERFACE, "Could not restore ip_forward settings\n");
275 if (olsr_cnf->smart_gw_active && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)) {
276 /* Generate the procfile name */
277 snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
278 if (writeToProc(procfile, NULL, orig_tunnel_rp_filter)) {
279 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not restore the IP spoof filter for tunnel!\n");
283 if (olsr_cnf->ip_version == AF_INET) {
284 /* Restore global ICMP redirect setting */
285 if (writeToProc(PROC_ALL_REDIRECT, NULL, orig_global_redirect_state)) {
286 OLSR_WARN(LOG_INTERFACE, "Could not restore global icmp_redirect setting\n");
289 /* Restore global rp_filter setting for linux 2.6.31+ */
290 if (is_at_least_linuxkernel_2_6_31()) {
291 if (writeToProc(PROC_ALL_SPOOF, NULL, orig_global_rp_filter)) {
292 OLSR_WARN(LOG_INTERFACE, "Could not restore global rp_filter setting\n");
299 *Bind a socket to a device
301 *@param sock the socket to bind
302 *@param dev_name name of the device
304 *@return negative if error
308 bind_socket_to_device(int sock, const char *dev_name)
311 *Bind to device using the SO_BINDTODEVICE flag
313 OLSR_DEBUG(LOG_NETWORKING, "Binding socket %d to device %s\n", sock, dev_name);
314 return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
319 *Creates a nonblocking broadcast socket.
320 *@param sa sockaddr struct. Used for bind(2).
321 *@return the FD of the socket or -1 on error.
324 os_getsocket4(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto)
326 struct sockaddr_in sin4;
328 int sock = socket(AF_INET, SOCK_DGRAM, 0);
330 OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
331 olsr_exit(EXIT_FAILURE);
336 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
337 OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
339 olsr_exit(EXIT_FAILURE);
343 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
344 OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for OLSR PDUs (%s)\n", strerror(errno));
346 olsr_exit(EXIT_FAILURE);
350 for (on = bufspace;; on -= 1024) {
351 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
352 OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
355 if (on <= 8 * 1024) {
356 OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
364 * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
368 if (bind_socket_to_device(sock, if_name) < 0) {
369 OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno);
371 olsr_exit(EXIT_FAILURE);
374 if (bindto == NULL) {
375 memset(&sin4, 0, sizeof(sin4));
376 sin4.sin_family = AF_INET;
377 sin4.sin_port = htons(port);
378 sin4.sin_addr.s_addr = 0;
379 bindto = (union olsr_sockaddr *)&sin4;
381 if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) {
382 OLSR_ERROR(LOG_NETWORKING, "Coult not bind socket for OLSR PDUs to port (%s)\n", strerror(errno));
384 olsr_exit(EXIT_FAILURE);
387 os_socket_set_nonblocking(sock);
393 *Creates a nonblocking IPv6 socket
394 *@param sin sockaddr_in6 struct. Used for bind(2).
395 *@return the FD of the socket or -1 on error.
398 os_getsocket6(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto)
400 struct sockaddr_in6 sin6;
402 int sock = socket(AF_INET6, SOCK_DGRAM, 0);
404 OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
405 olsr_exit(EXIT_FAILURE);
409 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
410 OLSR_WARN(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to ipv6 only (%s)\n", strerror(errno));
415 //#ifdef SO_BROADCAST
417 if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof(on)) < 0)
419 perror("setsockopt");
420 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
429 for (on = bufspace;; on -= 1024) {
430 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
431 OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
434 if (on <= 8 * 1024) {
435 OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
443 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
444 OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for socket for OLSR PDUs (%s)\n", strerror(errno));
446 olsr_exit(EXIT_FAILURE);
450 * we are abusing "on" here. The value is 1 which is our intended
453 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) {
454 OLSR_ERROR(LOG_NETWORKING, "Cannot set multicast hops to 1 for socket for OLSR PDUs (%s)\n", strerror(errno));
456 olsr_exit(EXIT_FAILURE);
461 * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
465 if (bind_socket_to_device(sock, if_name) < 0) {
466 OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno);
468 olsr_exit(EXIT_FAILURE);
471 if (bindto == NULL) {
472 memset(&sin6, 0, sizeof(sin6));
473 sin6.sin6_family = AF_INET6;
474 sin6.sin6_port = htons(port);
475 bindto = (union olsr_sockaddr *)&sin6;
477 if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) {
478 OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs (%s)\n", strerror(errno));
480 olsr_exit(EXIT_FAILURE);
483 os_socket_set_nonblocking(sock);
489 join_mcast(struct interface *ifs, int sock)
491 /* See linux/in6.h */
492 #if !defined REMOVE_LOG_INFO
493 struct ipaddr_str buf;
495 struct ipv6_mreq mcastreq;
497 if (olsr_cnf->ip_version == AF_INET) {
500 mcastreq.ipv6mr_multiaddr = ifs->int_multicast.v6.sin6_addr;
501 mcastreq.ipv6mr_interface = ifs->if_index;
503 OLSR_INFO(LOG_NETWORKING, "Interface %s joining multicast %s\n", ifs->int_name,
504 olsr_sockaddr_to_string(&buf, &ifs->int_multicast));
506 if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
508 OLSR_WARN(LOG_NETWORKING, "Cannot join multicast group (%s)\n", strerror(errno));
513 #ifdef IPV6_JOIN_GROUP
514 /* Join reciever group */
515 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
518 /* Join reciever group */
519 if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
523 perror("Join multicast send");
527 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface))
529 OLSR_WARN(LOG_NETWORKING, "Cannot set multicast interface (%s)\n", strerror(errno));
537 os_socket_set_olsr_options(struct interface * ifs, int sock) {
539 int data = IPTOS_PREC(olsr_cnf->tos);
540 if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (char *)&data, sizeof(data)) < 0) {
541 OLSR_WARN(LOG_INTERFACE, "setsockopt(SO_PRIORITY) error %s", strerror(errno));
543 data = IPTOS_TOS(olsr_cnf->tos);
544 if (setsockopt(sock, SOL_IP, IP_TOS, (char *)&data, sizeof(data)) < 0) {
545 OLSR_WARN(LOG_INTERFACE, "setsockopt(IP_TOS) error %s", strerror(errno));
548 join_mcast(ifs, sock);
552 *From net-tools lib/interface.c
556 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int addrtype6)
559 FILE *f = fopen(_PATH_PROCNET_IFINET6, "r");
561 char devname[IFNAMSIZ];
563 int plen, scope, dad_status, if_idx;
565 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
566 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
567 addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
568 if (strcmp(devname, ifname) == 0) {
570 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
571 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
573 if (addrtype6 == OLSR_IP6T_SITELOCAL && scope == IPV6_ADDR_SITELOCAL)
575 else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && scope == IPV6_ADDR_GLOBAL)
577 else if (addrtype6 == OLSR_IP6T_GLOBAL && scope == IPV6_ADDR_GLOBAL)
582 if (addr6p[0][0] == 'F' || addr6p[0][0] == 'f') {
583 if (addr6p[0][1] == 'C' || addr6p[0][1] == 'c' || addr6p[0][1] == 'D' || addr6p[0][1] == 'd')
586 if (addrtype6 == OLSR_IP6T_SITELOCAL)
588 else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && found)
590 else if (addrtype6 == OLSR_IP6T_GLOBAL && !found)
597 inet_pton(AF_INET6, addr6, &saddr6->sin6_addr);
610 * Wrapper for sendto(2)
613 os_sendto(int s, const void *buf, size_t len, int flags, const union olsr_sockaddr *sockaddr)
615 return sendto(s, buf, len, flags, &sockaddr->std, sizeof(*sockaddr));
619 * Wrapper for recvfrom(2)
623 os_recvfrom(int s, void *buf, size_t len, int flags,
624 union olsr_sockaddr *sockaddr, socklen_t *socklen)
626 return recvfrom(s, buf, len, flags, &sockaddr->std, socklen);
630 * Wrapper for select(2)
634 os_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
636 return select(nfds, readfds, writefds, exceptfds, timeout);
639 bool os_is_interface_up(const char * dev)
643 memset(&ifr, 0, sizeof(ifr));
644 strscpy(ifr.ifr_name, dev, IFNAMSIZ);
646 if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
647 OLSR_WARN(LOG_INTERFACE, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
648 dev, strerror(errno), errno);
651 return (ifr.ifr_flags & IFF_UP) != 0;
654 int os_interface_set_state(const char *dev, bool up) {
658 memset(&ifr, 0, sizeof(ifr));
659 strscpy(ifr.ifr_name, dev, IFNAMSIZ);
661 if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
662 OLSR_WARN(LOG_INTERFACE, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
663 dev, strerror(errno), errno);
667 oldflags = ifr.ifr_flags;
669 ifr.ifr_flags |= IFF_UP;
672 ifr.ifr_flags &= ~IFF_UP;
675 if (oldflags == ifr.ifr_flags) {
676 /* interface is already up/down */
680 if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
681 OLSR_WARN(LOG_INTERFACE, "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
682 up ? "up" : "down", dev, strerror(errno), errno);
691 * indent-tabs-mode: nil