summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Osuchowski2021-10-22 22:49:12 (GMT)
committerAdam Osuchowski2021-10-22 22:49:12 (GMT)
commitcffe34541e0e1cf720ff43fd0e8b8d2c522f7707 (patch)
tree29f2d737fff12e05ebf6da505b1cfe31bc4bc393
parentc9b98541d34727af83b27c892a44b7f9a1cac52f (diff)
downloadmtr-cffe34541e0e1cf720ff43fd0e8b8d2c522f7707.zip
mtr-cffe34541e0e1cf720ff43fd0e8b8d2c522f7707.tar.gz
- fix source address binding for IPv4 again
- rel 3
-rw-r--r--mtr-sourceaddr_ipv4.patch386
-rw-r--r--mtr.spec5
2 files changed, 390 insertions, 1 deletions
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;
+
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