Fix source IP address for ICMP unreachable packets generated by tinc.
Try to send ICMP unreachable replies from an address assigned to the local machine, instead of the destination address of the original packet. The address is found by looking up the route towards the sender of the packet that generated the error; in usual configurations, this is the tinc interface. This also fixes the traceroute display in mtr when using the DecrementTTL option. Signed-off-by: Vittorio Gambaletta <openwrt@vittgam.net> # Conflicts: # src/route.c
This commit is contained in:
parent
a8a3a2c8ce
commit
92203bdbcb
1 changed files with 41 additions and 1 deletions
42
src/route.c
42
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_src;
|
||||||
struct in_addr ip_dst;
|
struct in_addr ip_dst;
|
||||||
uint32_t oldlen;
|
uint32_t oldlen;
|
||||||
|
int sockfd;
|
||||||
|
|
||||||
if(ratelimit(3))
|
if(ratelimit(3))
|
||||||
return;
|
return;
|
||||||
|
@ -276,6 +277,25 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
|
||||||
ip_src = ip.ip_src;
|
ip_src = ip.ip_src;
|
||||||
ip_dst = ip.ip_dst;
|
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;
|
oldlen = packet->len - ether_size;
|
||||||
|
|
||||||
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
|
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) {
|
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 ip6_hdr ip6;
|
||||||
struct icmp6_hdr icmp6 = {0};
|
struct icmp6_hdr icmp6 = {0};
|
||||||
uint16_t checksum;
|
uint16_t checksum;
|
||||||
|
int sockfd;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct in6_addr ip6_src; /* source address */
|
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_src = ip6.ip6_dst;
|
||||||
pseudo.ip6_dst = ip6.ip6_src;
|
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;
|
pseudo.length = packet->len - ether_size;
|
||||||
|
|
||||||
if(type == ICMP6_PACKET_TOO_BIG)
|
if(type == ICMP6_PACKET_TOO_BIG)
|
||||||
|
|
Loading…
Reference in a new issue