• Guillaume Nault's avatar
    udp: mask TOS bits in udp_v4_early_demux() · 8d2b51b0
    Guillaume Nault authored
    udp_v4_early_demux() is the only function that calls
    ip_mc_validate_source() with a TOS that hasn't been masked with
    IPTOS_RT_MASK.
    
    This results in different behaviours for incoming multicast UDPv4
    packets, depending on if ip_mc_validate_source() is called from the
    early-demux path (udp_v4_early_demux) or from the regular input path
    (ip_route_input_noref).
    
    ECN would normally not be used with UDP multicast packets, so the
    practical consequences should be limited on that side. However,
    IPTOS_RT_MASK is used to also masks the TOS' high order bits, to align
    with the non-early-demux path behaviour.
    
    Reproducer:
    
      Setup two netns, connected with veth:
      $ ip netns add ns0
      $ ip netns add ns1
      $ ip -netns ns0 link set dev lo up
      $ ip -netns ns1 link set dev lo up
      $ ip link add name veth01 netns ns0 type veth peer name veth10 netns ns1
      $ ip -netns ns0 link set dev veth01 up
      $ ip -netns ns1 link set dev veth10 up
      $ ip -netns ns0 address add 192.0.2.10 peer 192.0.2.11/32 dev veth01
      $ ip -netns ns1 address add 192.0.2.11 peer 192.0.2.10/32 dev veth10
    
      In ns0, add route to multicast address 224.0.2.0/24 using source
      address 198.51.100.10:
      $ ip -netns ns0 address add 198.51.100.10/32 dev lo
      $ ip -netns ns0 route add 224.0.2.0/24 dev veth01 src 198.51.100.10
    
      In ns1, define route to 198.51.100.10, only for packets with TOS 4:
      $ ip -netns ns1 route add 198.51.100.10/32 tos 4 dev veth10
    
      Also activate rp_filter in ns1, so that incoming packets not matching
      the above route get dropped:
      $ ip netns exec ns1 sysctl -wq net.ipv4.conf.veth10.rp_filter=1
    
      Now try to receive packets on 224.0.2.11:
      $ ip netns exec ns1 socat UDP-RECVFROM:1111,ip-add-membership=224.0.2.11:veth10,ignoreeof -
    
      In ns0, send packet to 224.0.2.11 with TOS 4 and ECT(0) (that is,
      tos 6 for socat):
      $ echo test0 | ip netns exec ns0 socat - UDP-DATAGRAM:224.0.2.11:1111,bind=:1111,tos=6
    
      The "test0" message is properly received by socat in ns1, because
      early-demux has no cached dst to use, so source address validation
      is done by ip_route_input_mc(), which receives a TOS that has the
      ECN bits masked.
    
      Now send another packet to 224.0.2.11, still with TOS 4 and ECT(0):
      $ echo test1 | ip netns exec ns0 socat - UDP-DATAGRAM:224.0.2.11:1111,bind=:1111,tos=6
    
      The "test1" message isn't received by socat in ns1, because, now,
      early-demux has a cached dst to use and calls ip_mc_validate_source()
      immediately, without masking the ECN bits.
    
    Fixes: bc044e8d ("udp: perform source validation for mcast early demux")
    Signed-off-by: default avatarGuillaume Nault <gnault@redhat.com>
    Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
    8d2b51b0
udp.c 82.1 KB