Add the DirectOnly option.
[oweals/tinc.git] / src / route.c
index c04b0ad757ebc46d34698e3d8a8e0b6853050f5a..4e7f7e585db410c41f733a582aae7c2540064e43 100644 (file)
@@ -1,7 +1,7 @@
 /*
     route.c -- routing
     Copyright (C) 2000-2005 Ivo Timmermans,
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -33,6 +33,8 @@
 #include "utils.h"
 
 rmode_t routing_mode = RMODE_ROUTER;
+fmode_t forwarding_mode = FMODE_INTERNAL;
+bool directonly = false;
 bool priorityinheritance = false;
 int macexpire = 600;
 bool overwrite_mac = false;
@@ -94,9 +96,13 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
 }
 
 static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) {
-       if(!via || via == myself || !(via->options & OPTION_CLAMP_MSS))
+       if(!source || !via || !(via->options & OPTION_CLAMP_MSS))
                return;
 
+       uint16_t mtu = source->mtu;
+       if(via != myself && via->mtu < mtu)
+               mtu = via->mtu;
+
        /* Find TCP header */
        int start = 0;
        uint16_t type = packet->data[12] << 8 | packet->data[13];
@@ -140,7 +146,7 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
 
                /* Found it */
                uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i];
-               uint16_t newmss = via->mtu - start - 20;
+               uint16_t newmss = mtu - start - 20;
                uint16_t csum = packet->data[start + 16] << 8 | packet->data[start + 17];
 
                if(oldmss <= newmss)
@@ -188,6 +194,7 @@ static void learn_mac(mac_t *address) {
                subnet->net.mac.address = *address;
                subnet->weight = 10;
                subnet_add(myself, subnet);
+               subnet_update(myself, subnet, true);
 
                /* And tell all other tinc daemons it's our MAC */
 
@@ -223,6 +230,7 @@ void age_subnets(void) {
                                        send_del_subnet(c, s);
                        }
 
+                       subnet_update(myself, s, false);
                        subnet_del(myself, s);
                }
        }
@@ -377,13 +385,19 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
        }
 
        if(!subnet->owner->status.reachable)
-               route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
+               return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
+
+       if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
+               return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO);
 
        if(priorityinheritance)
                packet->priority = packet->data[15];
 
        via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
        
+       if(directonly && subnet->owner != via)
+               return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO);
+
        if(via && packet->len > max(via->mtu, 590) && via != myself) {
                ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
                if(packet->data[20] & 0x40) {
@@ -525,10 +539,16 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
        }
 
        if(!subnet->owner->status.reachable)
-               route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
+               return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
+
+       if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
+               return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
 
        via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
        
+       if(directonly && subnet->owner != via)
+               return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
+
        if(via && packet->len > max(via->mtu, 1294) && via != myself) {
                ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
                packet->len = max(via->mtu, 1294);
@@ -790,9 +810,15 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
                return;
        }
 
+       if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
+               return;
+
        // Handle packets larger than PMTU
 
        node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
+
+       if(directonly && subnet->owner != via)
+               return;
        
        if(via && packet->len > via->mtu && via != myself) {
                ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
@@ -818,6 +844,11 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
 }
 
 void route(node_t *source, vpn_packet_t *packet) {
+       if(forwarding_mode == FMODE_KERNEL) {
+               send_packet(myself, packet);
+               return;
+       }
+
        if(!checklength(source, packet, ether_size))
                return;