gateway ipip tunnel management (proof of concept)
authorMarkus Kittenberger <Markus.Kittenberger@gmx.at>
Fri, 8 Jan 2010 18:12:25 +0000 (19:12 +0100)
committerMarkus Kittenberger <Markus.Kittenberger@gmx.at>
Fri, 8 Jan 2010 18:12:25 +0000 (19:12 +0100)
src/kernel_routes.h
src/linux/kernel_routes.c
src/main.c
src/olsr_cfg.h

index 646a41f..dfdb7f9 100644 (file)
@@ -54,7 +54,7 @@ int olsr_ioctl_del_route(const struct rt_entry *);
 int olsr_ioctl_del_route6(const struct rt_entry *);
 
 #if LINUX_POLICY_ROUTING
-int olsr_netlink_rule(uint8_t, uint8_t, uint16_t);
+int olsr_netlink_rule(uint8_t, uint8_t, uint16_t, uint32_t, char*);
 
 #if LINUX_RTNETLINK_LISTEN
 int rtnetlink_register_socket(int);
index 9f36520..bdd21e4 100644 (file)
@@ -64,6 +64,14 @@ static int delete_all_inet_gws(void);
 #include <linux/types.h>
 #include <linux/rtnetlink.h>
 
+//ipip includes
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+
+
 extern struct rtnl_handle rth;
 
 struct olsr_rtreq {
@@ -173,8 +181,38 @@ void rtnetlink_read(int sock)
   }
 }
 
+//!!?? listen on our own tunlx interfaces aswell
+
 #endif /*linux_rtnetlink_listen*/
 
