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>
67 #define IPV6_ADDR_LOOPBACK 0x0010U
68 #define IPV6_ADDR_LINKLOCAL 0x0020U
69 #define IPV6_ADDR_SITELOCAL 0x0040U
72 #define PROC_IPFORWARD_V4 "/proc/sys/net/ipv4/ip_forward"
73 #define PROC_IPFORWARD_V6 "/proc/sys/net/ipv6/conf/all/forwarding"
75 /* Redirect proc entry */
76 #define PROC_IF_REDIRECT "/proc/sys/net/ipv4/conf/%s/send_redirects"
77 #define PROC_ALL_REDIRECT "/proc/sys/net/ipv4/conf/all/send_redirects"
79 /* IP spoof proc entry */
80 #define PROC_IF_SPOOF "/proc/sys/net/ipv4/conf/%s/rp_filter"
81 #define PROC_ALL_SPOOF "/proc/sys/net/ipv4/conf/all/rp_filter"
84 /* list of IPv6 interfaces */
85 #define PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
88 *Wireless definitions for ioctl calls
89 *(from linux/wireless.h)
91 #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
92 #define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */
94 /* The original state of the IP forwarding proc entry */
95 static char orig_fwd_state;
96 static char orig_global_redirect_state;
97 static char orig_global_rp_filter;
98 static char orig_tunnel_rp_filter;
99 #if 0 // should not be necessary for IPv6 */
100 static char orig_tunnel6_rp_filter;
103 static int writeToProc(const char *file, char *old, char value) {
107 if ((fd = open(file, O_RDWR)) < 0) {
108 OLSR_WARN(LOG_INTERFACE, "Cannot open proc entry %s: %s (%d)\n", file, strerror(errno), errno);
112 if (read(fd, &rv, 1) != 1) {
113 OLSR_WARN(LOG_INTERFACE, "Cannot read proc entry %s: %s (%d)\n", file, strerror(errno), errno);
118 if (lseek(fd, SEEK_SET, 0) == -1) {
119 OLSR_WARN(LOG_INTERFACE, "Cannot rewind proc entry %s: %s (%d)\n", file, strerror(errno), errno);
123 if (write(fd, &value, 1) != 1) {
124 OLSR_WARN(LOG_INTERFACE, "Cannot write proc entry %s: %s (%d)\n", file, strerror(errno), errno);
129 if (close(fd) != 0) {
130 OLSR_WARN(LOG_INTERFACE, "Cannot close proc entry %s: %s (%d)\n", file, strerror(errno), errno);
137 OLSR_DEBUG(LOG_INTERFACE, "Writing '%c' (was %c) to %s", value, rv, file);
141 static bool is_at_least_linuxkernel_2_6_31(void) {
144 memset(&uts, 0, sizeof(uts));
146 OLSR_WARN(LOG_NETWORKING, "Cannot not read kernel version: %s (%d)\n", strerror(errno), errno);
150 if (strncmp(uts.release, "2.6.",4) != 0) {
153 return atoi(&uts.release[4]) >= 31;
157 * Setup global interface options (icmp redirect, ip forwarding, rp_filter)
158 * @return 1 on success 0 on failure
161 os_init_global_ifoptions(void) {
162 if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, &orig_fwd_state, '1')) {
163 OLSR_WARN(LOG_INTERFACE, "Warning, could not enable IP forwarding!\n"
164 "you should manually ensure that IP forwarding is enabled!\n\n");
165 // TODO olsr_startup_sleep(3);
168 if (olsr_cnf->smart_gw_active) {
169 char procfile[FILENAME_MAX];
171 /* Generate the procfile name */
172 if (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) {
173 snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
174 if (writeToProc(procfile, &orig_tunnel_rp_filter, '0')) {
175 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable the IP spoof filter for tunnel!\n"
176 "you should mannually ensure that IP spoof filtering is disabled!\n\n");
178 // TODO olsr_startup_sleep(3);
183 if (olsr_cnf->ip_version == AF_INET) {
184 if (writeToProc(PROC_ALL_REDIRECT, &orig_global_redirect_state, '0')) {
185 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable ICMP redirects!\n"
186 "you should manually ensure that ICMP redirects are disabled!\n\n");
188 // TODO olsr_startup_sleep(3);
191 /* check kernel version and disable global rp_filter */
192 if (is_at_least_linuxkernel_2_6_31()) {
193 if (writeToProc(PROC_ALL_SPOOF, &orig_global_rp_filter, '0')) {
194 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable global rp_filter (necessary for kernel 2.6.31 and higher!\n"
195 "you should manually ensure that rp_filter is disabled!\n\n");
197 // TODO olsr_startup_sleep(3);
206 *@return 1 on sucess 0 on failiure
209 net_os_set_ifoptions(const char *if_name, struct interface *iface)
211 char procfile[FILENAME_MAX];
212 if (olsr_cnf->ip_version == AF_INET6)
215 /* Generate the procfile name */
216 snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, if_name);
218 if (writeToProc(procfile, &iface->nic_state.redirect, '0')) {
219 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable ICMP redirects!\n"
220 "you should mannually ensure that ICMP redirects are disabled!\n\n");
221 // TODO olsr_startup_sleep(3);
225 /* Generate the procfile name */
226 snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, if_name);
228 if (writeToProc(procfile, &iface->nic_state.spoof, '0')) {
229 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not disable the IP spoof filter!\n"
230 "you should mannually ensure that IP spoof filtering is disabled!\n\n");
232 // TODO olsr_startup_sleep(3);
238 void net_os_restore_ifoption(struct interface *ifs) {
239 char procfile[FILENAME_MAX];
242 snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, ifs->int_name);
243 if (writeToProc(procfile, NULL, ifs->nic_state.redirect)) {
244 OLSR_WARN(LOG_INTERFACE, "Could not restore icmp_redirect for interface %s\n", ifs->int_name);
248 sprintf(procfile, PROC_IF_SPOOF, ifs->int_name);
249 if (writeToProc(procfile, NULL, ifs->nic_state.spoof)) {
250 OLSR_WARN(LOG_INTERFACE, "Could not restore rp_filter for interface %s\n", ifs->int_name);
254 *Resets the spoof filter and ICMP redirect settings
257 os_cleanup_global_ifoptions(void)
259 char procfile[FILENAME_MAX];
260 OLSR_DEBUG(LOG_INTERFACE, "Restoring network state\n");
262 /* Restore IP forwarding to "off" */
263 if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, NULL, orig_fwd_state)) {
264 OLSR_WARN(LOG_INTERFACE, "Could not restore ip_forward settings\n");
267 if (olsr_cnf->smart_gw_active && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)) {
268 /* Generate the procfile name */
269 snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
270 if (writeToProc(procfile, NULL, orig_tunnel_rp_filter)) {
271 OLSR_WARN(LOG_INTERFACE, "WARNING! Could not restore the IP spoof filter for tunnel!\n");
275 if (olsr_cnf->ip_version == AF_INET) {
276 /* Restore global ICMP redirect setting */
277 if (writeToProc(PROC_ALL_REDIRECT, NULL, orig_global_redirect_state)) {
278 OLSR_WARN(LOG_INTERFACE, "Could not restore global icmp_redirect setting\n");
281 /* Restore global rp_filter setting for linux 2.6.31+ */
282 if (is_at_least_linuxkernel_2_6_31()) {
283 if (writeToProc(PROC_ALL_SPOOF, NULL, orig_global_rp_filter)) {
284 OLSR_WARN(LOG_INTERFACE, "Could not restore global rp_filter setting\n");
291 *Bind a socket to a device
293 *@param sock the socket to bind
294 *@param dev_name name of the device
296 *@return negative if error
300 bind_socket_to_device(int sock, const char *dev_name)
303 *Bind to device using the SO_BINDTODEVICE flag
305 OLSR_DEBUG(LOG_NETWORKING, "Binding socket %d to device %s\n", sock, dev_name);
306 return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
311 *Creates a nonblocking broadcast socket.
312 *@param sa sockaddr struct. Used for bind(2).
313 *@return the FD of the socket or -1 on error.
316 os_getsocket4(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto)
318 struct sockaddr_in sin4;
320 int sock = socket(AF_INET, SOCK_DGRAM, 0);
322 OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
323 olsr_exit(EXIT_FAILURE);
328 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
329 OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
331 olsr_exit(EXIT_FAILURE);
335 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
336 OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for OLSR PDUs (%s)\n", strerror(errno));
338 olsr_exit(EXIT_FAILURE);
342 for (on = bufspace;; on -= 1024) {
343 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
344 OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
347 if (on <= 8 * 1024) {
348 OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
356 * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
360 if (bind_socket_to_device(sock, if_name) < 0) {
361 OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno);
363 olsr_exit(EXIT_FAILURE);
366 if (bindto == NULL) {
367 memset(&sin4, 0, sizeof(sin4));
368 sin4.sin_family = AF_INET;
369 sin4.sin_port = htons(port);
370 sin4.sin_addr.s_addr = 0;
371 bindto = (union olsr_sockaddr *)&sin4;
373 if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) {
374 OLSR_ERROR(LOG_NETWORKING, "Coult not bind socket for OLSR PDUs to port (%s)\n", strerror(errno));
376 olsr_exit(EXIT_FAILURE);
379 os_socket_set_nonblocking(sock);
385 *Creates a nonblocking IPv6 socket
386 *@param sin sockaddr_in6 struct. Used for bind(2).
387 *@return the FD of the socket or -1 on error.
390 os_getsocket6(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto)
392 struct sockaddr_in6 sin6;
394 int sock = socket(AF_INET6, SOCK_DGRAM, 0);
396 OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
397 olsr_exit(EXIT_FAILURE);
401 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
402 OLSR_WARN(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to ipv6 only (%s)\n", strerror(errno));
407 //#ifdef SO_BROADCAST
409 if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof(on)) < 0)
411 perror("setsockopt");
412 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
421 for (on = bufspace;; on -= 1024) {
422 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
423 OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
426 if (on <= 8 * 1024) {
427 OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
435 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
436 OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for socket for OLSR PDUs (%s)\n", strerror(errno));
438 olsr_exit(EXIT_FAILURE);
442 * we are abusing "on" here. The value is 1 which is our intended
445 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) {
446 OLSR_ERROR(LOG_NETWORKING, "Cannot set multicast hops to 1 for socket for OLSR PDUs (%s)\n", strerror(errno));
448 olsr_exit(EXIT_FAILURE);
453 * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
457 if (bind_socket_to_device(sock, if_name) < 0) {
458 OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno);
460 olsr_exit(EXIT_FAILURE);
463 if (bindto == NULL) {
464 memset(&sin6, 0, sizeof(sin6));
465 sin6.sin6_family = AF_INET6;
466 sin6.sin6_port = htons(port);
467 bindto = (union olsr_sockaddr *)&sin6;
469 if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) {
470 OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs (%s)\n", strerror(errno));
472 olsr_exit(EXIT_FAILURE);
475 os_socket_set_nonblocking(sock);
481 join_mcast(struct interface *ifs, int sock)
483 /* See linux/in6.h */
484 #if !defined REMOVE_LOG_INFO
485 struct ipaddr_str buf;
487 struct ipv6_mreq mcastreq;
489 if (olsr_cnf->ip_version == AF_INET) {
492 mcastreq.ipv6mr_multiaddr = ifs->int_multicast.v6.sin6_addr;
493 mcastreq.ipv6mr_interface = ifs->if_index;
495 OLSR_INFO(LOG_NETWORKING, "Interface %s joining multicast %s\n", ifs->int_name,
496 olsr_sockaddr_to_string(&buf, &ifs->int_multicast));
498 if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
500 OLSR_WARN(LOG_NETWORKING, "Cannot join multicast group (%s)\n", strerror(errno));
505 #ifdef IPV6_JOIN_GROUP
506 /* Join reciever group */
507 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
510 /* Join reciever group */
511 if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
515 perror("Join multicast send");
519 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface))
521 OLSR_WARN(LOG_NETWORKING, "Cannot set multicast interface (%s)\n", strerror(errno));
529 os_socket_set_olsr_options(struct interface * ifs, int sock) {
531 int data = IPTOS_PREC(olsr_cnf->tos);
532 if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (char *)&data, sizeof(data)) < 0) {
533 OLSR_WARN(LOG_INTERFACE, "setsockopt(SO_PRIORITY) error %s", strerror(errno));
535 data = IPTOS_TOS(olsr_cnf->tos);
536 if (setsockopt(sock, SOL_IP, IP_TOS, (char *)&data, sizeof(data)) < 0) {
537 OLSR_WARN(LOG_INTERFACE, "setsockopt(IP_TOS) error %s", strerror(errno));
540 join_mcast(ifs, sock);
544 *From net-tools lib/interface.c
548 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int addrtype6)
551 FILE *f = fopen(_PATH_PROCNET_IFINET6, "r");
553 char devname[IFNAMSIZ];
555 int plen, scope, dad_status, if_idx;
557 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
558 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
559 addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
560 if (strcmp(devname, ifname) == 0) {
562 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
563 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
565 if (addrtype6 == OLSR_IP6T_SITELOCAL && scope == IPV6_ADDR_SITELOCAL)
567 else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && scope == IPV6_ADDR_GLOBAL)
569 else if (addrtype6 == OLSR_IP6T_GLOBAL && scope == IPV6_ADDR_GLOBAL)
574 if (addr6p[0][0] == 'F' || addr6p[0][0] == 'f') {
575 if (addr6p[0][1] == 'C' || addr6p[0][1] == 'c' || addr6p[0][1] == 'D' || addr6p[0][1] == 'd')
578 if (addrtype6 == OLSR_IP6T_SITELOCAL)
580 else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && found)
582 else if (addrtype6 == OLSR_IP6T_GLOBAL && !found)
589 inet_pton(AF_INET6, addr6, &saddr6->sin6_addr);
602 * Wrapper for sendto(2)
605 os_sendto(int s, const void *buf, size_t len, int flags, const union olsr_sockaddr *sockaddr)
607 return sendto(s, buf, len, flags, &sockaddr->std, sizeof(*sockaddr));
611 * Wrapper for recvfrom(2)
615 os_recvfrom(int s, void *buf, size_t len, int flags,
616 union olsr_sockaddr *sockaddr, socklen_t *socklen)
618 return recvfrom(s, buf, len, flags, &sockaddr->std, socklen);
622 * Wrapper for select(2)
626 os_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
628 return select(nfds, readfds, writefds, exceptfds, timeout);
631 bool os_is_interface_up(const char * dev)
635 memset(&ifr, 0, sizeof(ifr));
636 strscpy(ifr.ifr_name, dev, IFNAMSIZ);
638 if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
639 OLSR_WARN(LOG_INTERFACE, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
640 dev, strerror(errno), errno);
643 return (ifr.ifr_flags & IFF_UP) != 0;
646 int os_interface_set_state(const char *dev, bool up) {
650 memset(&ifr, 0, sizeof(ifr));
651 strscpy(ifr.ifr_name, dev, IFNAMSIZ);
653 if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
654 OLSR_WARN(LOG_INTERFACE, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
655 dev, strerror(errno), errno);
659 oldflags = ifr.ifr_flags;
661 ifr.ifr_flags |= IFF_UP;
664 ifr.ifr_flags &= ~IFF_UP;
667 if (oldflags == ifr.ifr_flags) {
668 /* interface is already up/down */
672 if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
673 OLSR_WARN(LOG_INTERFACE, "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
674 up ? "up" : "down", dev, strerror(errno), errno);
683 * indent-tabs-mode: nil