zehome / MLVPN

Multi-link VPN (ADSL/SDSL/xDSL/Network aggregation / bonding)
http://www.mlvpn.fr/
BSD 2-Clause "Simplified" License
518 stars 127 forks source link

Bind to device #70

Open markfoodyburton opened 8 years ago

markfoodyburton commented 8 years ago

I figured a ticket would help track this, I tried the bindztodev branch, and as you predicted, it doesn't work, for a number of reasons I haven't got to the bottom of it, but for a start, you need to run as root it seems which isn't ideal. Apart from that the branch works (but you need the same branch on both ends due to crypto).

Cheers

Mark.

zehome commented 8 years ago

That's because mlvpn uses UDP:

socket(7):

       SO_BINDTODEVICE
              Bind this socket to a particular device like “eth0”, as  specified  in  the  passed
              interface  name.   If the name is an empty string or the option length is zero, the
              socket device binding is removed.  The passed option is a variable-length null-ter‐
              minated  interface  name  string with the maximum size of IFNAMSIZ.  If a socket is
              bound to an interface, only packets received from  that  particular  interface  are
              processed by the socket.  Note that this works only for some socket types, particu‐
              larly AF_INET sockets.  It is not supported for packet sockets (use normal  bind(2)
              there).
stapelberg commented 8 years ago

I figured a ticket would help track this, I tried the bindztodev branch, and as you predicted, it doesn't work, for a number of reasons I haven't got to the bottom of it, but for a start, you need to run as root it seems which isn't ideal. Apart from that the branch works (but you need the same branch on both ends due to crypto).

Is there some more context? Where’s the prediction? What exactly doesn’t work?

I’ve also tried using SO_BINDTODEVICE and for me, it works once I also enable source-based routing:

ip rule add from 172.20.10.2 table 1
ip rule add from 10.0.0.218 table 2

ip route add 172.20.10.0/28 dev wlp4s0 scope link table 1
ip route add default via 172.20.10.1 dev wlp4s0 table 1

ip route add 10.0.0.0/24 dev enp0s25 scope link table 2
ip route add default via 10.0.0.1 dev enp0s25 table 2

ip route add default scope global nexthop via 10.0.0.1 dev enp0s25

(Where 172.20.10.2/28 is connected via WiFi to my iPhone, and 10.0.0.218/24 is connected via Ethernet.)

I haven’t understood yet why source-based routing is required. The symptom I’m seeing without source-based routing is that the mlvpn link never authenticates. While the response packets appear in tcpdump, the Linux kernel seems to not deliver the packet to mlvpn.

Reverse-path filtering is off for all interfaces:

net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.enp0s25.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.wlp4s0.rp_filter = 0

Any input appreciated.

markfoodyburton commented 8 years ago

I've lost the context a little, and in the end, I think it was my own stupidity. I was in the (random, and seemingly fortunate) position that Orange allocated my two ADSL lines different concentrators, I thought it was a good idea to have my firewall set up the two ppp interfaces using the concentrator to differentiate. And therefore, having mlvpn bind to those interfaces was ideal. It did work (for a while).... Then one day, Orange being Orange...... - I would advise anybody following not to do that. Hence the approach I'm taking now is to use the modem to make the connection (as per normal), I have each modem on a different sub-net, and MLVPN binds to each of the different IP addresses as per normal.

Hence, for me, I can no longer even test binding to devices - but from what I can remember, it worked ok.

(From my point of view, you can close this ticket).

Cheers

Mark

zehome commented 8 years ago

The problem with UDP is that it's not a connected protocol.

When mlvpn will try to send a packet outside, it will only tell the kernel the destination address, destination port and, enventually the bind address.

bind address is used because the kernel needs to know how to send the packet. What source IP address should it use?

By default, the kernel will lookup the destination address in the routing table, then if a source address is specified in the routing table, will choose this address (if bind address is not set) and send the packet.

Said otherwise, if you have the following:


CLIENT

NET1 -----\
           ------------------  SERVER IP
NET2 -----/

In that case, source routing is required because it's the only way to tell the kernel how to send a packet to the same destination two different ways. (By using the source routing system).

If you have two ip addresses on the same server on the other side, everything is much simplified. All you have to do is set two entries in the routing table with "src" set to the correct addresses.

Hope it clarifies a bit.

stapelberg commented 8 years ago

Managed to solve the issue I had in https://github.com/zehome/MLVPN/issues/70#issuecomment-235400270: Turns out that NixOS installs a rpfilter iptables rule (!) by default:

$ sudo iptables -nvL -t raw
Chain PREROUTING (policy ACCEPT 38644 packets, 67M bytes)
 pkts bytes target     prot opt in     out     source               destination         
 1762  274K DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            rpfilter invert

I wasn’t even aware there is a raw netfilter table or an rpfilter target, but once I removed that using sudo iptables -t raw -F, using SO_BINDTODEVICE works just fine, no source routing required.

stapelberg commented 8 years ago

So, with the issue I’ve had being resolved, I’d be very interested to see the SO_BINDTODEVICE code merged — in the setup I’m doing, the IP addresses will be assigned via DHCP, so I’d like to configure ethernet devices in the MLVPN config instead of IP addresses.

@zehome What needs to happen before the branch can get merged?