+/*create or change a ipip tunnel ipv4 only*/
+static int set_tunl(int cmd, unsigned long int ipv4)
+{
+  struct ifreq ifr;
+  int fd;
+  int err;
+  const char *name = "olsrtunl";
+  struct ip_tunnel_parm p;
+
+  p.iph.version = 4;
+  p.iph.ihl = 5;
+  p.iph.protocol=IPPROTO_IPIP; //IPPROTO_IPV6
+  p.iph.saddr=0x00000000;
+  p.iph.daddr=ipv4;
+
+  strncpy(p.name, name, IFNAMSIZ);
+
+  //specify existing interface name
+  if (cmd!=SIOCADDTUNNEL) strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+  ifr.ifr_ifru.ifru_data = (void *) &p;
+  fd = socket(AF_INET, SOCK_DGRAM, 0);//warning hardcoded AF_INET
+  err = ioctl(fd, cmd, &ifr);
+  if (err) perror("ioctl");
+  close(fd);
+  return err;
+}
+
 static void
 olsr_netlink_addreq(struct olsr_rtreq *req, int type, const void *data, int len)
 {
@@ -266,6 +304,11 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
 
     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
     olsr_netlink_addreq(&req, RTA_PRIORITY, &priority, sizeof(priority));
+    if (rt!=NULL) {
+      /*add interface name to rule*/
+      //olsr_netlink_addreq(&req, RTA_interface, &rt, sizeof(?));
+      //!!??printf("rule interface %s ignored!",(char*) rt);
+    } 
   }
   else {
     req.r.rtm_dst_len = rt->rt_dst.prefix_len;
@@ -279,7 +322,35 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
       req.r.rtm_scope = RT_SCOPE_LINK;
 
       /*add interface*/
-      if (flag == RT_NIIT) {
+      if ((&olsr_cnf->smart_gateway_active) && (rt->rt_dst.prefix_len == 0) && (&olsr_cnf->ipip_if_index==NULL))
+      {
+        //create tunnel
+        set_tunl(SIOCADDTUNNEL,rt->rt_best->rtp_originator.v4.s_addr);
+//!!?? currently it gets never deleted at shutdown, anyways reusing existing tunnel might be a safe approach if creating fails?
+        //find out iifindex (maybe it works even if above failed (old tunnel))
+        olsr_cnf->ipip_if_index=if_nametoindex("olsrtunl");
+      }
+
+      /*add interface*/
+      if ((&olsr_cnf->smart_gateway_active) && family != AF_INET)
+      {
+        printf("smart gateway not available for ipv6 currently");
+        return -1;
+      }
+      else if ((&olsr_cnf->smart_gateway_active) && (rt->rt_dst.prefix_len == 0) && (&olsr_cnf->ipip_if_index))
+      {
+        //change tunnel to new originator og potentially new gateway
+        if (olsr_cnf->ipip_remote_address != rt->rt_best->rtp_originator.v4.s_addr)
+        {
+          struct ipaddr_str buf;
+          printf("changing tunnel to %s",olsr_ip_to_string(&buf,&rt->rt_best->rtp_originator));
+          olsr_cnf->ipip_remote_address = rt->rt_best->rtp_originator.v4.s_addr;
+          set_tunl(SIOCCHGTUNNEL,olsr_cnf->ipip_remote_address);
+        }
+        //add interface
+        olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->niit_if_index, sizeof(&olsr_cnf->ipip_if_index));
+      }
+      else if (flag == RT_NIIT) {
         olsr_netlink_addreq(&req, RTA_OIF, &olsr_cnf->niit_if_index, sizeof(&olsr_cnf->niit_if_index));
       }
       else {
@@ -319,7 +390,8 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
      * or if delete-similar to make insertion of auto-generated route possible
      **/
     if (AF_INET == family) {
-      if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE) && 
+      if ( !( (rt->rt_dst.prefix_len == 0) && (olsr_cnf->smart_gateway_active) )
+           && ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE) && 
            ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) && (rt->rt_dst.prefix.v4.s_addr != nexthop->gateway.v4.s_addr) ) {
         olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
@@ -334,7 +406,8 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
         olsr_netlink_addreq(&req, RTA_DST, olsr_ipv6_to_ipv4(&rt->rt_dst.prefix, &ipv4_addr), sizeof(ipv4_addr.v4));
       }
       else {
-        if ( ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
+        if ( !( (rt->rt_dst.prefix_len == 0) && (olsr_cnf->smart_gateway_active) ) 
+            && ( flag != RT_AUTO_ADD_GATEWAY_ROUTE ) && (flag != RT_DELETE_SIMILAR_ROUTE ) && ( flag != RT_DELETE_SIMILAR_AUTO_ROUTE) 
             && (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) ) {
           olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
           req.r.rtm_scope = RT_SCOPE_UNIVERSE;
@@ -538,9 +611,10 @@ olsr_netlink_route_int(const struct rt_entry *rt, uint8_t family, uint8_t rttabl
 
 /* external wrapper function for above patched multi purpose rtnetlink function */
 int
-olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd)
+olsr_netlink_rule(uint8_t family, uint8_t rttable, uint16_t cmd, uint32_t priority, char* dev)
 {
-  return olsr_netlink_route_int(NULL, family, rttable, cmd, RT_ORIG_REQUEST);
+  printf("rule priority not supported");
+  return olsr_netlink_route_int(dev, family, rttable, cmd, RT_ORIG_REQUEST);
 }
 
 /* internal wrapper function for above patched function */
index 543f899..670e60a 100644 (file)
 #include <linux/types.h>
 #include <linux/rtnetlink.h>
 #include "kernel_routes.h"
+
+/*takes up the tunl0 interface*/
+static int olsr_tunl_up(void)
+{
+  printf("tunl0 up not supported");
+  return 0;
+}
 #endif
 
 #ifdef WIN32
@@ -467,12 +474,66 @@ int main(int argc, char *argv[]) {
   OLSR_PRINTF(1, "Main address: %s\n\n", olsr_ip_to_string(&buf, &olsr_cnf->main_addr));
 
 #if LINUX_POLICY_ROUTING
+  /*create smart-gateway-tunnel policy rules*/
+  if (olsr_cnf->smart_gateway_active) {
+
+    //todo take up tunl0 device or disable smartgateway
+    olsr_cnf->smart_gateway_active = olsr_tunl_up();
+
+    if (olsr_cnf->smart_gateway_active) {
+      struct olsr_if *cfg_if;
+
+      //need sanity checks for routintg tables
+
+      //question: if rttable_default unconfigured, determine one?
+      //yes use 112
+      //same with smartTable (113)
+
+      //further checks: tabledefault and smartgateway >0 < 253
+      //check if all tables are unique
+      //if not use other values for unconfigured Tables? or stop startup?
+
+      //future improvement: verify if no rule points to default and smartgateway table, with un unknown realm?
+      //nice as we can use realms to give traffic info about gateway tunnel, and ...
+
+      //question: do we set an defaulttable now, which persists if smartgateway is turned off, due to problems (or an rmmodding user) later?
+      //its easier to stick to tables and also better, 
+      //as users will always find the default route on same place.
+
+      //question: make priority of rules configureable (if configured for rttable this might means we shall create this rule (instead the 65535 dummy)
+      //question olsr did never create rules for a custom table (beside the dummy)
+      //should we start now doing so anyways? (beter not, use only new RTTableRule priority)
+
+      //as above ist neither finalized nor done in parser, we use hardcoded values
+      olsr_cnf->rttable_default=112;
+      olsr_cnf->rttable_smartgw=113;
+      if (olsr_cnf->rttable_default_rule==0) olsr_cnf->rttable_default_rule=65532;
+      if (olsr_cnf->rttable_smartgw_rule==0) olsr_cnf->rttable_smartgw_rule=olsr_cnf->rttable_default_rule+1;
+      if (olsr_cnf->rttable_backup_rule==0) olsr_cnf->rttable_backup_rule=olsr_cnf->rttable_smartgw_rule+1;
+
+      //!!??warning rule function ignores prio at the moment, so ordering counts (should be enough for a prrof of concept)
+
+      /*table with default routes for olsr interfaces*/
+      for (cfg_if = olsr_cnf->interfaces; cfg_if; cfg_if = cfg_if->next) {
+        olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default, RTM_NEWRULE, 
+                             olsr_cnf->rttable_default_rule, cfg_if->name);
+      }
+      /*table with route into tunnel (for all interfaces)*/
+      olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_smartgw, RTM_NEWRULE,
+                        olsr_cnf->rttable_smartgw_rule, NULL);
+      /*backup rule to default route table (if tunnel table gets empty)*/
+      olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable_default, RTM_NEWRULE, 
+                        olsr_cnf->rttable_backup_rule, NULL);
+    }
+  }
+
   /* Create rule for RtTable to resolve route insertion problems*/
   if ((olsr_cnf->rttable < 253) & (olsr_cnf->rttable > 0)) {
-    olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, RTM_NEWRULE);
+    olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, RTM_NEWRULE, (olsr_cnf->rttable_rule>0?olsr_cnf->rttable_rule:65535), NULL);
   }
 
   /* Create rtnetlink socket to listen on interface change events RTMGRP_LINK and RTMGRP_IPV4_ROUTE */
