X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Froute.c;h=c1be6cb0ae4a607ce54f1bb1cf0519c1ff49a484;hp=a1254d80832491ee947e505c2c2050a9cd33e0fa;hb=6da826db2154321addb79c05b60a5e6f1a9dccf1;hpb=a588f6febeca13edd038d78e42efb8aa9f16a444 diff --git a/src/route.c b/src/route.c index a1254d80..c1be6cb0 100644 --- a/src/route.c +++ b/src/route.c @@ -160,7 +160,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 = mtu - start - 20; - uint16_t csum = packet->data[start + 16] << 8 | packet->data[start + 17]; + uint32_t csum = packet->data[start + 16] << 8 | packet->data[start + 17]; if(oldmss <= newmss) break; @@ -171,11 +171,13 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac packet->data[start + 22 + i] = newmss >> 8; packet->data[start + 23 + i] = newmss & 0xff; csum ^= 0xffff; - csum -= oldmss; + csum += oldmss ^ 0xffff; csum += newmss; + csum = (csum & 0xffff) + (csum >> 16); + csum += csum >> 16; csum ^= 0xffff; packet->data[start + 16] = csum >> 8; - packet->data[start + 17] = csum & 0xff; + packet->data[start + 17] = csum; break; } } @@ -275,6 +277,27 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_ ip_src = ip.ip_src; ip_dst = ip.ip_dst; + /* Try to reply with an IP address assigned to the local machine */ + + if (type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) { + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd != -1) { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = ip.ip_src; + if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) { + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + socklen_t addrlen = sizeof(addr); + if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) { + ip_dst = addr.sin_addr; + } + } + close(sockfd); + } + } + oldlen = packet->len - ether_size; if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) @@ -477,6 +500,27 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_ pseudo.ip6_src = ip6.ip6_dst; pseudo.ip6_dst = ip6.ip6_src; + /* Try to reply with an IP address assigned to the local machine */ + + if (type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) { + int sockfd = socket(AF_INET6, SOCK_DGRAM, 0); + if (sockfd != -1) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = ip6.ip6_src; + if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) { + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + socklen_t addrlen = sizeof(addr); + if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) { + pseudo.ip6_src = addr.sin6_addr; + } + } + close(sockfd); + } + } + pseudo.length = packet->len - ether_size; if(type == ICMP6_PACKET_TOO_BIG)