From cffe34541e0e1cf720ff43fd0e8b8d2c522f7707 Mon Sep 17 00:00:00 2001 From: Adam Osuchowski Date: Sat, 23 Oct 2021 00:49:12 +0200 Subject: - fix source address binding for IPv4 again - rel 3 diff --git a/mtr-sourceaddr_ipv4.patch b/mtr-sourceaddr_ipv4.patch new file mode 100644 index 0000000..2817d23 --- /dev/null +++ b/mtr-sourceaddr_ipv4.patch @@ -0,0 +1,386 @@ +diff -ruNp mtr-0.94.orig/packet/construct_unix.c mtr-0.94/packet/construct_unix.c +--- mtr-0.94.orig/packet/construct_unix.c 2020-09-24 10:26:14.000000000 +0200 ++++ mtr-0.94/packet/construct_unix.c 2021-10-23 00:30:26.579107865 +0200 +@@ -71,19 +71,6 @@ uint16_t compute_checksum( + return (~sum & 0xffff); + } + +-/* Encode the IP header length field in the order required by the OS. */ +-static +-uint16_t length_byte_swap( +- const struct net_state_t *net_state, +- uint16_t length) +-{ +- if (net_state->platform.ip_length_host_order) { +- return length; +- } else { +- return htons(length); +- } +-} +- + /* Construct a combined sockaddr from a source address and source port */ + static + void construct_addr_port( +@@ -95,38 +82,9 @@ void construct_addr_port( + *sockaddr_port_offset(addr_with_port) = htons(port); + } + +-/* Construct a header for IP version 4 */ +-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 probe_param_t *param) +-{ +- struct IPHeader *ip; +- +- ip = (struct IPHeader *) &packet_buffer[0]; +- +- memset(ip, 0, sizeof(struct IPHeader)); +- +- ip->version = 0x45; +- ip->tos = param->type_of_service; +- ip->len = length_byte_swap(net_state, packet_size); +- ip->ttl = param->ttl; +- ip->protocol = param->protocol; +-// 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( ++int construct_icmp4_packet( + const struct net_state_t *net_state, + struct probe_t *probe, + char *packet_buffer, +@@ -134,22 +92,17 @@ void construct_icmp4_header( + const struct probe_param_t *param) + { + struct ICMPHeader *icmp; +- int icmp_size; + +- if (net_state->platform.ip4_socket_raw) { +- icmp = (struct ICMPHeader *) &packet_buffer[sizeof(struct IPHeader)]; +- icmp_size = packet_size - sizeof(struct IPHeader); +- } else { +- icmp = (struct ICMPHeader *) &packet_buffer[0]; +- icmp_size = packet_size; +- } ++ icmp = (struct ICMPHeader *) packet_buffer; + + memset(icmp, 0, sizeof(struct ICMPHeader)); + + icmp->type = ICMP_ECHO; + icmp->id = htons(getpid()); + icmp->sequence = htons(probe->sequence); +- icmp->checksum = htons(compute_checksum(icmp, icmp_size)); ++ icmp->checksum = htons(compute_checksum(icmp, packet_size)); ++ ++ return 0; + } + + /* Construct an ICMP header for IPv6 */ +@@ -238,7 +191,7 @@ int udp4_checksum(void *pheader, void *u + with the probe. + */ + static +-void construct_udp4_header( ++int construct_udp4_packet( + const struct net_state_t *net_state, + struct probe_t *probe, + char *packet_buffer, +@@ -248,13 +201,8 @@ void construct_udp4_header( + struct UDPHeader *udp; + int udp_size; + +- if (net_state->platform.ip4_socket_raw) { +- udp = (struct UDPHeader *) &packet_buffer[sizeof(struct IPHeader)]; +- udp_size = packet_size - sizeof(struct IPHeader); +- } else { +- udp = (struct UDPHeader *) &packet_buffer[0]; +- udp_size = packet_size; +- } ++ udp = (struct UDPHeader *) packet_buffer; ++ udp_size = packet_size; + + memset(udp, 0, sizeof(struct UDPHeader)); + +@@ -283,6 +231,8 @@ void construct_udp4_header( + *checksum_off = htons(udp4_checksum(&udph, udp, + sizeof(struct UDPPseudoHeader), + udp_size, udp->checksum != 0)); ++ ++ return 0; + } + + /* Construct a header for UDPv6 probes */ +@@ -545,10 +495,10 @@ int construct_ip4_packet( + int packet_size, + const struct probe_param_t *param) + { +- int send_socket = net_state->platform.ip4_send_socket; ++ int send_socket; + bool is_stream_protocol = false; +- int tos, ttl, socket; +- bool bind_send_socket = false; ++ int tos, ttl; ++ bool bind_send_socket = true; + struct sockaddr_storage current_sockaddr; + int current_sockaddr_len; + +@@ -558,23 +508,34 @@ int construct_ip4_packet( + } else if (param->protocol == IPPROTO_SCTP) { + is_stream_protocol = true; + #endif +- } else { ++ } else if (param->protocol == IPPROTO_ICMP) { + if (net_state->platform.ip4_socket_raw) { +- construct_ip4_header(net_state, probe, packet_buffer, packet_size, +- param); ++ send_socket = net_state->platform.icmp4_send_socket; ++ } else { ++ send_socket = net_state->platform.ip4_txrx_icmp_socket; ++ } ++ ++ if (construct_icmp4_packet ++ (net_state, probe, packet_buffer, packet_size, param)) { ++ return -1; + } +- if (param->protocol == IPPROTO_ICMP) { +- construct_icmp4_header(net_state, probe, packet_buffer, +- packet_size, param); +- } else if (param->protocol == IPPROTO_UDP) { +- construct_udp4_header(net_state, probe, packet_buffer, +- packet_size, param); ++ } else if (param->protocol == IPPROTO_UDP) { ++ if (net_state->platform.ip4_socket_raw) { ++ send_socket = net_state->platform.udp4_send_socket; + } else { +- errno = EINVAL; ++ send_socket = net_state->platform.ip4_txrx_udp_socket; ++ } ++ ++ if (construct_udp4_packet ++ (net_state, probe, packet_buffer, packet_size, param)) { + return -1; + } ++ } else { ++ errno = EINVAL; ++ return -1; + } + ++ + if (is_stream_protocol) { + send_socket = + open_stream_socket(net_state, param->protocol, probe->sequence, +@@ -608,54 +569,51 @@ int construct_ip4_packet( + #endif + + /* +- Bind src port when not using raw socket to pass in ICMP id, kernel +- get ICMP id from src_port when using DGRAM socket. ++ Check the current socket address, and if it is the same ++ as the source address we intend, we will skip the bind. ++ This is to accommodate Solaris, which, as of Solaris 11.3, ++ will return an EINVAL error on bind if the socket is already ++ bound, even if the same address is used. + */ +- if (!net_state->platform.ip4_socket_raw && +- param->protocol == IPPROTO_ICMP && +- !param->is_probing_byte_order) { +- current_sockaddr_len = sizeof(struct sockaddr_in); +- bind_send_socket = true; +- socket = net_state->platform.ip4_txrx_icmp_socket; +- if (getsockname(socket, (struct sockaddr *) ¤t_sockaddr, +- ¤t_sockaddr_len)) { +- return -1; +- } +- struct sockaddr_in *sin_cur = +- (struct sockaddr_in *) ¤t_sockaddr; ++ current_sockaddr_len = sizeof(struct sockaddr_in); ++ if (getsockname(send_socket, (struct sockaddr *) ¤t_sockaddr, ++ ¤t_sockaddr_len) == 0) { ++ struct sockaddr_in *sin_cur = (struct sockaddr_in *) ¤t_sockaddr; + +- /* avoid double bind */ +- if (sin_cur->sin_port) { +- bind_send_socket = false; ++ if (net_state->platform.ip4_socket_raw) { ++ if (memcmp(¤t_sockaddr, ++ &probe->local_addr, sizeof(struct sockaddr_in)) == 0) { ++ bind_send_socket = false; ++ } ++ } else { ++ /* avoid double bind for DGRAM socket */ ++ if (sin_cur->sin_port) { ++ bind_send_socket = false; ++ } + } + } + + /* Bind to our local address */ +- if (bind_send_socket && bind(socket, (struct sockaddr *)&probe->local_addr, ++ if (bind_send_socket && bind(send_socket, (struct sockaddr *)&probe->local_addr, + sizeof(struct sockaddr_in))) { + return -1; + } + +- /* set TOS and TTL for non-raw socket */ +- if (!net_state->platform.ip4_socket_raw && !param->is_probing_byte_order) { +- if (param->protocol == IPPROTO_ICMP) { +- socket = net_state->platform.ip4_txrx_icmp_socket; +- } else if (param->protocol == IPPROTO_UDP) { +- socket = net_state->platform.ip4_txrx_udp_socket; +- } else { +- return 0; +- } +- tos = param->type_of_service; +- if (setsockopt(socket, SOL_IP, IP_TOS, &tos, sizeof(int))) { +- return -1; +- } +- ttl = param->ttl; +- if (setsockopt(socket, SOL_IP, IP_TTL, +- &ttl, sizeof(int)) == -1) { +- return -1; +- } ++ /* Set the type of service */ ++ tos = param->type_of_service; ++ if (setsockopt(send_socket, SOL_IP, IP_TOS, &tos, sizeof(int))) { ++ return -1; + } + ++ /* Set the time-to-live */ ++ ttl = param->ttl; ++ if (setsockopt(send_socket, SOL_IP, IP_TTL, ++ &ttl, sizeof(int)) == -1) { ++ return -1; ++ } ++ ++ ++ + return 0; + } + +diff -ruNp mtr-0.94.orig/packet/probe_unix.c mtr-0.94/packet/probe_unix.c +--- mtr-0.94.orig/packet/probe_unix.c 2020-09-24 10:26:14.000000000 +0200 ++++ mtr-0.94/packet/probe_unix.c 2021-10-23 00:30:26.579107865 +0200 +@@ -87,16 +87,21 @@ int send_packet( + } else if (sockaddr->ss_family == AF_INET) { + sockaddr_length = sizeof(struct sockaddr_in); + +- if (net_state->platform.ip4_socket_raw) { +- send_socket = net_state->platform.ip4_send_socket; +- } else { +- if (param->protocol == IPPROTO_ICMP) { +- if (param->is_probing_byte_order) { +- send_socket = net_state->platform.ip4_tmp_icmp_socket;; +- } else { +- send_socket = net_state->platform.ip4_txrx_icmp_socket; +- } +- } else if (param->protocol == IPPROTO_UDP) { ++ if (param->protocol == IPPROTO_ICMP) { ++ if (net_state->platform.ip4_socket_raw) { ++ send_socket = net_state->platform.icmp4_send_socket; ++ } else { ++ send_socket = net_state->platform.ip4_txrx_icmp_socket; ++ } ++ } else if (param->protocol == IPPROTO_UDP) { ++ if (net_state->platform.ip4_socket_raw) { ++ send_socket = net_state->platform.udp4_send_socket; ++ /* we got a ipv4 udp raw socket ++ * the remote port is in the payload ++ * we do not set in the sockaddr ++ */ ++ *sockaddr_port_offset(&dst) = 0; ++ } else { + send_socket = net_state->platform.ip4_txrx_udp_socket; + if (param->dest_port) { + *sockaddr_port_offset(&dst) = htons(param->dest_port); +@@ -105,6 +110,7 @@ int send_packet( + } + } + } ++ + } + + if (send_socket == 0) { +@@ -236,26 +242,19 @@ static + int open_ip4_sockets_raw( + struct net_state_t *net_state) + { +- int send_socket; ++ int send_socket_icmp; ++ int send_socket_udp; + int recv_socket; +- int trueopt = 1; + +- send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); +- if (send_socket == -1) { +- send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); +- if (send_socket == -1) { +- return -1; +- } ++ send_socket_icmp = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); ++ if (send_socket_icmp == -1) { ++ return -1; + } + +- /* +- We will be including the IP header in transmitted packets. +- Linux doesn't require this, but BSD derived network stacks do. +- */ +- if (setsockopt +- (send_socket, IPPROTO_IP, IP_HDRINCL, &trueopt, sizeof(int))) { ++ send_socket_udp = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); ++ if (send_socket_udp == -1) { ++ close(send_socket_icmp); + +- close(send_socket); + return -1; + } + +@@ -265,13 +264,15 @@ int open_ip4_sockets_raw( + */ + recv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (recv_socket == -1) { +- close(send_socket); ++ close(send_socket_icmp); ++ close(send_socket_udp); + return -1; + } + + net_state->platform.ip4_present = true; + net_state->platform.ip4_socket_raw = true; +- net_state->platform.ip4_send_socket = send_socket; ++ net_state->platform.icmp4_send_socket = send_socket_icmp; ++ net_state->platform.udp4_send_socket = send_socket_udp; + net_state->platform.ip4_recv_socket = recv_socket; + + return 0; +diff -ruNp mtr-0.94.orig/packet/probe_unix.h mtr-0.94/packet/probe_unix.h +--- mtr-0.94.orig/packet/probe_unix.h 2020-09-24 10:26:14.000000000 +0200 ++++ mtr-0.94/packet/probe_unix.h 2021-10-23 00:31:30.775836399 +0200 +@@ -69,9 +69,15 @@ struct net_state_platform_t { + /* Socket used to send IPv4 udp packets and receive icmp err packets */ + int ip4_txrx_udp_socket; + ++ /* Send socket for ICMPv4 packets */ ++ int icmp4_send_socket; ++ + /* Send socket for ICMPv6 packets */ + int icmp6_send_socket; + ++ /* Send socket for UDPv4 packets */ ++ int udp4_send_socket; ++ + /* Send socket for UDPv6 packets */ + int udp6_send_socket; + diff --git a/mtr.spec b/mtr.spec index 9fbf3ad..5bec156 100644 --- a/mtr.spec +++ b/mtr.spec @@ -10,7 +10,7 @@ Summary(ru.UTF-8): Matt's Traceroute - утилита для диагности Summary(uk.UTF-8): Matt's Traceroute - утиліта для діагностики мережі Name: mtr Version: 0.94 -Release: 2 +Release: 3 Epoch: 1 License: GPL v2 Group: Networking/Utilities @@ -26,6 +26,8 @@ Patch1: %{name}-mtr6.patch Patch2: %{name}-display.patch Patch3: %{name}-curses-clear_colors.patch Patch4: %{name}-completion.patch +# https://github.com/TomHetmer/mtr/commit/19a1fbaf4efc232c4f4a29067297cf5c93fb2794.diff +Patch5: %{name}-sourceaddr_ipv4.patch URL: http://www.bitwizard.nl/mtr/ BuildRequires: autoconf >= 2.59 BuildRequires: automake >= 1:1.7.9 @@ -159,6 +161,7 @@ Pakiet ten dostarcza bashowe uzupełnianie parametrów polecenia mtr. %patch2 -p1 %patch3 -p1 %patch4 -p1 +%patch5 -p1 echo %{version} > .tarball-version -- cgit v0.10.2