X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Froute.c;h=6cc2fc1c00a221904ef8822d91385ad4a0cddd2b;hp=e79fae51f130a9ce4f5182d789022b41ab74aeda;hb=5dde6461a321ee47b06e33f8203f2acf00a31a51;hpb=78fc59e994c764d072bf0045177f690a378d1308 diff --git a/src/route.c b/src/route.c index e79fae51..6cc2fc1c 100644 --- a/src/route.c +++ b/src/route.c @@ -13,11 +13,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id$ + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "system.h" @@ -53,8 +51,7 @@ static const size_t opt_size = sizeof(struct nd_opt_hdr); /* RFC 1071 */ -static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) -{ +static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { uint16_t *p = data; uint32_t checksum = prevsum ^ 0xFFFF; @@ -94,9 +91,15 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) { } else return true; } + +static void swap_mac_addresses(vpn_packet_t *packet) { + mac_t tmp; + memcpy(&tmp, &packet->data[0], sizeof tmp); + memcpy(&packet->data[0], &packet->data[6], sizeof tmp); + memcpy(&packet->data[6], &tmp, sizeof tmp); +} -static void learn_mac(mac_t *address) -{ +static void learn_mac(mac_t *address) { subnet_t *subnet; avl_node_t *node; connection_t *c; @@ -131,8 +134,7 @@ static void learn_mac(mac_t *address) subnet->expires = now + macexpire; } -void age_subnets(void) -{ +void age_subnets(void) { subnet_t *s; connection_t *c; avl_node_t *node, *next, *node2; @@ -160,44 +162,9 @@ void age_subnets(void) } } -static void route_mac(node_t *source, vpn_packet_t *packet) -{ - subnet_t *subnet; - mac_t dest; - - cp(); - - - /* Learn source address */ - - if(source == myself) { - mac_t src; - memcpy(&src, &packet->data[6], sizeof src); - learn_mac(&src); - } - - /* Lookup destination address */ - - memcpy(&dest, &packet->data[0], sizeof dest); - subnet = lookup_subnet_mac(&dest); - - if(!subnet) { - broadcast_packet(source, packet); - return; - } - - if(subnet->owner == source) { - ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname); - return; - } - - send_packet(subnet->owner, packet); -} - /* RFC 792 */ -static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) -{ +static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) { struct ip ip = {0}; struct icmp icmp = {0}; @@ -210,6 +177,10 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t cp(); + /* Swap Ethernet source and destination addresses */ + + swap_mac_addresses(packet); + /* Copy headers from packet into properly aligned structs on the stack */ memcpy(&ip, packet->data + ether_size, ip_size); @@ -318,8 +289,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) { } } -static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) -{ +static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { subnet_t *subnet; node_t *via; ipv4_t dest; @@ -369,8 +339,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) send_packet(subnet->owner, packet); } -static void route_ipv4(node_t *source, vpn_packet_t *packet) -{ +static void route_ipv4(node_t *source, vpn_packet_t *packet) { cp(); if(!checklength(source, packet, ether_size + ip_size)) @@ -388,8 +357,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) /* RFC 2463 */ -static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) -{ +static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) { struct ip6_hdr ip6; struct icmp6_hdr icmp6 = {0}; uint16_t checksum; @@ -406,6 +374,10 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t cp(); + /* Swap Ethernet source and destination addresses */ + + swap_mac_addresses(packet); + /* Copy headers from packet to structs on the stack */ memcpy(&ip6, packet->data + ether_size, ip6_size); @@ -465,8 +437,7 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t send_packet(source, packet); } -static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) -{ +static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { subnet_t *subnet; node_t *via; ipv6_t dest; @@ -514,8 +485,7 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) /* RFC 2461 */ -static void route_neighborsol(node_t *source, vpn_packet_t *packet) -{ +static void route_neighborsol(node_t *source, vpn_packet_t *packet) { struct ip6_hdr ip6; struct nd_neighbor_solicit ns; struct nd_opt_hdr opt; @@ -656,8 +626,7 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) send_packet(source, packet); } -static void route_ipv6(node_t *source, vpn_packet_t *packet) -{ +static void route_ipv6(node_t *source, vpn_packet_t *packet) { cp(); if(!checklength(source, packet, ether_size + ip6_size)) @@ -676,8 +645,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) /* RFC 826 */ -static void route_arp(node_t *source, vpn_packet_t *packet) -{ +static void route_arp(node_t *source, vpn_packet_t *packet) { struct ether_arp arp; subnet_t *subnet; struct in_addr addr; @@ -743,8 +711,63 @@ static void route_arp(node_t *source, vpn_packet_t *packet) send_packet(source, packet); } -void route(node_t *source, vpn_packet_t *packet) -{ +static void route_mac(node_t *source, vpn_packet_t *packet) { + subnet_t *subnet; + mac_t dest; + + cp(); + + + /* Learn source address */ + + if(source == myself) { + mac_t src; + memcpy(&src, &packet->data[6], sizeof src); + learn_mac(&src); + } + + /* Lookup destination address */ + + memcpy(&dest, &packet->data[0], sizeof dest); + subnet = lookup_subnet_mac(&dest); + + if(!subnet) { + broadcast_packet(source, packet); + return; + } + + if(subnet->owner == source) { + ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname); + return; + } + + // Handle packets larger than PMTU + + node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; + + 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(packet->data[20] & 0x40) { + packet->len = via->mtu; + route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); + } else { + fragment_ipv4_packet(via, packet); + } + return; + } else if(type == ETH_P_IPV6) { + packet->len = via->mtu; + route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0); + return; + } + } + + send_packet(subnet->owner, packet); +} + + +void route(node_t *source, vpn_packet_t *packet) { cp(); if(!checklength(source, packet, ether_size)) @@ -753,9 +776,8 @@ void route(node_t *source, vpn_packet_t *packet) switch (routing_mode) { case RMODE_ROUTER: { - uint16_t type; + uint16_t type = packet->data[12] << 8 | packet->data[13]; - type = ntohs(*((uint16_t *)(&packet->data[12]))); switch (type) { case ETH_P_ARP: route_arp(source, packet);