On 12/4/25 09:18, Nicolas Cavallari wrote:
On 12/3/25 23:55, Sławomir Zborowski wrote:
 > There's not really such a thing as an "inet interface" or an "inet6
 > interface" an interface, represented by an index, can have multiple
 > addresses, both IPv4 and IPv6.

You're right. That was imprecise mental shortcut.

 > What I would expect to see here is that the interface had both IPv4
 > addresses and IPv6 addresses when it was added to the daemon- >interfaces  > list, so this check will find at least one entry on that list which came
 > from the arrival interface and has the correct address family.

The thing is it only has the IPv6 address. This is how Calico (or the OS
- I'm not entirely sure) configures it.

 > Your description implies that the TCP connection is over IPv4. Does the
 > interface is arrives on have an IP4 address?

Destination is a regular eth0 iface on the server with IPv4 address only.
The connection originates from a Pod that is connected through veth pair.
That veth pair has only IPv6 address in the system.

 > As usual, the most useful resource here is the simplest configuration
 > which demonstrates this problem on the most vanilla kernel network
 > configuration.

I'm not sure if that's the most vanilla way out there, but I believe that
Calico does something along following. I'm not sure if the proxy_arp
thing is necessary. With following I was able to reproduce the problem.

# ip netns add fakepod
# ip link add host-veth type veth peer name pod-veth
# ip link set pod-veth netns fakepod
# ip link set host-veth up
# echo 1 | sudo tee /proc/sys/net/ipv4/conf/host-veth/proxy_arp
# ip netns exec fakepod bash
# ip link set lo up
# ip link set pod-veth up
# ip addr add 10.44.0.51/32 <http://10.44.0.51/32> dev pod-veth
# ip route add default dev pod-veth
# ip route add 169.254.1.1/32 <http://169.254.1.1/32> dev pod-veth
# exit
# ip route add 10.44.0.51/32 <http://10.44.0.51/32> dev host-veth

Now, start dnsmasq on the host:
# sudo ./src/dnsmasq -d --log-debug 2>&1 | tee /tmp/dnsmasq.log

And trigger the behavior:
# ip netns exec fakepod dig duckduckgo.com <http://duckduckgo.com>. A +tcp @[REDACTED: server eth0 physical IPv4 address] ;; communications error to [REDACTED: server eth0 physical IPv4 address]#53: end of file

;; communications error to [REDACTED: server eth0 physical IPv4 address]#53: end of file

This is, by the way, how the iface shows up in the system:
266: host-veth@if265: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000      link/ether d6:35:97:b9:51:f0 brd ff:ff:ff:ff:ff:ff link-netns fakepod
     inet6 fe80::d435:97ff:feb9:51f0/64 scope link
        valid_lft forever preferred_lft forever

And dnsmasq will recognize it as IPv6. I added some debug prints
to verify that it happens. Incoming TCP addr sa_family is 0x2, iface
sa_family is 0xA.

I think the IPv6 address that is attached to the veth host end is added
by the OS.

Hopefully all of the above is helpful.

So basically, dnsmasq receives a TCP connection from 10.44.0.51 to [redacted] through the host-veth interface, but the host-veth interface only have a ipv6 link-local and no ipv4.  [redacted] is actually configured on eth0.

It is quite difficult for a TCP server to know from which an interface a request comes from. Finding the interface where the destination address was configured only works on systems with a strong host model, but linux uses a weak host model and your setup rely on it.

A weak host model system will accept packets from 10.44.0.51 to [redacted] regardless of the interface the packet came from.  And replies are sent to whatever interface the FIB says should be used and the interface may change over time.

A workaround would be to use RTM_GETROUTE on the source address and consider that as the interface the request came from, but that could cause other problems.


[This is a reply to both Sławomir's second email and Nicolas's email. It's easier to reply to Nicolas's since the information he provides is highly pertinent.]

The aim of the code in question is to only accept TCP connections which arrive via an allowed interface, when the set of allowed interfaces is configured using --interface=<name> and --address=<ip> options to dnsmasq.

Ideally UDP using a single, wildcard-bound socket, UDP with a socket for each address, and TCP should work the same.

TCP is kind of difficult, and looking at this code, it's more complicated than it needs to be, and (as Sławomir found) it doesn't behave the same as UDP.

I think I can improve this to solve the problem, but I'm definitely not going to try and do that for the 2.92 release. This is the sort of thing that's very difficult to fix without breaking some installations. Even if you make the behaviour better, there will always be someone who is inadvertently relying on the old, broken behaviour.


TL;DR  Sławomir, you can remove the

  iface->addr.sa.sa_family == tcp_addr.sa.sa_family


condition, which should fix your immediate problem without undesirable side-affects. I'll work on improving this code, and push somethingout one 2.92 is released.


Cheers,

Simon.

_______________________________________________
Dnsmasq-discuss mailing list
[email protected]
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss


_______________________________________________
Dnsmasq-discuss mailing list
[email protected]
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to