X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Froute.c;h=3d7b1df1e426ad36d7c3105352abdd23899bd79f;hp=d7c4c872fe27fed160af90458ea403ecd66e4387;hb=92203bdbcb1af4a52c7ca9d0e1a271168435c905;hpb=a8a3a2c8ceb19bcb6c2c3ef0647c94d7d0624b7a diff --git a/src/route.c b/src/route.c index d7c4c872..3d7b1df1 100644 --- a/src/route.c +++ b/src/route.c @@ -259,6 +259,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_ struct in_addr ip_src; struct in_addr ip_dst; uint32_t oldlen; + int sockfd; if(ratelimit(3)) return; @@ -276,6 +277,25 @@ 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 */ + + 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) @@ -448,7 +468,8 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) { static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { struct ip6_hdr ip6; struct icmp6_hdr icmp6 = {0}; - uint16_t checksum; + uint16_t checksum; + int sockfd; struct { struct in6_addr ip6_src; /* source address */ @@ -473,6 +494,25 @@ 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 */ + + 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)