X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Froute.c;h=e874d8926dd1909179cf3bd354ebbb6fc61c5bb1;hp=cec35cae13b37b51fbeb5d7596bdafc00815aa73;hb=d917c8cb6b69475d568ccbe82389b9f2b3eb5e80;hpb=58f4b845b9a7d83739af77337f2ce263d8df7838 diff --git a/src/route.c b/src/route.c index cec35cae..e874d892 100644 --- a/src/route.c +++ b/src/route.c @@ -71,7 +71,7 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { checksum += *p++; len -= 2; } - + if(len) checksum += *(uint8_t *)p; @@ -85,7 +85,7 @@ static bool ratelimit(int frequency) { static time_t lasttime = 0; static int count = 0; time_t now = time(NULL); - + if(lasttime == now) { if(count >= frequency) return true; @@ -162,7 +162,7 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac if(oldmss <= newmss) break; - + logger(DEBUG_TRAFFIC, LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss); /* Update the MSS value and the checksum */ @@ -184,7 +184,7 @@ static void swap_mac_addresses(vpn_packet_t *packet) { memcpy(&packet->data[0], &packet->data[6], sizeof tmp); memcpy(&packet->data[6], &tmp, sizeof tmp); } - + static void age_subnets(int fd, short events, void *data) { bool left = false; time_t now = time(NULL); @@ -250,14 +250,14 @@ static void learn_mac(mac_t *address) { 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}; - + struct in_addr ip_src; struct in_addr ip_dst; uint32_t oldlen; if(ratelimit(3)) return; - + /* Swap Ethernet source and destination addresses */ swap_mac_addresses(packet); @@ -267,7 +267,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t memcpy(&ip, packet->data + ether_size, ip_size); /* Remember original source and destination */ - + ip_src = ip.ip_src; ip_dst = ip.ip_dst; @@ -278,13 +278,13 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t if(oldlen >= IP_MSS - ip_size - icmp_size) oldlen = IP_MSS - ip_size - icmp_size; - + /* Copy first part of original contents to ICMP message */ - + memmove(packet->data + ether_size + ip_size + icmp_size, packet->data + ether_size, oldlen); /* Fill in IPv4 header */ - + ip.ip_v = 4; ip.ip_hl = ip_size / 4; ip.ip_tos = 0; @@ -298,13 +298,13 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t ip.ip_dst = ip_src; ip.ip_sum = inet_checksum(&ip, ip_size, ~0); - + /* Fill in ICMP header */ - + icmp.icmp_type = type; icmp.icmp_code = code; icmp.icmp_cksum = 0; - + icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0); icmp.icmp_cksum = inet_checksum(packet->data + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum); @@ -312,7 +312,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t memcpy(packet->data + ether_size, &ip, ip_size); memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size); - + packet->len = ether_size + ip_size + icmp_size + oldlen; send_packet(source, packet); @@ -326,13 +326,13 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) { int len, maxlen, todo; uint8_t *offset; uint16_t ip_off, origf; - + memcpy(&ip, packet->data + ether_size, ip_size); fragment.priority = packet->priority; if(ip.ip_hl != ip_size / 4) return; - + todo = ntohs(ip.ip_len) - ip_size; if(ether_size + ip_size + todo != packet->len) { @@ -347,7 +347,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) { ip_off = ntohs(ip.ip_off); origf = ip_off & ~IP_OFFMASK; ip_off &= IP_OFFMASK; - + while(todo) { len = todo > maxlen ? maxlen : todo; memcpy(fragment.data + ether_size + ip_size, offset, len); @@ -365,7 +365,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) { send_packet(dest, &fragment); ip_off += len / 8; - } + } } static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { @@ -387,7 +387,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN); return; } - + if(subnet->owner == source) { logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname); return; @@ -408,7 +408,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { logger(DEBUG_TRAFFIC, LOG_ERR, "Routing loop for packet from %s (%s)!", source->name, source->hostname); return; } - + if(directonly && subnet->owner != via) return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO); @@ -425,7 +425,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { } clamp_mss(source, via, packet); - + send_packet(subnet->owner, packet); } @@ -448,18 +448,18 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) { 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; + uint16_t checksum; struct { - struct in6_addr ip6_src; /* source address */ - struct in6_addr ip6_dst; /* destination address */ + struct in6_addr ip6_src; /* source address */ + struct in6_addr ip6_dst; /* destination address */ uint32_t length; uint32_t next; } pseudo; if(ratelimit(3)) return; - + /* Swap Ethernet source and destination addresses */ swap_mac_addresses(packet); @@ -469,7 +469,7 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t memcpy(&ip6, packet->data + ether_size, ip6_size); /* Remember original source and destination */ - + pseudo.ip6_src = ip6.ip6_dst; pseudo.ip6_dst = ip6.ip6_src; @@ -477,16 +477,16 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t if(type == ICMP6_PACKET_TOO_BIG) icmp6.icmp6_mtu = htonl(pseudo.length); - + if(pseudo.length >= IP_MSS - ip6_size - icmp6_size) pseudo.length = IP_MSS - ip6_size - icmp6_size; - + /* Copy first part of original contents to ICMP message */ - + memmove(packet->data + ether_size + ip6_size + icmp6_size, packet->data + ether_size, pseudo.length); /* Fill in IPv6 header */ - + ip6.ip6_flow = htonl(0x60000000UL); ip6.ip6_plen = htons(icmp6_size + pseudo.length); ip6.ip6_nxt = IPPROTO_ICMPV6; @@ -495,18 +495,18 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t ip6.ip6_dst = pseudo.ip6_dst; /* Fill in ICMP header */ - + icmp6.icmp6_type = type; icmp6.icmp6_code = code; icmp6.icmp6_cksum = 0; /* Create pseudo header */ - + pseudo.length = htonl(icmp6_size + pseudo.length); pseudo.next = htonl(IPPROTO_ICMPV6); /* Generate checksum */ - + checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); checksum = inet_checksum(&icmp6, icmp6_size, checksum); checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum); @@ -517,9 +517,9 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t memcpy(packet->data + ether_size, &ip6, ip6_size); memcpy(packet->data + ether_size + ip6_size, &icmp6, icmp6_size); - + packet->len = ether_size + ip6_size + ntohl(pseudo.length); - + send_packet(source, packet); } @@ -559,12 +559,12 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { 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 == source) { logger(DEBUG_TRAFFIC, LOG_ERR, "Routing loop for packet from %s (%s)!", source->name, source->hostname); return; } - + if(directonly && subnet->owner != via) return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); @@ -576,7 +576,7 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { } clamp_mss(source, via, packet); - + send_packet(subnet->owner, packet); } @@ -591,17 +591,17 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) { bool has_opt; struct { - struct in6_addr ip6_src; /* source address */ - struct in6_addr ip6_dst; /* destination address */ + struct in6_addr ip6_src; + struct in6_addr ip6_dst; uint32_t length; uint32_t next; } pseudo; if(!checklength(source, packet, ether_size + ip6_size + ns_size)) return; - + has_opt = packet->len >= ether_size + ip6_size + ns_size + opt_size + ETH_ALEN; - + if(source != myself) { logger(DEBUG_TRAFFIC, LOG_WARNING, "Got neighbor solicitation request from %s (%s) while in router mode!", source->name, source->hostname); return; @@ -672,22 +672,22 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) { /* Check if it is for our own subnet */ if(subnet->owner == myself) - return; /* silently ignore */ + return; /* silently ignore */ /* Create neighbor advertation reply */ - memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ - packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ + memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ + packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ - ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */ + ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */ ip6.ip6_src = ns.nd_ns_target; if(has_opt) - memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ + memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ ns.nd_ns_cksum = 0; ns.nd_ns_type = ND_NEIGHBOR_ADVERT; - ns.nd_ns_reserved = htonl(0x40000000UL); /* Set solicited flag */ + ns.nd_ns_reserved = htonl(0x40000000UL); /* Set solicited flag */ opt.nd_opt_type = ND_OPT_TARGET_LINKADDR; /* Create pseudo header */ @@ -782,17 +782,17 @@ static void route_arp(node_t *source, vpn_packet_t *packet) { /* Check if it is for our own subnet */ if(subnet->owner == myself) - return; /* silently ignore */ + return; /* silently ignore */ - memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ - packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ + memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ + packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ - memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */ - memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */ - memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */ + memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */ + memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */ + memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */ - memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */ - memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ + memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */ + memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ arp.arp_op = htons(ARPOP_REPLY); /* Copy structs on stack back to packet */ @@ -838,7 +838,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { if(directonly && subnet->owner != via) return; - + if(via && packet->len > via->mtu && via != myself) { logger(DEBUG_TRAFFIC, 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]; @@ -858,7 +858,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { } clamp_mss(source, via, packet); - + send_packet(subnet->owner, packet); } @@ -941,28 +941,26 @@ void route(node_t *source, vpn_packet_t *packet) { if(!do_decrement_ttl(source, packet)) return; + uint16_t type = packet->data[12] << 8 | packet->data[13]; + switch (routing_mode) { case RMODE_ROUTER: - { - uint16_t type = packet->data[12] << 8 | packet->data[13]; - - switch (type) { - case ETH_P_ARP: - route_arp(source, packet); - break; - - case ETH_P_IP: - route_ipv4(source, packet); - break; - - case ETH_P_IPV6: - route_ipv6(source, packet); - break; - - default: - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type); - break; - } + switch (type) { + case ETH_P_ARP: + route_arp(source, packet); + break; + + case ETH_P_IP: + route_ipv4(source, packet); + break; + + case ETH_P_IPV6: + route_ipv6(source, packet); + break; + + default: + logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type); + break; } break;