[packages/mtr] - fix source address binding for IPv4 again - rel 3

adwol adwol at pld-linux.org
Sat Oct 23 00:50:49 CEST 2021


commit cffe34541e0e1cf720ff43fd0e8b8d2c522f7707
Author: Adam Osuchowski <adwol at pld-linux.org>
Date:   Sat Oct 23 00:49:12 2021 +0200

    - fix source address binding for IPv4 again
    - rel 3

 mtr-sourceaddr_ipv4.patch | 386 ++++++++++++++++++++++++++++++++++++++++++++++
 mtr.spec                  |   5 +-
 2 files changed, 390 insertions(+), 1 deletion(-)
---
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
 
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 *) &current_sockaddr,
+-                        &current_sockaddr_len)) {
+-            return -1;
+-        }
+-        struct sockaddr_in *sin_cur =
+-            (struct sockaddr_in *) &current_sockaddr;
++    current_sockaddr_len = sizeof(struct sockaddr_in);
++    if (getsockname(send_socket, (struct sockaddr *) &current_sockaddr,
++                    &current_sockaddr_len) == 0) {
++        struct sockaddr_in *sin_cur = (struct sockaddr_in *) &current_sockaddr;
+ 
+-        /* avoid double bind */
+-        if (sin_cur->sin_port) {
+-            bind_send_socket = false;
++        if (net_state->platform.ip4_socket_raw) {
++            if (memcmp(&current_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;
+ 
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/mtr.git/commitdiff/cffe34541e0e1cf720ff43fd0e8b8d2c522f7707



More information about the pld-cvs-commit mailing list