Hi,

so, as promised, more details on the route/iroute issues I saw...  with
a new Subject: line, to keep the threads halfway orderly.

On Sat, Aug 20, 2022 at 04:01:02PM +0200, Gert Doering wrote:
>  - route *deletion* does not work for IPv4 host routes, because of
>    "other code stupidity" - this is not a problem of your code, but
>    of an omission in dco.c (and I do wonder why this works for Linux)

A patch for *this* has been sent, so this is of no concern anymore
(just needs someone bold enough to ACK it).

>  - in one case I saw something that looks like a race condition between
>    DCO, "ifconfig route propagation", and "route add"

This is something I need to test further, to see if this was a one-off
issue, or can be reproduced with good timing.

>  - iroute installation works for the easy cases (--route in server.conf,
>    --iroute with a more-specific of that in ccd/).  It does not work
>    for the nasty cases (--route and --iroute with same netbits).
> 
>    I will send a followup e-mail with more details on this soon.

*This* is the bit I want to cover separately, because this e-mail is
going to be long :-)

So, here's my test cases, to see if I could get DCO to misbehave.

Server config has:

# grep ^route server.conf
route 10.114.200.0 255.255.255.0
route-ipv6 fd00:abcd:114:200::/64
route 10.114.201.0 255.255.255.0
route-ipv6 fd00:abcd:114:201::/64

("pull two /24 and two /64 towards the tun interface")

There is one particular client which has many addresses configured on
its loopback

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
        inet 10.114.200.74 netmask 0xffffffff 
        inet 10.114.201.74 netmask 0xffffffff 
        inet 10.114.202.74 netmask 0xffffffff 
        inet6 fd00:abcd:114:200::74 prefixlen 128 
        inet6 fd00:abcd:114:201::74 prefixlen 128 
        inet6 fd00:abcd:114:202::74 prefixlen 128 

