Open bd46 opened 6 years ago
After bug submission I found the same bug as #232, sorry for duplicaion. Testcase is quite simple: multihomed host (several interfaces with different addresses), mtr sent packets via default route regardless of -a option.
Just to confirm that I also came in practice to the same bug -a source_IP
not working with ICMP, it sends the packets with the proper source_IP but trough the default interface (gateway) not the one associated with the provided source IP. With --tcp
it works as expected.
Ubuntu 18.04
mtr --version
mtr 0.92
Test case. Normal PC, ifconfig eth0:1 <a second IP addres>
Now ping -I <second ip adress>
a host and see that the second IP address is being used.
Now mtr -a <second ip address>
that host and see that the second IP address is being used.
The -I on "ping" hints at using an INTERFACE as the source, but I don't think that can be done with the networking-interface on Unix-like machines. the -a option on mtr explains better what it does: The source address is set. The kernel then often decides to use the interface that you meant to use, but if it doesn't... well mtr can't do much about that.
When mtr submits packet FROM your second interface IP address, TO "random IP on the internet", you still expect the routing tables to work and tell that packet where to go. As an example: If you ping-or-mtr a host not on your local network, you expect the kernel to look up how to reach that host and often then use the default route to try to reach that host, right?
On Thu, Aug 02, 2018 at 11:36:19PM -0700, Roger Wolff wrote:
Test case. Normal PC, ifconfig eth0:1 Now ping -I
a host and see that the second IP address is being used. Now mtr -a that host and see that the second IP address is being used. The -I on "ping" hints at using an INTERFACE as the source, but I don't think that can be done with the networking-interface on Unix-like machines. the -a option on mtr explains better what it does: The source address is set. The kernel then often decides to use the interface that you meant to use, but if it doesn't... well mtr can't do much about that.
To set ip-address of source packets application MUST(!) do bind(2) syscall.
For check run "strace -e bind -o mtr.trace mtr -a
It's a bug. And it's practice, not abstract theory. Ping works fine. -- Eugene Berdnikov
@rewolff , on the same machine ping -I source_IP
provides the expected result - it works!
As I said in the previous post, the bug is when the source_IP is not on the interface of default gw for that scope. We have tested it even without any network namespaces and VRFs or ip rules...
I have same issue with mtr package in version 0.92-2 on Debian buster.
I have simple machines. If any of you can provide me a "howto reproduce" that I can run to reproduce this, then the chances that I can look into it improve dramatically.
On Wed, Jan 15, 2020 at 09:33:04AM -0800, Roger Wolff wrote:
I have simple machines. If any of you can provide me a "howto reproduce" that I can run to reproduce this, then the chances that I can look into it improve dramatically.
What do you mean by "simple machines"? Machines with one (single) network interface except loopback? You can't reproduce problem with one interface. The point is: if you have several interfaces to destination with different addresses, then wrong interface may be chosen.
Manual page told:
-a ADDRESS, --address ADDRESS
Use this option to bind the outgoing socket to ADDRESS, so that
all packets will be sent with ADDRESS as source address. NOTE
that this option doesn't apply to DNS requests (which could be
and could not be what you want).
This is a lie: mtr do not bind outgoing socket to this address. Really, it does not call bind(2) at all, that can be easily proved with strace. There no invocation of bind() in the source code!
Mtr uses raw socket and tries to feed kernel with packet having "-a" value as its source address field in ip header. Strace shows:
9580 socket(AF_INET, SOCK_RAW, IPPROTO_RAW) = 3 9580 setsockopt(3, SOL_IP, IP_HDRINCL, [1], 4) = 0
then something like that:
9580 read(0, "33000 send-probe ip-4 192.168.16.47 local-ip-4 192.168.30.1 protocol icmp size 64 bit-pattern 0 tos 0 ttl 1 timeout 10\n", 4095) = 119 9580 getpid() = 9580 9580 sendto(3, "E\0\0@\0\0\0\0\1\1\0\0\300\250\36\1\300\250\20/\10\0Q\253%l\200\350\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 64, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("192.168.16.47")}, 16) = 64
This logic is defective: kernel DOES NOT scan packet ip-headers in order to make route lookup. That's why filling source ip field in ip-4 header is not enouph for correct routing. You must additionally do bind() on socket to the source address, otherwise kernel peeks wrong interface to send. Namely, without bind() it peaks interface corresponding to default route.
How to reproduce on Linux: connect 2 interfaces (say, eth0 and eth1) to some switch, and configure them to one subnet:
ip addr add 192.168.0.2/24 dev eth0 ip rule add pref 2 from 192.168.0.2 lookup 2 ip route add table 2 192.168.0.0/24 dev eth0 sysctl -w net.ipv4.conf.eth0.rp_filter=1 sysctl -w net.ipv4.conf.eth0.arp_filter=1
ip addr add 192.168.0.3/24 dev eth1 ip rule add pref 3 from 192.168.0.3 lookup 3 ip route add table 3 192.168.0.0/24 dev eth1 sysctl -w net.ipv4.conf.eth1.rp_filter=1 sysctl -w net.ipv4.conf.eth1.arp_filter=1
Plug a target host with ip=192.168.0.1 (mask /24) to the same switch. Check that depending on source ip-address ping sends packets via right interface and get replies on the same interface:
ping -n -I 192.168.0.2 192.168.0.1 # use eth0 ping -n -I 192.168.0.3 192.168.0.1 # use eth1
It can be watched by interfaces packet counters on host and switch, or by blinking leds, or by tcpdump, or even by disconnecting cables.
Then run mtr:
mtr -n -a 192.168.0.2 192.168.0.1 mtr -n -a 192.168.0.3 192.168.0.1
You should see that mtr in both cases use one interface. However, old versions of mtr worked right. -- Eugene Berdnikov
Hi,
This issue is still present in latest release 0.93. Neither -I or -a change the source address of a packet.
Cheers, David
A raw socket can be bound to a specific local address using the bind(2) call. If it isn't bound, all packets with the specified IP protocol are received. In addition, a RAW socket can be bound to a specific network device using SO_BINDTODEVICE; see socket(7).
One way of fixing it. One small problem is, you need to find out the device name first.
On Thu, Sep 24, 2020 at 11:08:46AM -0700, Tom Hetmer wrote:
A raw socket can be bound to a specific local address using the bind(2) call. If it isn't bound, all packets with the specified IP protocol are received. In addition, a RAW socket can be bound to a specific network device using SO_BINDTODEVICE; see socket(7).
One way of fixing it. One small problem is, you need to find out the device name first.
It's not a problem but small task to get device name from CLI.
There is already a command line option to get bind address, so 1st variant "bind to IP addr" is even simpler. It might be good to implement both. -- Eugene Berdnikov
Please check commit https://github.com/TomHetmer/mtr/commit/19a1fbaf4efc232c4f4a29067297cf5c93fb2794 I rewrote the v4 sockets to get rid of IPPROTO_RAW.
cc @rewolff i'll do a pull request if it's okay.
The "HDR_INCL" define has completely vanished. Could it be that this is going to be a problem on some machines that you did not test?
>Linux doesn't require this, but BSD derived network stacks do.
Any idea what those machines are?
Would be weird since it's copied from the IPv6 code and that one doesn't use IPV6_HDRINCL. Runs fine on Linux and OS X, anything else I don't have.
Best Tom Hetmer
On Fri, Sep 25, 2020 at 11:54 AM Roger Wolff notifications@github.com wrote:
The "HDR_INCL" define has completely vanished. Could it be that this is going to be a problem on some machines that you did not test?
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/traviscross/mtr/issues/250#issuecomment-698838537, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIR5GUZREMZP2BTVN7XTRTSHRSD5ANCNFSM4EYKLEQA .
sigh…… still broken in 0.93
any updates on this?
I was able to reproduce it using
# dpkg -l | grep mtr
ii mtr-tiny 0.93-1
on Ubuntu 20.04
mtr-tiny 0.93-1
on Ubuntu 20.04 also doesn't work properly using
mtr -I <IFACE> 1.1.1.1
It ignores both -I
and -a
mtr 0.95 on Arch does not work properly
The configuration of my environment is as follows: [root@mtr ~]# mtr --version mtr 0.95
[root@mtr ~]# ip rule show 0: from all lookup local 32765: from 99.99.23.6 lookup net_252 32766: from all lookup main 32767: from all lookup default
[root@mtr ~]# ip route show default via 192.168.0.0 dev eth0 proto dhcp metric 100 99.99.23.0/24 dev eth1 proto kernel scope link src 99.99.23.6 192.168.0.0/16 dev eth0 proto kernel scope link src 192.168.. metric 100
[root@mtr ~]# ip route show table net_252 default dev eth1 scope link
[root@mtr ~]# mtr -r -n -a 99.99.23.6 1.1.1.1
Use tcpdump to capture packets. It is found that packets are not sent from eth1 but from eth0. [root@mtr ~]# tcpdump -n -i eth0 icmp dropped privs to tcpdump tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes 11:21:34.060252 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33000, length 44 11:21:34.160450 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33001, length 44 11:21:34.260649 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33002, length 44 11:21:34.360844 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33003, length 44 11:21:34.461050 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33004, length 44 11:21:34.561246 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33005, length 44 11:21:34.661405 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33006, length 44 11:21:34.761648 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33007, length 44 11:21:34.861836 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33008, length 44 11:21:34.962096 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33009, length 44 11:21:35.062263 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33010, length 44 11:21:35.162424 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33011, length 44 11:21:35.262651 IP 99.99.23.6 > 1.1.1.1: ICMP echo request, id 7550, seq 33012, length 44
Do you have any plans to repair it?
I have the same problem, it looks like no one is going to solve it ....
My impression was that 7a0320038a64594c138e69b1200c30428bd1c75c fixed this issue. Instead of reporting issues about the mtr
included with your distro of choice, perhaps some of the people submitting complaints to this thread could try the latest from master and comment on whether or not it is indeed fixed when building from that commit, or more recent.
On Mon, Nov 20, 2023 at 04:16:22PM -0800, Matt Kimball wrote:
My impression was that 7a03200 fixed this issue.
My impression is that this patch has relation to "-I" option, while subject mentions "-a". Binding to source IP address and binding to interface (SO_BINDTODEVICE) are different things.
References
Visible links
-- Eugene Berdnikov
That fix was committed on 5th August 2022, however the last release of mtr
was v0.95 on 11th January 2022; therefore, the suggested fix has not made its way into any release as far as I can see.
Why not cut a release? It's been 2 years since 0.95. (Same problem with 0.95 in current OPNsense)
-a
or -I
and -M
work
Based on my tests --address
and --interface
in MTR 0.95 do not work (anymore) when used with source/policy based routing, such as two internet upstreams ("two default gateways"). For me it starts working for both when switching from ICMP to TCP using --tcp
.
Edit: MTR 0.95 with commit 74d312d (from #484) additionally applied works for me in the above scenario on Linux (without the workaround to switch from ICMP to TCP).
Option "-a|--address" does not work in package "mtr-tiny" (build without X11) on Debian Linux, version 0.92-1. Running under strace shows that program does NOT call bind(2).
Breif examination of source code from Github reveals that -a parameter value is assigned to ctl->InterfaceAddress, then is validated in net.c::net_validate_interface_address(), and never used later. Probably some piece of code was lost.
In previous mtr versions option "-a" worked as expected.