Source IP patch
authorHenning Rogge <hrogge@googlemail.com>
Sat, 7 Mar 2009 19:41:55 +0000 (20:41 +0100)
committerHenning Rogge <hrogge@googlemail.com>
Sat, 7 Mar 2009 19:41:55 +0000 (20:41 +0100)
src/bsd/kernel_routes.c
src/kernel_routes.h
src/linux/kernel_routes.c
src/main.c
src/olsr_cfg.c
src/olsr_cfg.h
src/win32/kernel_routes.c

index 629f536..d71b5ee 100644 (file)
@@ -398,6 +398,14 @@ olsr_kernel_del_route(const struct rt_entry *rt, int ip_version)
   return AF_INET == ip_version ? add_del_route(rt, 0) : add_del_route6(rt, 0);
 }
 
+int olsr_create_lo_interface(union olsr_ip_addr *ip  __attribute__((unused))) {
+  return 0;
+}
+
+int olsr_delete_lo_interface(union olsr_ip_addr *ip   __attribute__((unused))) {
+  return 0;
+}
+
 /*
  * Local Variables:
  * c-basic-offset: 2
index a2d7197..972e4a0 100644 (file)
@@ -50,6 +50,9 @@ olsr_kernel_add_route(const struct rt_entry *, int);
 int
 olsr_kernel_del_route(const struct rt_entry *, int);
 
+int olsr_create_lo_interface(union olsr_ip_addr *ip);
+int olsr_delete_lo_interface(union olsr_ip_addr *ip);
+
 #endif
 
 /*
index 715f95f..bf4a716 100644 (file)
@@ -51,20 +51,24 @@ struct olsr_rtreq {
   char            buf[512];
 };
 
-static void olsr_netlink_addreq(struct olsr_rtreq *req, int type, const void *data, int len)
+struct olsr_ipadd_req {
+  struct nlmsghdr   n;
+  struct ifaddrmsg  ifa;
+  char        buf[256];
+};
+
+
+static void olsr_netlink_addreq(struct nlmsghdr *n, size_t reqSize, int type, const void *data, int len)
 {
-  struct rtattr *rta = (struct rtattr*)(((char*)req) + NLMSG_ALIGN(req->n.nlmsg_len));
-  req->n.nlmsg_len = NLMSG_ALIGN(req->n.nlmsg_len) + RTA_LENGTH(len);
-  assert(req->n.nlmsg_len < sizeof(*req));
+  struct rtattr *rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
+  n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_LENGTH(len);
+  assert(n->nlmsg_len < reqSize);
   rta->rta_type = type;
   rta->rta_len = RTA_LENGTH(len);
   memcpy(RTA_DATA(rta), data, len);
 }
 
-static int olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
-{
-  int ret = 0;
-  struct olsr_rtreq req;
+static int olsr_netlink_send(struct nlmsghdr *n, char *buf, size_t bufSize) {
   struct iovec iov;
   struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
   struct msghdr msg = {
@@ -76,6 +80,42 @@ static int olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t
     .msg_controllen = 0,
     .msg_flags = 0
   };
+  int ret;
+
+  iov.iov_base = n;
+  iov.iov_len = n->nlmsg_len;
+  ret = sendmsg(olsr_cnf->rts_linux, &msg, 0);
+  if (0 <= ret) {
+    iov.iov_base = buf;
+    iov.iov_len = bufSize;
+    ret = recvmsg(olsr_cnf->rts_linux, &msg, 0);
+    if (0 < ret) {
+      struct nlmsghdr* h = (struct nlmsghdr*)buf;
+      while (NLMSG_OK(h, (unsigned int)ret)) {
+        if (NLMSG_DONE == h->nlmsg_type) {
+          break;
+        }
+        if (NLMSG_ERROR == h->nlmsg_type) {
+          if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
+            const struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
+            errno = -l_err->error;
+            if (0 != errno) {
+              ret = -1;
+            }
+          }
+          break;
+        }
+        h = NLMSG_NEXT(h, ret);
+      }
+    }
+  }
+  return ret;
+}
+
+static int olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
+{
+  int ret = 0;
+  struct olsr_rtreq req;
   uint32_t metric = FIBM_FLAT != olsr_cnf->fib_metric
     ? (RTM_NEWROUTE == cmd
        ? rt->rt_best->rtp_metric.hops
@@ -96,24 +136,32 @@ static int olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t
   req.r.rtm_type = RTN_UNICAST;
   req.r.rtm_dst_len = rt->rt_dst.prefix_len;
 
+  /* source ip here is based on now static olsr_cnf->main_addr in this olsr-0.5.6-r4, should be based on orignator-id in newer olsrds*/
+  if (AF_INET == family) {
+    olsr_netlink_addreq(&req.n, sizeof(req), RTA_PREFSRC, &olsr_cnf->router_id.v4, sizeof(olsr_cnf->router_id.v4));
+  }
+  else {
+    olsr_netlink_addreq(&req.n, sizeof(req), RTA_PREFSRC, &olsr_cnf->router_id.v6, sizeof(olsr_cnf->router_id.v6));
+  }
+
   if (NULL != nexthop->interface) {
     if (AF_INET == family) {
       if (!ip4equal(&rt->rt_dst.prefix.v4, &nexthop->gateway.v4)) {
-        olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
+        olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
       }
-      olsr_netlink_addreq(&req, RTA_DST, &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
+      olsr_netlink_addreq(&req.n, sizeof(req), RTA_DST, &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
     } else {
       if (!ip6equal(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6)) {
-        olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
+        olsr_netlink_addreq(&req.n, sizeof(req), RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
       }
-      olsr_netlink_addreq(&req, RTA_DST, &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
+      olsr_netlink_addreq(&req.n, sizeof(req), RTA_DST, &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
     }
     if (FIBM_APPROX != olsr_cnf->fib_metric || RTM_NEWROUTE == cmd) {
-      olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
+      olsr_netlink_addreq(&req.n, sizeof(req), RTA_PRIORITY, &metric, sizeof(metric));
     }
-    olsr_netlink_addreq(&req, RTA_OIF, &nexthop->interface->if_index,
+    olsr_netlink_addreq(&req.n, sizeof(req), RTA_OIF, &nexthop->interface->if_index,
                         sizeof(nexthop->interface->if_index));
   }
   else {
@@ -122,39 +170,13 @@ static int olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t
      */
     req.r.rtm_scope = RT_SCOPE_NOWHERE;
   }
-  iov.iov_base = &req.n;
-  iov.iov_len = req.n.nlmsg_len;
-  ret = sendmsg(olsr_cnf->rts_linux, &msg, 0);
-  if (0 <= ret) {
-    iov.iov_base = req.buf;
-    iov.iov_len = sizeof(req.buf);
-    ret = recvmsg(olsr_cnf->rts_linux, &msg, 0);
-    if (0 < ret) {
-      struct nlmsghdr* h = (struct nlmsghdr*)req.buf;
-      while (NLMSG_OK(h, (unsigned int)ret)) {
-        if (NLMSG_DONE == h->nlmsg_type) {
-         break;
-       }
-        if (NLMSG_ERROR == h->nlmsg_type) {
-          if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
-            const struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
-            errno = -l_err->error;
-            if (0 != errno) {
-             ret = -1;
-           }
-          }
-          break;
-        }
-        h = NLMSG_NEXT(h, ret);
-      }
-    }
-    if (0 <= ret && olsr_cnf->ipc_connections > 0) {
-      ipc_route_send_rtentry(&rt->rt_dst.prefix,
-                            &nexthop->gateway,
-                            metric,
-                            RTM_NEWROUTE == cmd,
-                            nexthop->interface->int_name);
-    }
+  ret = olsr_netlink_send(&req.n, req.buf, sizeof(req.buf));
+  if (0 <= ret && olsr_cnf->ipc_connections > 0) {
+    ipc_route_send_rtentry(&rt->rt_dst.prefix,
+         &nexthop->gateway,
+         metric,
+         RTM_NEWROUTE == cmd,
+         nexthop->interface->int_name);
   }
   return ret;
 }
@@ -232,6 +254,49 @@ olsr_kernel_del_route(const struct rt_entry *rt, int ip_version)
   return rslt;
 }
 
+
+int olsr_create_lo_interface(union olsr_ip_addr *ip) {
+  struct olsr_ipadd_req req;
+  static char  l[] = "lo:olsr";
+
+  memset(&req, 0, sizeof(req));
+
+  req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+  req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE;
+  req.n.nlmsg_type = RTM_NEWADDR;
+  req.ifa.ifa_family = olsr_cnf->ip_version;
+
+  olsr_netlink_addreq(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
+  olsr_netlink_addreq(&req.n, sizeof(req), IFA_LOCAL, ip, olsr_cnf->ipsize);
+
+  req.ifa.ifa_prefixlen = olsr_cnf->ipsize * 8;
+
+  req.ifa.ifa_index = if_nametoindex("lo");
+
+  return olsr_netlink_send(&req.n, req.buf, sizeof(req.buf));
+}
+
+int olsr_delete_lo_interface(union olsr_ip_addr *ip) {
+  struct olsr_ipadd_req req;
+  static char  l[] = "lo:olsr";
+
+  memset(&req, 0, sizeof(req));
+
+  req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+  req.n.nlmsg_flags = NLM_F_REQUEST;
+  req.n.nlmsg_type = RTM_DELADDR;
+  req.ifa.ifa_family = olsr_cnf->ip_version;
+
+  olsr_netlink_addreq(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
+  olsr_netlink_addreq(&req.n, sizeof(req), IFA_LOCAL, ip, olsr_cnf->ipsize);
+
+  req.ifa.ifa_prefixlen = olsr_cnf->ipsize * 8;
+
+  req.ifa.ifa_index = if_nametoindex("lo");
+
+  return olsr_netlink_send(&req.n, req.buf, sizeof(req.buf));
+}
+
 /*
  * Local Variables:
  * c-basic-offset: 2
index 16edb19..25e2ea9 100644 (file)
@@ -63,6 +63,7 @@
 #include "common/string.h"
 #include "mid_set.h"
 #include "duplicate_set.h"
+#include "kernel_routes.h"
 
 #if defined linux
 #include <linux/types.h>
@@ -107,7 +108,7 @@ main(int argc, char *argv[])
   char conf_file_name[FILENAME_MAX];
   char parse_msg[FILENAME_MAX + 256];
   int exitcode = 0;
-#ifndef REMOVE_LOG_INFO
+#if !defined(REMOVE_LOG_INFO) || !defined(REMOVE_LOG_ERROR)
   struct ipaddr_str buf;
 #endif
 #ifdef WIN32
@@ -288,6 +289,12 @@ main(int argc, char *argv[])
     }
   }
 
+  /* Initializing lo:olsr if necessary */
+  if (olsr_cnf->source_ip_mode) {
+    if (olsr_create_lo_interface(&olsr_cnf->router_id) <= 0) {
+      OLSR_ERROR(LOG_NETWORKING, "Cannot create lo:olsr interface for ip '%s'\n", olsr_ip_to_string(&buf, &olsr_cnf->router_id));
+    }
+  }
   /* Initializing networkinterfaces */
   if (!ifinit()) {
     if (olsr_cnf->allow_no_interfaces) {
@@ -503,6 +510,11 @@ olsr_shutdown(void)
     remove_interface(&iface->interf);
   }
 
+  /* delete lo:olsr if neccesarry */
+  if (olsr_cnf->source_ip_mode) {
+    olsr_delete_lo_interface(&olsr_cnf->router_id);
+  }
+
   /* Reset network settings */
   restore_settings(olsr_cnf->ip_version);
 
index 2ce6998..3b1d6ac 100644 (file)
@@ -1019,6 +1019,10 @@ parse_cfg_option(const int optint, char *argstr, const int line, struct olsr_con
   case 'L':                    /* Log (string) */
     return parse_cfg_log(argstr, rcfg, rmsg);
     break;
+  case 's':                    /* SourceIpMode (string) */
+    rcfg->source_ip_mode = (0 == strcmp("yes", argstr)) ? 1 : 0;
+    PARSER_DEBUG_PRINTF("Source IP mode %s\n", rcfg->source_ip_mode ? "enabled" : "disabled");
+    break;
   case 'o':                    /* Originator Address (ip) */
     if (inet_pton(AF_INET, argstr, &rcfg->router_id) <= 0) {
       sprintf(rmsg, "Failed converting IP address %s for originator address\n", argstr);
@@ -1124,6 +1128,8 @@ olsr_parse_cfg(int argc, char *argv[], const char *file, char *rmsg, struct olsr
     {"TosValue",                 required_argument, 0, 'Z'}, /* (i) */
     {"Willingness",              required_argument, 0, 'w'}, /* (i) */
     {"RouterId",                 required_argument, 0, 'o'}, /* (ip) */
+    {"SourceIpMode",             required_argument, 0, 's'}, /* (yes/no) */
+
     {"UseHysteresis",            required_argument, 0,  0 }, /* ignored */
     {"HystScaling",              required_argument, 0,  0 }, /* ignored */
     {"HystThrHigh",              required_argument, 0,  0 }, /* ignored */
@@ -1323,6 +1329,12 @@ olsr_sanity_check_cfg(struct olsr_config *cfg)
     return -1;
   }
 
+  /* Source ip mode need fixed router id */
+  if (0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)) && cfg->source_ip_mode) {
+    fprintf(stderr, "You cannot use source ip routing without setting a fixed router id\n");
+    return -1;
+  }
+
   if (in == NULL) {
     fprintf(stderr, "No interfaces configured!\n");
     return -1;
@@ -1514,6 +1526,7 @@ olsr_get_default_cfg(void)
 
   assert(cfg->system_tick_divider == 0);
   assert(0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)));
+  assert(0 == cfg->source_ip_mode);
   cfg->will_int = 10 * HELLO_INTERVAL;
   cfg->exit_value = EXIT_SUCCESS;
 
index b037ba0..b3e2844 100644 (file)
@@ -182,6 +182,7 @@ struct olsr_config {
   unsigned char fixed_origaddr:1;      /* Use a fixed originator addr == Node ID? */
   unsigned char disp_packets_in:1;     /* Display incoming packets? */
   unsigned char disp_packets_out:1;    /* Display outgoing packets? */
+  unsigned char source_ip_mode:1;      /* Run OLSR routing in sourceip mode */
 
   uint16_t tos;                        /* IP Type of Service Byte */
   uint8_t rtproto;                     /* Policy routing proto, 0 == operating sys default */
index f1004e7..34f0f3e 100644 (file)
@@ -201,6 +201,14 @@ int olsr_kernel_del_route(const struct rt_entry *rt, int ip_version)
   return 0;
 }
 
+int olsr_create_lo_interface(union olsr_ip_addr *ip  __attribute__((unused))) {
+  return 0;
+}
+
+int olsr_delete_lo_interface(union olsr_ip_addr *ip   __attribute__((unused))) {
+  return 0;
+}
+
 /*
  * Local Variables:
  * c-basic-offset: 2