X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Froute.c;h=324212b7c0be585a13f549f4b0f9543dc295a456;hp=c11267b159efe51fe11bd8629807859b528692a6;hb=3d02192c9bd42a979d8d5b109b0475dd0566e99f;hpb=8fce1eacd7fd7496a740be3ffc236fde37c681d7 diff --git a/src/route.c b/src/route.c index c11267b1..324212b7 100644 --- a/src/route.c +++ b/src/route.c @@ -275,6 +275,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 +498,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) @@ -891,7 +933,7 @@ static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) { if(!checklength(source, packet, ethlen + ip_size)) return false; - if(packet->data[ethlen + 8] < 1) { + if(packet->data[ethlen + 8] <= 1) { if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED) route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL); return false; @@ -914,7 +956,7 @@ static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) { if(!checklength(source, packet, ethlen + ip6_size)) return false; - if(packet->data[ethlen + 7] < 1) { + if(packet->data[ethlen + 7] <= 1) { if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED) route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT); return false;