From: Matt Kimball Date: Fri, 23 Dec 2016 17:37:47 +0000 (-0800) Subject: mtr-packet: allow local address binding X-Git-Tag: v0.88~15^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4149c2cfbe63881105142f00a0ce6e32b0712b78;p=thirdparty%2Fmtr.git mtr-packet: allow local address binding A probe can be bound to a local address with the 'local-ip-4' or 'local-ip-6' arguments to 'send-probe'. The '-a' commandline argument to mtr will cause sent probes to be bound to the specified address. Changed argument names for consistency: 'localport' is now 'local-port' 'bitpattern' is now 'bit-pattern' mtr now opens and connects a UDP socket at startup to determine the local address for display in the UI. Windows error codes resulting from send-probe are now using the same error strings which are used to report errors in the Unix implementation. We now use the mtr commandline timeout value for sent probes. Edited the help and man page to reflect that the timeout value no longer applies to only TCP probes, but now all probes. With this change, I believe the mtr-packet implementation is at feature parity with mainline mtr. --- diff --git a/cmdpipe.c b/cmdpipe.c index 3a38ec7..4783e30 100644 --- a/cmdpipe.c +++ b/cmdpipe.c @@ -325,24 +325,38 @@ void construct_base_command( char *command, int buffer_size, int command_token, - ip_t *address) + ip_t *address, + ip_t *localaddress) { char ip_string[INET6_ADDRSTRLEN]; + char local_ip_string[INET6_ADDRSTRLEN]; const char *ip_type; + const char *local_ip_type; const char *protocol = NULL; /* Conver the remote IP address to a string */ if (inet_ntop( - ctl->af, address, ip_string, INET6_ADDRSTRLEN) == NULL) { + ctl->af, address, + ip_string, INET6_ADDRSTRLEN) == NULL) { display_close(ctl); - error(EXIT_FAILURE, errno, "failure stringifying remote IP address"); + error(EXIT_FAILURE, errno, "invalid remote IP address"); + } + + if (inet_ntop( + ctl->af, localaddress, + local_ip_string, INET6_ADDRSTRLEN) == NULL) { + + display_close(ctl); + error(EXIT_FAILURE, errno, "invalid local IP address"); } if (ctl->af == AF_INET6) { ip_type = "ip-6"; + local_ip_type = "local-ip-6"; } else { ip_type = "ip-4"; + local_ip_type = "local-ip-4"; } if (ctl->mtrtype == IPPROTO_ICMP) { @@ -362,8 +376,10 @@ void construct_base_command( snprintf( command, buffer_size, - "%d send-probe %s %s protocol %s", - command_token, ip_type, ip_string, protocol); + "%d send-probe %s %s %s %s protocol %s", + command_token, + ip_type, ip_string, local_ip_type, local_ip_string, + protocol); } @@ -390,21 +406,23 @@ void send_probe_command( struct mtr_ctl *ctl, struct packet_command_pipe_t *cmdpipe, ip_t *address, + ip_t *localaddress, int packet_size, int sequence, int time_to_live) { char command[COMMAND_BUFFER_SIZE]; int remaining_size; + int timeout; construct_base_command( - ctl, command, COMMAND_BUFFER_SIZE, sequence, address); + ctl, command, COMMAND_BUFFER_SIZE, sequence, address, localaddress); append_command_argument( command, COMMAND_BUFFER_SIZE, "size", packet_size); append_command_argument( - command, COMMAND_BUFFER_SIZE, "bitpattern", ctl->bitpattern); + command, COMMAND_BUFFER_SIZE, "bit-pattern", ctl->bitpattern); append_command_argument( command, COMMAND_BUFFER_SIZE, "tos", ctl->tos); @@ -412,6 +430,10 @@ void send_probe_command( append_command_argument( command, COMMAND_BUFFER_SIZE, "ttl", time_to_live); + timeout = ctl->probe_timeout / 1000000; + append_command_argument( + command, COMMAND_BUFFER_SIZE, "timeout", timeout); + if (ctl->remoteport) { append_command_argument( command, COMMAND_BUFFER_SIZE, "port", ctl->remoteport); @@ -419,7 +441,7 @@ void send_probe_command( if (ctl->localport) { append_command_argument( - command, COMMAND_BUFFER_SIZE, "localport", ctl->localport); + command, COMMAND_BUFFER_SIZE, "local-port", ctl->localport); } #ifdef SO_MARK @@ -609,6 +631,16 @@ void handle_reply_errors( error(EXIT_FAILURE, 0, "Permission denied"); } + if (!strcmp(reply_name, "address-in-use")) { + display_close(ctl); + error(EXIT_FAILURE, 0, "Address in use"); + } + + if (!strcmp(reply_name, "address-not-available")) { + display_close(ctl); + error(EXIT_FAILURE, 0, "Address not available"); + } + if (!strcmp(reply_name, "unexpected-error")) { display_close(ctl); error(EXIT_FAILURE, 0, "Unexpected mtr-packet error"); diff --git a/cmdpipe.h b/cmdpipe.h index 9c0dd86..8f2cb70 100644 --- a/cmdpipe.h +++ b/cmdpipe.h @@ -61,6 +61,7 @@ void send_probe_command( struct mtr_ctl *ctl, struct packet_command_pipe_t *cmdpipe, ip_t *address, + ip_t *localaddress, int packet_size, int sequence, int time_to_live); diff --git a/mtr-packet.8.in b/mtr-packet.8.in index 97b46af..9691f74 100644 --- a/mtr-packet.8.in +++ b/mtr-packet.8.in @@ -117,7 +117,21 @@ or probes. .HP 7 .IP -.B localport +.B local-ip-4 +.I IP-ADDRESS +.HP 14 +.IP +The local Internet Procol version 4 address to use when sending probes. +.HP 7 +.IP +.B local-ip-6 +.I IP-ADDRESS +.HP 14 +.IP +The local Internet Protocol version 6 address to use when sending probes. +.HP 7 +.IP +.B local-port .I PORT-NUMBER .HP 14 .IP @@ -154,7 +168,7 @@ The size of the packet used to send the probe, in bytes, including the Internet Protocol header and transport protocol header. .HP 7 .IP -.B bitpattern +.B bit-pattern .I PATTERN-VALUE .HP 14 .IP diff --git a/mtr.8.in b/mtr.8.in index eb9fbe8..79ffc09 100644 --- a/mtr.8.in +++ b/mtr.8.in @@ -407,10 +407,9 @@ The target port number for TCP/SCTP/UDP traces. The source port number for UDP traces. .TP .B \-Z \fISECONDS\fR, \fB\-\-timeout \fISECONDS -The number of seconds to keep the TCP socket open before giving up on -the connection. This will only affect the final hop. Using large values -for this, especially combined with a short interval, will use up a lot -of file descriptors. +The number of seconds to keep probe sockets open before giving up on +the connection. Using large values for this, especially combined with +a short interval, will use up a lot of file descriptors. .TP .B \-M \fIMARK\fR, \fB\-\-mark \fIMARK Set the mark for each packet sent through this socket similar to the diff --git a/mtr.c b/mtr.c index 48307ff..0f0650e 100644 --- a/mtr.c +++ b/mtr.c @@ -102,21 +102,21 @@ static void __attribute__((__noreturn__)) usage(FILE *out) fputs(" -F, --filename FILE read hostname(s) from a file\n", out); fputs(" -4 use IPv4 only\n", out); fputs(" -6 use IPv6 only\n", out); - fputs(" -u, --udp use udp instead of icmp echo\n", out); - fputs(" -T, --tcp use tcp instead of icmp echo\n", out); + fputs(" -u, --udp use UDP instead of ICMP echo\n", out); + fputs(" -T, --tcp use TCP instead of ICMP echo\n", out); fputs(" -a, --address ADDRESS bind the outgoing socket to ADDRESS\n", out); fputs(" -f, --first-ttl NUMBER set what TTL to start\n", out); fputs(" -m, --max-ttl NUMBER maximum number of hops\n", out); fputs(" -U, --max-unknown NUMBER maximum unknown host\n", out); - fputs(" -P, --port PORT target port number for tcp, sctp, or udp\n", out); - fputs(" -L, --localport LOCALPORT source port number for udp\n", out); + fputs(" -P, --port PORT target port number for TCP, SCTP, or UDP\n", out); + fputs(" -L, --localport LOCALPORT source port number for UDP\n", out); fputs(" -s, --psize PACKETSIZE set the packet size used for probing\n", out); fputs(" -B, --bitpattern NUMBER set bit pattern to use in payload\n", out); - fputs(" -i, --interval SECONDS icmp echo request interval\n", out); + fputs(" -i, --interval SECONDS ICMP echo request interval\n", out); fputs(" -G, --gracetime SECONDS number of seconds to wait for responses\n", out); fputs(" -Q, --tos NUMBER type of service field in IP header\n", out); fputs(" -e, --mpls display information from ICMP extensions\n", out); - fputs(" -Z, --timeout SECONDS seconds to keep the TCP socket open\n", out); + fputs(" -Z, --timeout SECONDS seconds to keep probe sockets open\n", out); fputs(" -M, --mark MARK mark each sent packet\n", out); fputs(" -r, --report output using report mode\n", out); fputs(" -w, --report-wide output wide report\n", out); @@ -137,7 +137,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out) fputs(" -b, --show-ips show IP numbers and host names\n", out); fputs(" -o, --order FIELDS select output fields\n", out); #ifdef HAVE_IPINFO - fputs(" -y, --ipinfo NUMBER select ip information in output\n", out); + fputs(" -y, --ipinfo NUMBER select IP information in output\n", out); fputs(" -z, --aslookup display AS number\n", out); #endif fputs(" -h, --help display this help and exit\n", out); @@ -323,7 +323,7 @@ static void parse_arg (struct mtr_ctl *ctl, names_t **names, int argc, char **ar { "sctp", 0, NULL, 'S' }, /* SCTP (default is ICMP) */ { "port", 1, NULL, 'P' }, /* target port number for TCP/SCTP/UDP */ { "localport", 1, NULL, 'L' }, /* source port number for UDP */ - { "timeout", 1, NULL, 'Z' }, /* timeout for TCP sockets */ + { "timeout", 1, NULL, 'Z' }, /* timeout for probe sockets */ { "gracetime", 1, NULL, 'G' }, /* gracetime for replies after last probe */ #ifdef SO_MARK { "mark", 1, NULL, 'M' }, /* use SO_MARK */ @@ -531,8 +531,8 @@ static void parse_arg (struct mtr_ctl *ctl, names_t **names, int argc, char **ar } break; case 'Z': - ctl->tcp_timeout = strtonum_or_err(optarg, "invalid argument", STRTO_INT); - ctl->tcp_timeout *= 1000000; + ctl->probe_timeout = strtonum_or_err(optarg, "invalid argument", STRTO_INT); + ctl->probe_timeout *= 1000000; break; case '4': ctl->af = AF_INET; @@ -648,7 +648,7 @@ extern int main(int argc, char **argv) ctl.fstTTL = 1; ctl.maxTTL = 30; ctl.maxUnknown = 12; - ctl.tcp_timeout = 10 * 1000000; + ctl.probe_timeout = 10 * 1000000; ctl.ipinfo_no = -1; ctl.ipinfo_max = -1; xstrncpy(ctl.fld_active, "LS NABWV", 2 * MAXFLD); diff --git a/mtr.h b/mtr.h index 1058a5a..364ed2a 100644 --- a/mtr.h +++ b/mtr.h @@ -101,7 +101,7 @@ struct mtr_ctl { int maxUnknown; /* stop ping threshold */ int remoteport; /* target port for TCP tracing */ int localport; /* source port for UDP tracing */ - int tcp_timeout; /* timeout for TCP connections */ + int probe_timeout; /* timeout for probe sockets */ unsigned char fld_active[2 * MAXFLD]; /* SO_MARK to set for ping packet*/ int display_mode; /* display mode selector */ int fld_index[FLD_INDEX_SZ]; /* default display field (defined by key in net.h) and order */ diff --git a/net.c b/net.c index 3703e9a..e49de8e 100644 --- a/net.c +++ b/net.c @@ -18,10 +18,12 @@ #include "config.h" +#include #include #include #include #include +#include #ifdef HAVE_ERROR_H # include @@ -41,6 +43,8 @@ static int packetsize; /* packet size used by ping */ +static void sockaddrtop( struct sockaddr * saddr, char * strptr, size_t len ); + struct nethost { ip_t addr; ip_t addrs[MAXPATH]; /* for multi paths byMin */ @@ -88,6 +92,7 @@ static struct sockaddr_in sourcesockaddr_struct; static struct sockaddr_in remotesockaddr_struct; #endif +static struct sockaddr * sourcesockaddr = (struct sockaddr *) &sourcesockaddr_struct; static struct sockaddr * remotesockaddr = (struct sockaddr *) &remotesockaddr_struct; static struct sockaddr_in * ssa4 = (struct sockaddr_in *) &sourcesockaddr_struct; static struct sockaddr_in * rsa4 = (struct sockaddr_in *) &remotesockaddr_struct; @@ -154,7 +159,8 @@ static void net_send_query(struct mtr_ctl *ctl, int index, int packet_size) int time_to_live = index + 1; send_probe_command( - ctl, &packet_command_pipe, remoteaddress, packetsize, seq, time_to_live); + ctl, &packet_command_pipe, remoteaddress, sourceaddress, + packetsize, seq, time_to_live); } @@ -481,6 +487,75 @@ extern int net_send_batch(struct mtr_ctl *ctl) } +/* Ensure the interface address a valid address for our use */ +static void net_validate_interface_address( + int address_family, char *interface_address) +{ + if (inet_pton( + address_family, interface_address, sourceaddress) != 1) { + + error(EXIT_FAILURE, errno, "invalid local address"); + } + + if (inet_ntop( + address_family, sourceaddress, localaddr, sizeof(localaddr)) == NULL) { + + error(EXIT_FAILURE, errno, "invalid local address"); + } +} + + +/* + Find the local address we will use to sent to the remote + host by connecting a UDP socket and checking the address + the socket is bound to. +*/ +static void net_find_local_address(void) +{ + int udp_socket; + int addr_length; + struct sockaddr_storage remote_sockaddr; + struct sockaddr_in *remote4; + struct sockaddr_in6 *remote6; + + udp_socket = socket(remotesockaddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); + if (udp_socket == -1) { + error(EXIT_FAILURE, errno, "udp socket creation failed"); + } + + /* + We need to set the port to a non-zero value for the connect + to succeed. + */ + if (remotesockaddr->sa_family == AF_INET6) { + addr_length = sizeof(struct sockaddr_in6); + + memcpy(&remote_sockaddr, rsa6, addr_length); + remote6 = (struct sockaddr_in6 *)&remote_sockaddr; + remote6->sin6_port = htons(1); + } else { + addr_length = sizeof(struct sockaddr_in); + + memcpy(&remote_sockaddr, rsa4, addr_length); + remote4 = (struct sockaddr_in *)&remote_sockaddr; + remote4->sin_port = htons(1); + } + + if (connect(udp_socket, (struct sockaddr *)&remote_sockaddr, addr_length)) { + error(EXIT_FAILURE, errno, "udp socket connect failed"); + } + + if (getsockname(udp_socket, sourcesockaddr, &addr_length)) { + + error(EXIT_FAILURE, errno, "local address determination failed"); + } + + sockaddrtop(sourcesockaddr, localaddr, sizeof(localaddr)); + + close(udp_socket); +} + + extern int net_open(struct mtr_ctl *ctl, struct hostent * hostent) { int err; @@ -512,6 +587,12 @@ extern int net_open(struct mtr_ctl *ctl, struct hostent * hostent) error(EXIT_FAILURE, 0, "net_open bad address type"); } + if (ctl->InterfaceAddress) { + net_validate_interface_address(ctl->af, ctl->InterfaceAddress); + } else { + net_find_local_address(); + } + return 0; } @@ -618,6 +699,33 @@ extern void net_save_return(int at, int seq, int ms) host[at].saved[idx] = ms; } +/* Similar to inet_ntop but uses a sockaddr as it's argument. */ +static void sockaddrtop( struct sockaddr * saddr, char * strptr, size_t len ) { + struct sockaddr_in * sa4; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 * sa6; +#endif + + switch ( saddr->sa_family ) { + case AF_INET: + sa4 = (struct sockaddr_in *) saddr; + xstrncpy( strptr, inet_ntoa( sa4->sin_addr ), len - 1 ); + strptr[ len - 1 ] = '\0'; + return; +#ifdef ENABLE_IPV6 + case AF_INET6: + sa6 = (struct sockaddr_in6 *) saddr; + inet_ntop( sa6->sin6_family, &(sa6->sin6_addr), strptr, len ); + return; +#endif + default: + error(0, 0, "sockaddrtop unknown address type"); + strptr[0] = '\0'; + return; + } +} + + /* Address comparison. */ extern int addrcmp( char * a, char * b, int family ) { int rc = -1; diff --git a/packet/command.c b/packet/command.c index faee5a8..2b9a054 100644 --- a/packet/command.c +++ b/packet/command.c @@ -150,13 +150,23 @@ bool decode_probe_argument( /* Pass IPv4 addresses as string values */ if (!strcmp(name, "ip-4")) { param->ip_version = 4; - param->address = value; + param->remote_address = value; } /* IPv6 address */ if (!strcmp(name, "ip-6")) { param->ip_version = 6; - param->address = value; + param->remote_address = value; + } + + /* IPv4 address to send from */ + if (!strcmp(name, "local-ip-4")) { + param->local_address = value; + } + + /* IPv6 address to send from */ + if (!strcmp(name, "local-ip-6")) { + param->local_address = value; } /* Protocol for the probe */ @@ -185,7 +195,7 @@ bool decode_probe_argument( } /* The local port to send UDP probes from */ - if (!strcmp(name, "localport")) { + if (!strcmp(name, "local-port")) { param->local_port = strtol(value, &endstr, 10); if (*endstr != 0) { return false; @@ -226,7 +236,7 @@ bool decode_probe_argument( } /* The packet's bytes will be filled with this value */ - if (!strcmp(name, "bitpattern")) { + if (!strcmp(name, "bit-pattern")) { param->bit_pattern = strtol(value, &endstr, 10); if (*endstr != 0) { return false; diff --git a/packet/construct_unix.c b/packet/construct_unix.c index 5800426..6fe3684 100644 --- a/packet/construct_unix.c +++ b/packet/construct_unix.c @@ -612,6 +612,11 @@ int construct_ip6_packet( return 0; } + if (bind(send_socket, + (struct sockaddr *)src_sockaddr, sizeof(struct sockaddr_in6))) { + return -1; + } + /* The traffic class in IPv6 is analagous to ToS in IPv4 */ if (setsockopt( send_socket, IPPROTO_IPV6, @@ -647,10 +652,10 @@ int construct_packet( 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; - struct sockaddr_storage src_sockaddr; packet_size = compute_packet_size(net_state, param); if (packet_size < 0) { @@ -662,24 +667,20 @@ int construct_packet( return -1; } - if (find_source_addr(&src_sockaddr, dest_sockaddr)) { - return -1; - } - memset(packet_buffer, param->bit_pattern, packet_size); if (param->ip_version == 6) { if (construct_ip6_packet( net_state, packet_socket, sequence, packet_buffer, packet_size, - &src_sockaddr, dest_sockaddr, param)) { + src_sockaddr, dest_sockaddr, param)) { return -1; } } else if (param->ip_version == 4) { if (construct_ip4_packet( net_state, packet_socket, sequence, packet_buffer, packet_size, - &src_sockaddr, dest_sockaddr, param)) { + src_sockaddr, dest_sockaddr, param)) { return -1; } } else { diff --git a/packet/construct_unix.h b/packet/construct_unix.h index 1f0ae48..7ac7110 100644 --- a/packet/construct_unix.h +++ b/packet/construct_unix.h @@ -28,6 +28,7 @@ int construct_packet( 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/probe.c b/packet/probe.c index 7817866..3e7cffd 100644 --- a/packet/probe.c +++ b/packet/probe.c @@ -35,24 +35,25 @@ #define IP_TEXT_LENGTH 64 /* Convert the destination address from text to sockaddr */ -int decode_dest_addr( - const struct probe_param_t *param, - struct sockaddr_storage *dest_sockaddr) +int decode_address_string( + int ip_version, + const char *address_string, + struct sockaddr_storage *address) { - struct in_addr dest_addr4; - struct in6_addr dest_addr6; + struct in_addr addr4; + struct in6_addr addr6; struct sockaddr_in *sockaddr4; struct sockaddr_in6 *sockaddr6; - if (param->address == NULL) { + if (address == NULL) { errno = EINVAL; return -1; } - if (param->ip_version == 6) { - sockaddr6 = (struct sockaddr_in6 *)dest_sockaddr; + if (ip_version == 6) { + sockaddr6 = (struct sockaddr_in6 *)address; - if (inet_pton(AF_INET6, param->address, &dest_addr6) != 1) { + if (inet_pton(AF_INET6, address_string, &addr6) != 1) { errno = EINVAL; return -1; } @@ -60,19 +61,19 @@ int decode_dest_addr( sockaddr6->sin6_family = AF_INET6; sockaddr6->sin6_port = 0; sockaddr6->sin6_flowinfo = 0; - sockaddr6->sin6_addr = dest_addr6; + sockaddr6->sin6_addr = addr6; sockaddr6->sin6_scope_id = 0; - } else if (param->ip_version == 4) { - sockaddr4 = (struct sockaddr_in *)dest_sockaddr; + } else if (ip_version == 4) { + sockaddr4 = (struct sockaddr_in *)address; - if (inet_pton(AF_INET, param->address, &dest_addr4) != 1) { + if (inet_pton(AF_INET, address_string, &addr4) != 1) { errno = EINVAL; return -1; } sockaddr4->sin_family = AF_INET; sockaddr4->sin_port = 0; - sockaddr4->sin_addr = dest_addr4; + sockaddr4->sin_addr = addr4; } else { errno = EINVAL; return -1; @@ -81,6 +82,34 @@ int decode_dest_addr( return 0; } +/* + Resolve the probe parameters into a remote and local address + for the probe. +*/ +int resolve_probe_addresses( + const struct probe_param_t *param, + struct sockaddr_storage *dest_sockaddr, + struct sockaddr_storage *src_sockaddr) +{ + if (decode_address_string( + param->ip_version, param->remote_address, dest_sockaddr)) { + return -1; + } + + if (param->local_address) { + if (decode_address_string( + param->ip_version, param->local_address, src_sockaddr)) { + return -1; + } + } else { + if (find_source_addr(src_sockaddr, dest_sockaddr)) { + return -1; + } + } + + return 0; +} + /* Allocate a structure for tracking a new probe */ struct probe_t *alloc_probe( struct net_state_t *net_state, diff --git a/packet/probe.h b/packet/probe.h index 6538388..25a225d 100644 --- a/packet/probe.h +++ b/packet/probe.h @@ -46,7 +46,10 @@ struct probe_param_t int command_token; /* The IP address to probe */ - const char *address; + const char *remote_address; + + /* The local address from which to send probes */ + const char *local_address; /* Protocol for the probe, using the IPPROTO_* defines */ int protocol; @@ -150,9 +153,15 @@ void respond_to_probe( int mpls_count, const struct mpls_label_t *mpls); -int decode_dest_addr( +int decode_address_string( + int ip_version, + const char *address_string, + struct sockaddr_storage *address); + +int resolve_probe_addresses( const struct probe_param_t *param, - struct sockaddr_storage *dest_sockaddr); + struct sockaddr_storage *dest_sockaddr, + struct sockaddr_storage *src_sockaddr); struct probe_t *alloc_probe( struct net_state_t *net_state, diff --git a/packet/probe_cygwin.c b/packet/probe_cygwin.c index 0818f52..2857db9 100644 --- a/packet/probe_cygwin.c +++ b/packet/probe_cygwin.c @@ -77,6 +77,29 @@ void platform_free_probe( } } +/* Report a windows error code using a platform-independent error string */ +static +void report_win_error( + int command_token, + int err) +{ + /* It could be that we got no reply because of timeout */ + if (err == IP_REQ_TIMED_OUT) { + printf("%d no-reply\n", command_token); + } else if (err == IP_DEST_HOST_UNREACHABLE + || err == IP_DEST_NET_UNREACHABLE + || err == IP_DEST_UNREACHABLE + || err == IP_DEST_NO_ROUTE) { + printf("%d no-route\n", command_token); + } else if (err == ERROR_INVALID_NETNAME) { + printf("%d address-not-available\n", command_token); + } else if (err == ERROR_INVALID_PARAMETER) { + printf("%d invalid-argument\n", command_token); + } else { + printf("%d unexpected-error winerror %d\n", command_token, err); + } +} + /* The overlapped I/O style completion routine to be called by Windows during an altertable wait when an ICMP probe has @@ -139,16 +162,9 @@ void WINAPI on_icmp_reply( if (reply_count == 0) { err = GetLastError(); - /* It could be that we got no reply because of timeout */ - if (err == IP_REQ_TIMED_OUT) { - printf("%d no-reply\n", probe->token); - - free_probe(probe); - return; - } - - fprintf(stderr, "IcmpParseReplies failure %d\n", err); - exit(1); + report_win_error(probe->token, err); + free_probe(probe); + return; } @@ -183,6 +199,7 @@ void icmp_send_probe( DWORD timeout; DWORD send_result; int reply_size; + int err; struct sockaddr_in *dest_sockaddr4; struct sockaddr_in6 *src_sockaddr6; struct sockaddr_in6 *dest_sockaddr6; @@ -233,13 +250,15 @@ void icmp_send_probe( } if (send_result == 0) { + err = GetLastError(); + /* ERROR_IO_PENDING is expected for asynchronous probes, but any other error is unexpected. */ - if (GetLastError() != ERROR_IO_PENDING) { - fprintf(stderr, "IcmpSendEcho2 failure %d\n", GetLastError()); - exit(1); + if (err != ERROR_IO_PENDING) { + report_win_error(probe->token, err); + free_probe(probe); } } } @@ -289,7 +308,7 @@ void send_probe( char payload[PACKET_BUFFER_SIZE]; int payload_size; - if (decode_dest_addr(param, &dest_sockaddr)) { + if (resolve_probe_addresses(param, &dest_sockaddr, &src_sockaddr)) { printf("%d invalid-argument\n", param->command_token); return; } @@ -300,11 +319,6 @@ void send_probe( return; } - if (find_source_addr(&src_sockaddr, &dest_sockaddr)) { - fprintf(stderr, "error finding source address\n"); - exit(1); - } - probe->platform.ip_version = param->ip_version; payload_size = fill_payload(param, payload, PACKET_BUFFER_SIZE); diff --git a/packet/probe_unix.c b/packet/probe_unix.c index cdfd699..424901e 100644 --- a/packet/probe_unix.c +++ b/packet/probe_unix.c @@ -87,6 +87,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; ssize_t bytes_sent; int packet_size; @@ -94,9 +95,9 @@ void check_length_order( param.ip_version = 4; param.protocol = IPPROTO_ICMP; param.ttl = 255; - param.address = "127.0.0.1"; + param.remote_address = "127.0.0.1"; - if (decode_dest_addr(¶m, &dest_sockaddr)) { + if (resolve_probe_addresses(¶m, &dest_sockaddr, &src_sockaddr)) { fprintf(stderr, "Error decoding localhost address\n"); exit(1); } @@ -106,7 +107,8 @@ void check_length_order( packet_size = construct_packet( net_state, NULL, MIN_PORT, - packet, PACKET_BUFFER_SIZE, &dest_sockaddr, ¶m); + packet, PACKET_BUFFER_SIZE, + &dest_sockaddr, &src_sockaddr, ¶m); if (packet_size < 0) { perror("Unable to send to localhost"); exit(1); @@ -123,7 +125,8 @@ void check_length_order( packet_size = construct_packet( net_state, NULL, MIN_PORT, - packet, PACKET_BUFFER_SIZE, &dest_sockaddr, ¶m); + packet, PACKET_BUFFER_SIZE, + &dest_sockaddr, &src_sockaddr, ¶m); if (packet_size < 0) { perror("Unable to send to localhost"); exit(1); @@ -318,10 +321,14 @@ void report_packet_error( printf("%d network-down\n", command_token); } else if (errno == ENETUNREACH) { printf("%d no-route\n", command_token); + } else if (errno == EHOSTUNREACH) { + printf("%d no-route\n", command_token); } else if (errno == EPERM) { printf("%d permission-denied\n", command_token); } else if (errno == EADDRINUSE) { printf("%d address-in-use\n", command_token); + } else if (errno == EADDRNOTAVAIL) { + printf("%d address-not-available\n", command_token); } else { printf("%d unexpected-error errno %d\n", command_token, errno); } @@ -335,6 +342,7 @@ void send_probe( char packet[PACKET_BUFFER_SIZE]; struct probe_t *probe; int packet_size; + struct sockaddr_storage src_sockaddr; probe = alloc_probe(net_state, param->command_token); if (probe == NULL) { @@ -342,7 +350,7 @@ void send_probe( return; } - if (decode_dest_addr(param, &probe->remote_addr)) { + if (resolve_probe_addresses(param, &probe->remote_addr, &src_sockaddr)) { printf("%d invalid-argument\n", param->command_token); free_probe(probe); return; @@ -355,7 +363,8 @@ void send_probe( packet_size = construct_packet( net_state, &probe->platform.socket, probe->sequence, - packet, PACKET_BUFFER_SIZE, &probe->remote_addr, param); + packet, PACKET_BUFFER_SIZE, + &probe->remote_addr, &src_sockaddr, param); if (packet_size < 0) { /* diff --git a/test/param.py b/test/param.py index 7db108c..d511062 100755 --- a/test/param.py +++ b/test/param.py @@ -43,7 +43,7 @@ class TestParameters(mtrpacket.MtrPacketTest): 'Test probes are filled with the requested bit pattern' with mtrpacket.PacketListen('-4') as listen: - cmd = '20 send-probe ip-4 127.0.0.1 bitpattern 44' + cmd = '20 send-probe ip-4 127.0.0.1 bit-pattern 44' self.write_command(cmd) @@ -69,7 +69,7 @@ class TestIPv6Parameters(mtrpacket.MtrPacketTest): 'Test a variety of packet parameters' with mtrpacket.PacketListen('-6') as listen: - param = 'size 256 bitpattern 51 tos 77' + param = 'size 256 bit-pattern 51 tos 77' cmd = '20 send-probe ip-6 ::1 ' + param self.write_command(cmd) diff --git a/test/probe.py b/test/probe.py index 20ca892..871db41 100755 --- a/test/probe.py +++ b/test/probe.py @@ -326,7 +326,7 @@ class TestProbeUDP(mtrpacket.MtrPacketTest): reply = self.parse_reply() self.assertEqual('reply', reply.command_name) - cmd = '82 send-probe protocol udp localport 1991 ' + address + cmd = '82 send-probe protocol udp local-port 1991 ' + address self.write_command(cmd) reply = self.parse_reply() self.assertEqual('reply', reply.command_name)