+  //todo listen on tunl0 events aswell
 
 #if LINUX_RTNETLINK_LISTEN
   rtnetlink_register_socket(RTMGRP_LINK);
@@ -646,9 +707,12 @@ static void olsr_shutdown(int signo __attribute__ ((unused)))
   close(olsr_cnf->ioctl_s);
 
 #if LINUX_POLICY_ROUTING
+//!!?? warning we do not delete any smartgw rules
+printf("smartgw rules where not deleted!");
+
   /* RtTable (linux only!!) */
   if ((olsr_cnf->rttable < 253) & (olsr_cnf->rttable > 0)) {
-    olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, RTM_DELRULE);
+    olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, RTM_DELRULE, 65535, NULL);
   }
 
   close(olsr_cnf->rtnl_s);
index f76a4b1..37a20bd 100644 (file)
@@ -212,8 +212,8 @@ struct olsrd_config {
   bool allow_no_interfaces;
   uint16_t tos;
   uint8_t rtproto;
-  uint8_t rttable;
-  uint8_t rttable_default;
+  uint8_t rttable, rttable_default, rttable_smartgw;
+  uint16_t rttable_rule, rttable_default_rule, rttable_smartgw_rule, rttable_backup_rule;
   uint8_t willingness;
   bool willingness_auto;
   int ipc_connections;
@@ -256,6 +256,8 @@ struct olsrd_config {
   bool smart_gateway_active;
   uint32_t smart_gateway_uplink;
   uint32_t smart_gateway_downlink;
+  uint32_t ipip_if_index;
+  unsigned long int ipip_remote_address;
 
   int ioctl_s;                         /* Socket used for ioctl calls */
 #if LINUX_POLICY_ROUTING