... and when that client connects, the expectation is that *other* clients
can ping these 6 addresses (note it's 200, 201, 202 for v4 and v6).

Here's the ccd file for this client:

# cat /root/t_server/tun-udp-p2mp/ccd/freebsd-74-amd64
# Host iroute
iroute 10.114.200.74 255.255.255.255
iroute-ipv6 fd00:abcd:114:200::74/128
# Subnet-iroute
iroute 10.114.201.0 255.255.255.0
iroute-ipv6 fd00:abcd:114:201::/64
# iroute-without-route
# 10.114.202, fd00:abcd:114:202::/64
iroute 10.114.202.74 255.255.255.255
iroute-ipv6 fd00:abcd:114:202::74/128


So the "200" routes are "install a host route for IPv4 or IPv6 that is
part of an aggregate".  This works fine.

The "202" routes are "install a host route for IPv4 or IPv6 where there
is no covering --route" - this is basically something OpenVPN could not
do before DCO (update host routes on-demand on client connect), but is
something I've long waited for :-) - this also works fine.

Now, the 201 routes are "there whole network specified in --route is
routed to a single client".  This is not such an unusual setup in
cases like "there is a central office OpenVPN server, and one of the
branch offices wants it 192.168.77.0/24 reachable from the other 
clients".  This *fails*.

For IPv4, we end up with "netstat -rn" looking like this:

10.114.201.0/24    10.114.2.2         UGS        tun1
10.114.201.0/24    10.114.2.8         UGS        tun1

and "route get" telling us the the first one is preferred

$ route get 10.114.201.74
   route to: 10.114.201.74
destination: 10.114.201.0
       mask: 255.255.255.0
    gateway: 10.114.2.2
        fib: 0
  interface: tun1

so packets loop... (10.114.2.2 is not an address that belongs to an
actual client, but "the tun interface peer") the client is 10.114.2.8.

$ traceroute 10.114.201.74
traceroute to 10.114.201.74 (10.114.201.74), 64 hops max, 40 byte packets
 1  10.114.2.2 (10.114.2.2)  1.706 ms  1.240 ms  0.921 ms
 2  localhost (127.0.0.1)  0.865 ms  0.809 ms  0.807 ms
 3  10.114.2.2 (10.114.2.2)  1.603 ms  1.605 ms  1.595 ms
 4  localhost (127.0.0.1)  1.533 ms  1.383 ms  1.768 ms


For IPv6, things look different - route installation fails

2022-08-20 15:47:24 freebsd-74-amd64/2001:608:0:814::f000:3 /sbin/route -6 add 
-net fd00:abcd:114:201::/64 fd00:abcd:114:2::1006 -fib 0
add net fd00:abcd:114:201::/64: gateway fd00:abcd:114:2::1006 fib 0: route 
already in table

so, the iroute never makes it to kernel, "netstat -rn" remains at

fd00:abcd:114:201::/64            link#14                       US         tun1

and packets loop as well

$ traceroute6 fd00:abcd:114:201::74
traceroute6 to fd00:abcd:114:201::74 (fd00:abcd:114:201::74) from 
fd00:abcd:114:2::1, 64 hops max, 28 byte packets
 1  fd00:abcd:114:2::1000  1.749 ms  1.246 ms  0.930 ms
 2  fd00:abcd:114:2::1  0.836 ms  1.225 ms  1.067 ms
 3  fd00:abcd:114:2::1000  1.555 ms  1.631 ms  1.575 ms
 4  fd00:abcd:114:2::1  1.472 ms  1.531 ms  1.677 ms



So, what we do on *Linux* to handle this, is to work with route metrics
(10.220.* = "same instances, different host, so different address range")

linux$ ip route |grep tun1
10.220.200.0/24 via 10.220.2.2 dev tun1 metric 200 
10.220.200.74 via 10.220.2.8 dev tun1 metric 100 
10.220.201.0/24 via 10.220.2.8 dev tun1 metric 100 
10.220.201.0/24 via 10.220.2.2 dev tun1 metric 200 
10.220.202.74 via 10.220.2.8 dev tun1 metric 100 
linux$ ip -6 route |grep tun1
fd00:abcd:220:200::74 via fd00:abcd:220:2::1006 dev tun1 metric 100 pref medium
fd00:abcd:220:200::/64 dev tun1 metric 200 pref medium
fd00:abcd:220:201::/64 via fd00:abcd:220:2::1006 dev tun1 metric 100 pref medium
fd00:abcd:220:201::/64 dev tun1 metric 200 pref medium
fd00:abcd:220:202::74 via fd00:abcd:220:2::1006 dev tun1 metric 100 pref medium

so there's always 5 routes in the active table - 2 "--route" routes
(according to server.conf) with *metric 200*, and then 3 "--iroute" routes
(from ccd/) with metric DCO_IROUTE_METRIC = 100.

Linux handles this as would a "Cisco router" do - if there are two
identical routes with different metric, the lower-metric route is
used, and the other one is ignored.  So this works very nicely.


Now, back to FreeBSD.

  - our code does not try to set metrics on FreeBSD
  - my reading of route(8) does not show me anything in that direction 
    (metric, preference, administrative distance, ...)
  - I do not understand FreeBSD internals well enough to know whether 
    it can be done at all, or not.

If it can not be done, we need to document this as "one of the issues
with FreeBSD DCO", and it can of course be easily workarounded in most
cases

  --route 10.114.201.0/24
    --iroute 10.114.201.0/25
    --iroute 10.114.201.128/25

will get the same thing done "when client is online route the whole /25
down there", but it's harder to get into people's heads :-)  (adding
code to auto-split such a prefix is technically possible but would be 
quite a complication, so I'd rather solve this "with documentation").

So, what shall we do?

gert

-- 
"If was one thing all people took for granted, was conviction that if you 
 feed honest figures into a computer, honest figures come out. Never doubted 
 it myself till I met a computer with a sense of humor."
                             Robert A. Heinlein, The Moon is a Harsh Mistress

Gert Doering - Munich, Germany                             g...@greenie.muc.de

Attachment: signature.asc
Description: PGP signature

_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to