Merge branch 'master' into 1.1
Conflicts: NEWS README configure.in have.h src/conf.c src/conf.h src/net.c src/net_packet.c src/protocol_key.c src/protocol_subnet.c src/route.c src/tincd.c
This commit is contained in:
commit
103543aa2c
27 changed files with 694 additions and 237 deletions
123
src/route.c
123
src/route.c
|
|
@ -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;
|
||||
|
|
@ -48,6 +50,7 @@ static const size_t ip6_size = sizeof(struct ip6_hdr);
|
|||
static const size_t icmp6_size = sizeof(struct icmp6_hdr);
|
||||
static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
|
||||
static const size_t opt_size = sizeof(struct nd_opt_hdr);
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static struct event age_subnets_event;
|
||||
|
||||
|
|
@ -95,6 +98,78 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) {
|
||||
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];
|
||||
|
||||
if(type == ETH_P_IP && packet->data[23] == 6)
|
||||
start = 14 + (packet->data[14] & 0xf) * 4;
|
||||
else if(type == ETH_P_IPV6 && packet->data[20] == 6)
|
||||
start = 14 + 40;
|
||||
|
||||
if(!start || packet->len <= start + 20)
|
||||
return;
|
||||
|
||||
/* Use data offset field to calculate length of options field */
|
||||
int len = ((packet->data[start + 12] >> 4) - 5) * 4;
|
||||
|
||||
if(packet->len < start + 20 + len)
|
||||
return;
|
||||
|
||||
/* Search for MSS option header */
|
||||
for(int i = 0; i < len;) {
|
||||
if(packet->data[start + 20 + i] == 0)
|
||||
break;
|
||||
|
||||
if(packet->data[start + 20 + i] == 1) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(i > len - 2 || i > len - packet->data[start + 21 + i])
|
||||
break;
|
||||
|
||||
if(packet->data[start + 20 + i] != 2) {
|
||||
if(packet->data[start + 21 + i] < 2)
|
||||
break;
|
||||
i += packet->data[start + 21 + i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if(packet->data[start + 21] != 4)
|
||||
break;
|
||||
|
||||
/* Found it */
|
||||
uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i];
|
||||
uint16_t newmss = mtu - start - 20;
|
||||
uint16_t csum = packet->data[start + 16] << 8 | packet->data[start + 17];
|
||||
|
||||
if(oldmss <= newmss)
|
||||
break;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss);
|
||||
|
||||
/* Update the MSS value and the checksum */
|
||||
packet->data[start + 22 + i] = newmss >> 8;
|
||||
packet->data[start + 23 + i] = newmss & 0xff;
|
||||
csum ^= 0xffff;
|
||||
csum -= oldmss;
|
||||
csum += newmss;
|
||||
csum ^= 0xffff;
|
||||
packet->data[start + 16] = csum >> 8;
|
||||
packet->data[start + 17] = csum & 0xff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void swap_mac_addresses(vpn_packet_t *packet) {
|
||||
mac_t tmp;
|
||||
memcpy(&tmp, &packet->data[0], sizeof tmp);
|
||||
|
|
@ -156,6 +231,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 */
|
||||
|
||||
|
|
@ -323,17 +399,23 @@ 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(via && packet->len > via->mtu && via != myself) {
|
||||
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) {
|
||||
packet->len = via->mtu;
|
||||
packet->len = max(via->mtu, 590);
|
||||
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
|
||||
} else {
|
||||
fragment_ipv4_packet(via, packet);
|
||||
|
|
@ -342,6 +424,8 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
return;
|
||||
}
|
||||
|
||||
clamp_mss(source, via, packet);
|
||||
|
||||
send_packet(subnet->owner, packet);
|
||||
}
|
||||
|
||||
|
|
@ -469,17 +553,25 @@ 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(via && packet->len > via->mtu && via != myself) {
|
||||
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 = via->mtu;
|
||||
packet->len = max(via->mtu, 1294);
|
||||
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
clamp_mss(source, via, packet);
|
||||
|
||||
send_packet(subnet->owner, packet);
|
||||
}
|
||||
|
||||
|
|
@ -732,14 +824,20 @@ 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);
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
if(type == ETH_P_IP) {
|
||||
if(type == ETH_P_IP && packet->len > 590) {
|
||||
if(packet->data[20] & 0x40) {
|
||||
packet->len = via->mtu;
|
||||
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
|
||||
|
|
@ -747,17 +845,24 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
fragment_ipv4_packet(via, packet);
|
||||
}
|
||||
return;
|
||||
} else if(type == ETH_P_IPV6) {
|
||||
} else if(type == ETH_P_IPV6 && packet->len > 1294) {
|
||||
packet->len = via->mtu;
|
||||
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
clamp_mss(source, via, packet);
|
||||
|
||||
send_packet(subnet->owner, packet);
|
||||
}
|
||||
|
||||
void route(node_t *source, vpn_packet_t *packet) {
|
||||
if(forwarding_mode == FMODE_KERNEL && source != myself) {
|
||||
send_packet(myself, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!checklength(source, packet, ether_size))
|
||||
return;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue