From: Markus Kötter Date: Thu, 1 Nov 2018 10:34:25 +0000 (+0100) Subject: probe - extend matching to src/dst host&port X-Git-Tag: v0.93~1^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=08750eb4449a07a203723497627ab8032e3eeb89;p=thirdparty%2Fmtr.git probe - extend matching to src/dst host&port Running multiple instances of mtr in udp mode will lead to incorrect response pick ups due to sequence number re-use. The changes address the issue by using more values to prevent incorrect probe matches. --- diff --git a/packet/construct_unix.c b/packet/construct_unix.c index 9b33596..2268a22 100644 --- a/packet/construct_unix.c +++ b/packet/construct_unix.c @@ -99,15 +99,12 @@ void construct_addr_port( static void construct_ip4_header( const struct net_state_t *net_state, + const struct probe_t *probe, char *packet_buffer, int packet_size, - const struct sockaddr_storage *srcaddr, - const struct sockaddr_storage *destaddr, const struct probe_param_t *param) { struct IPHeader *ip; - struct sockaddr_in *srcaddr4 = (struct sockaddr_in *) srcaddr; - struct sockaddr_in *destaddr4 = (struct sockaddr_in *) destaddr; ip = (struct IPHeader *) &packet_buffer[0]; @@ -118,15 +115,20 @@ void construct_ip4_header( ip->len = length_byte_swap(net_state, packet_size); ip->ttl = param->ttl; ip->protocol = param->protocol; - memcpy(&ip->saddr, &srcaddr4->sin_addr, sizeof(uint32_t)); - memcpy(&ip->daddr, &destaddr4->sin_addr, sizeof(uint32_t)); +// ip->id = htons(getpid()); + memcpy(&ip->saddr, + sockaddr_addr_offset(&probe->local_addr), + sockaddr_addr_size(&probe->local_addr)); + memcpy(&ip->daddr, + sockaddr_addr_offset(&probe->remote_addr), + sockaddr_addr_size(&probe->remote_addr)); } /* Construct an ICMP header for IPv4 */ static void construct_icmp4_header( const struct net_state_t *net_state, - int sequence, + struct probe_t *probe, char *packet_buffer, int packet_size, const struct probe_param_t *param) @@ -146,7 +148,7 @@ void construct_icmp4_header( icmp->type = ICMP_ECHO; icmp->id = htons(getpid()); - icmp->sequence = htons(sequence); + icmp->sequence = htons(probe->sequence); icmp->checksum = htons(compute_checksum(icmp, icmp_size)); } @@ -154,7 +156,7 @@ void construct_icmp4_header( static int construct_icmp6_packet( const struct net_state_t *net_state, - int sequence, + struct probe_t *probe, char *packet_buffer, int packet_size, const struct probe_param_t *param) @@ -167,7 +169,7 @@ int construct_icmp6_packet( icmp->type = ICMP6_ECHO; icmp->id = htons(getpid()); - icmp->sequence = htons(sequence); + icmp->sequence = htons(probe->sequence); return 0; } @@ -184,7 +186,7 @@ int construct_icmp6_packet( static void set_udp_ports( struct UDPHeader *udp, - int sequence, + struct probe_t *probe, const struct probe_param_t *param) { if (param->dest_port) { @@ -192,13 +194,13 @@ void set_udp_ports( if (param->local_port) { udp->srcport = htons(param->local_port); - udp->checksum = htons(sequence); + udp->checksum = htons(probe->sequence); } else { - udp->srcport = htons(sequence); + udp->srcport = htons(probe->sequence); udp->checksum = 0; } } else { - udp->dstport = htons(sequence); + udp->dstport = htons(probe->sequence); if (param->local_port) { udp->srcport = htons(param->local_port); @@ -208,6 +210,8 @@ void set_udp_ports( udp->checksum = 0; } + *(uint16_t *)sockaddr_port_offset(&probe->local_addr) = udp->srcport; + *(uint16_t *)sockaddr_port_offset(&probe->remote_addr) = udp->dstport; } /* Prepend pseudoheader to the udp datagram and calculate checksum */ @@ -236,11 +240,9 @@ int udp4_checksum(void *pheader, void *udata, int psize, int dsize, static void construct_udp4_header( const struct net_state_t *net_state, - int sequence, + struct probe_t *probe, char *packet_buffer, int packet_size, - const struct sockaddr_in *src_addr, - const struct sockaddr_in *dst_addr, const struct probe_param_t *param) { struct UDPHeader *udp; @@ -256,13 +258,13 @@ void construct_udp4_header( memset(udp, 0, sizeof(struct UDPHeader)); - set_udp_ports(udp, sequence, param); + set_udp_ports(udp, probe, param); udp->length = htons(udp_size); /* calculate udp checksum */ struct UDPPseudoHeader udph = { - .saddr = src_addr->sin_addr.s_addr, - .daddr = dst_addr->sin_addr.s_addr, + .saddr = *(uint32_t *)sockaddr_addr_offset(&probe->local_addr), + .daddr = *(uint32_t *)sockaddr_addr_offset(&probe->remote_addr), .zero = 0, .protocol = 17, .len = udp->length @@ -287,7 +289,7 @@ void construct_udp4_header( static int construct_udp6_packet( const struct net_state_t *net_state, - int sequence, + struct probe_t *probe, char *packet_buffer, int packet_size, const struct probe_param_t *param) @@ -301,7 +303,7 @@ int construct_udp6_packet( memset(udp, 0, sizeof(struct UDPHeader)); - set_udp_ports(udp, sequence, param); + set_udp_ports(udp, probe, param); udp->length = htons(udp_size); if (net_state->platform.ip6_socket_raw) { @@ -538,11 +540,9 @@ static int construct_ip4_packet( const struct net_state_t *net_state, int *packet_socket, - int sequence, + struct probe_t *probe, char *packet_buffer, int packet_size, - const struct sockaddr_storage *src_sockaddr, - const struct sockaddr_storage *dest_sockaddr, const struct probe_param_t *param) { int send_socket = net_state->platform.ip4_send_socket; @@ -560,18 +560,15 @@ int construct_ip4_packet( #endif } else { if (net_state->platform.ip4_socket_raw) { - construct_ip4_header(net_state, packet_buffer, packet_size, - src_sockaddr, dest_sockaddr, param); + construct_ip4_header(net_state, probe, packet_buffer, packet_size, + param); } if (param->protocol == IPPROTO_ICMP) { - construct_icmp4_header(net_state, sequence, packet_buffer, + construct_icmp4_header(net_state, probe, packet_buffer, packet_size, param); } else if (param->protocol == IPPROTO_UDP) { - construct_udp4_header(net_state, sequence, packet_buffer, - packet_size, - (struct sockaddr_in *)src_sockaddr, - (struct sockaddr_in *)dest_sockaddr, - param); + construct_udp4_header(net_state, probe, packet_buffer, + packet_size, param); } else { errno = EINVAL; return -1; @@ -580,8 +577,8 @@ int construct_ip4_packet( if (is_stream_protocol) { send_socket = - open_stream_socket(net_state, param->protocol, sequence, - src_sockaddr, dest_sockaddr, param); + open_stream_socket(net_state, param->protocol, probe->sequence, + &probe->local_addr, &probe->remote_addr, param); if (send_socket == -1) { return -1; @@ -634,7 +631,7 @@ int construct_ip4_packet( } /* Bind to our local address */ - if (bind_send_socket && bind(socket, (struct sockaddr *)src_sockaddr, + if (bind_send_socket && bind(socket, (struct sockaddr *)&probe->local_addr, sizeof(struct sockaddr_in))) { return -1; } @@ -667,11 +664,9 @@ static int construct_ip6_packet( const struct net_state_t *net_state, int *packet_socket, - int sequence, + struct probe_t *probe, char *packet_buffer, int packet_size, - const struct sockaddr_storage *src_sockaddr, - const struct sockaddr_storage *dest_sockaddr, const struct probe_param_t *param) { int send_socket; @@ -694,7 +689,7 @@ int construct_ip6_packet( } if (construct_icmp6_packet - (net_state, sequence, packet_buffer, packet_size, param)) { + (net_state, probe, packet_buffer, packet_size, param)) { return -1; } } else if (param->protocol == IPPROTO_UDP) { @@ -705,7 +700,7 @@ int construct_ip6_packet( } if (construct_udp6_packet - (net_state, sequence, packet_buffer, packet_size, param)) { + (net_state, probe, packet_buffer, packet_size, param)) { return -1; } } else { @@ -715,8 +710,8 @@ int construct_ip6_packet( if (is_stream_protocol) { send_socket = - open_stream_socket(net_state, param->protocol, sequence, - src_sockaddr, dest_sockaddr, param); + open_stream_socket(net_state, param->protocol, probe->sequence, + &probe->local_addr, &probe->remote_addr, param); if (send_socket == -1) { return -1; @@ -740,7 +735,7 @@ int construct_ip6_packet( if (net_state->platform.ip6_socket_raw) { if (memcmp(¤t_sockaddr, - src_sockaddr, sizeof(struct sockaddr_in6)) == 0) { + &probe->local_addr, sizeof(struct sockaddr_in6)) == 0) { bind_send_socket = false; } } else { @@ -753,7 +748,7 @@ int construct_ip6_packet( /* Bind to our local address */ if (bind_send_socket) { - if (bind(send_socket, (struct sockaddr *) src_sockaddr, + if (bind(send_socket, (struct sockaddr *) &probe->local_addr, sizeof(struct sockaddr_in6))) { return -1; } @@ -787,11 +782,9 @@ int construct_ip6_packet( int construct_packet( const struct net_state_t *net_state, int *packet_socket, - int sequence, + struct probe_t *probe, char *packet_buffer, int packet_buffer_size, - const struct sockaddr_storage *dest_sockaddr, - const struct sockaddr_storage *src_sockaddr, const struct probe_param_t *param) { int packet_size; @@ -809,15 +802,15 @@ int construct_packet( memset(packet_buffer, param->bit_pattern, packet_size); if (param->ip_version == 6) { - if (construct_ip6_packet(net_state, packet_socket, sequence, + if (construct_ip6_packet(net_state, packet_socket, probe, packet_buffer, packet_size, - src_sockaddr, dest_sockaddr, param)) { + param)) { return -1; } } else if (param->ip_version == 4) { - if (construct_ip4_packet(net_state, packet_socket, sequence, + if (construct_ip4_packet(net_state, packet_socket, probe, packet_buffer, packet_size, - src_sockaddr, dest_sockaddr, param)) { + param)) { return -1; } } else { diff --git a/packet/construct_unix.h b/packet/construct_unix.h index 39fe282..99e1305 100644 --- a/packet/construct_unix.h +++ b/packet/construct_unix.h @@ -24,11 +24,9 @@ int construct_packet( const struct net_state_t *net_state, int *packet_socket, - int sequence, + struct probe_t *probe, char *packet_buffer, int packet_buffer_size, - const struct sockaddr_storage *dest_sockaddr, - const struct sockaddr_storage *src_sockaddr, const struct probe_param_t *param); #endif diff --git a/packet/deconstruct_unix.c b/packet/deconstruct_unix.c index 276f803..3c535e1 100644 --- a/packet/deconstruct_unix.c +++ b/packet/deconstruct_unix.c @@ -23,6 +23,7 @@ #include #include "protocols.h" +#include "sockaddr.h" #define MAX_MPLS_LABELS 8 @@ -64,6 +65,8 @@ void handle_inner_udp_packet( struct net_state_t *net_state, const struct sockaddr_storage *remote_addr, int icmp_result, + int af, + const void *ip, const struct UDPHeader *udp, int udp_length, struct timeval *timestamp, @@ -79,11 +82,46 @@ void handle_inner_udp_packet( if (probe == NULL) { probe = find_probe(net_state, IPPROTO_UDP, 0, udp->checksum); } + if (probe == NULL) + return; - if (probe != NULL) { - receive_probe(net_state, probe, icmp_result, - remote_addr, timestamp, mpls_count, mpls); + if (probe->remote_addr.ss_family != remote_addr->ss_family) + return; + + if (udp->dstport != *(uint16_t *)sockaddr_port_offset(&probe->remote_addr) ) + return; + + if (udp->srcport != *(uint16_t *)sockaddr_port_offset(&probe->local_addr) ) + return; + + void *saddr, *daddr; + if (af == AF_INET) + { + saddr = &((struct IPHeader *)ip)->saddr; + daddr = &((struct IPHeader *)ip)->daddr; + }else + if (af == AF_INET6) + { + daddr = &((struct IP6Header *)ip)->daddr; + saddr = &((struct IP6Header *)ip)->saddr; + }else + { + return; } + + if( memcmp(sockaddr_addr_offset(&probe->remote_addr), + daddr, + sockaddr_addr_size(&probe->remote_addr)) != 0 ) + return; + + if( memcmp(sockaddr_addr_offset(&probe->local_addr), + saddr, + sockaddr_addr_size(&probe->local_addr)) != 0) + return; + + /* probe is not null */ + receive_probe(net_state, probe, icmp_result, + remote_addr, timestamp, mpls_count, mpls); } void handle_error_queue_packet( @@ -96,7 +134,7 @@ void handle_error_queue_packet( struct timeval *timestamp) { if (proto == IPPROTO_UDP) { - handle_inner_udp_packet(net_state, remote_addr, ICMP_TIME_EXCEEDED, + handle_inner_udp_packet(net_state, remote_addr, ICMP_TIME_EXCEEDED, 0, NULL, (struct UDPHeader *)packet, packet_length, timestamp, 0, NULL); } else if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) { const struct ICMPHeader *icmp = (struct ICMPHeader *)packet; @@ -157,7 +195,7 @@ void handle_inner_ip4_packet( udp = (struct UDPHeader *) (ip + 1); udp_length = packet_length - sizeof(struct IPHeader); - handle_inner_udp_packet(net_state, remote_addr, icmp_result, udp, + handle_inner_udp_packet(net_state, remote_addr, icmp_result, AF_INET, ip, udp, udp_length, timestamp, mpls_count, mpls); } else if (ip->protocol == IPPROTO_TCP) { if (packet_length < ip_tcp_size) { @@ -233,7 +271,7 @@ void handle_inner_ip6_packet( udp = (struct UDPHeader *) (ip + 1); udp_length = packet_length - sizeof(struct IP6Header); - handle_inner_udp_packet(net_state, remote_addr, icmp_result, udp, + handle_inner_udp_packet(net_state, remote_addr, icmp_result, AF_INET6, ip, udp, udp_length, timestamp, mpls_count, mpls); } else if (ip->protocol == IPPROTO_TCP) { if (packet_length < ip_tcp_size) { diff --git a/packet/probe.h b/packet/probe.h index ead2a41..53b8037 100644 --- a/packet/probe.h +++ b/packet/probe.h @@ -104,6 +104,10 @@ struct probe_t { /* The address being probed */ struct sockaddr_storage remote_addr; + /* The local address which was used */ + struct sockaddr_storage local_addr; + + /* Platform specific probe tracking */ struct probe_platform_t platform; }; diff --git a/packet/probe_unix.c b/packet/probe_unix.c index 046229d..405b53c 100644 --- a/packet/probe_unix.c +++ b/packet/probe_unix.c @@ -120,8 +120,7 @@ void check_length_order( { char packet[PACKET_BUFFER_SIZE]; struct probe_param_t param; - struct sockaddr_storage dest_sockaddr; - struct sockaddr_storage src_sockaddr; + struct probe_t p0 = {.sequence = MIN_PORT }; ssize_t bytes_sent; int packet_size; @@ -138,8 +137,9 @@ void check_length_order( param.remote_address = "127.0.0.1"; param.is_probing_byte_order = true; - if (resolve_probe_addresses(net_state, ¶m, &dest_sockaddr, - &src_sockaddr)) { + + if (resolve_probe_addresses(net_state, ¶m, &p0.remote_addr, + &p0.local_addr)) { fprintf(stderr, "Error decoding localhost address\n"); exit(EXIT_FAILURE); } @@ -147,9 +147,9 @@ void check_length_order( /* First attempt to ping the localhost with network byte order */ net_state->platform.ip_length_host_order = false; - packet_size = construct_packet(net_state, NULL, MIN_PORT, + packet_size = construct_packet(net_state, NULL, &p0, packet, PACKET_BUFFER_SIZE, - &dest_sockaddr, &src_sockaddr, ¶m); + ¶m); if (packet_size < 0) { perror("Unable to send to localhost"); exit(EXIT_FAILURE); @@ -157,7 +157,7 @@ void check_length_order( bytes_sent = send_packet(net_state, ¶m, MIN_PORT, packet, packet_size, - &dest_sockaddr); + &p0.remote_addr); if (bytes_sent > 0) { return; } @@ -165,9 +165,9 @@ void check_length_order( /* Since network byte order failed, try host byte order */ net_state->platform.ip_length_host_order = true; - packet_size = construct_packet(net_state, NULL, MIN_PORT, + packet_size = construct_packet(net_state, NULL, &p0, packet, PACKET_BUFFER_SIZE, - &dest_sockaddr, &src_sockaddr, ¶m); + ¶m); if (packet_size < 0) { perror("Unable to send to localhost"); exit(EXIT_FAILURE); @@ -175,7 +175,7 @@ void check_length_order( bytes_sent = send_packet(net_state, ¶m, MIN_PORT, packet, packet_size, - &dest_sockaddr); + &p0.remote_addr); if (bytes_sent < 0) { perror("Unable to send with swapped length"); exit(EXIT_FAILURE); @@ -551,7 +551,6 @@ void send_probe( { char packet[PACKET_BUFFER_SIZE]; struct probe_t *probe; - struct sockaddr_storage src_sockaddr; int trytimes; int packet_size; @@ -562,7 +561,7 @@ void send_probe( } if (resolve_probe_addresses(net_state, param, &probe->remote_addr, - &src_sockaddr)) { + &probe->local_addr)) { printf("%d invalid-argument\n", param->command_token); free_probe(net_state, probe); return; @@ -579,9 +578,9 @@ void send_probe( for (trytimes=MIN_PORT; trytimes < MAX_PORT; trytimes++) { packet_size = construct_packet(net_state, &probe->platform.socket, - probe->sequence, packet, PACKET_BUFFER_SIZE, - &probe->remote_addr, &src_sockaddr, param); - + probe, packet, PACKET_BUFFER_SIZE, + param); + if (packet_size > 0) break; // no retry if we succeed. if ((param->protocol != IPPROTO_TCP) &&