# VPN tunnels and "bind local address"



## PMc (Apr 24, 2021)

Nowadays most tools seem to have an option to specify the local address or local ip to use for a connection. 
Surprizingly, `git` doesn't (in http mode). So I asked this question here - let's see what comes out of it.

The background: when connecting two machines with `openvpn`, for a direct connection between both, the ip routing will select the tunnel address locally because that is the outgoing interface. But this is usually a private 10.x.x.x address - it is not supposed to be used anywhere. So, to make things working, one will likely end up configuring these private addresses _everywhere_: DNS, firewall, webserver, documentation... 

This is very undesireable. It is much nicer to tell the specific programs on the client that they should bind the regular local address. But that works only when the programs support it.
The other, more radical solution might be to always insert a NAT into both ending piers of a tunnel, for rewriting the respective address.

Ideas, improvements, comments, suggestions?


----------



## covacat (Apr 24, 2021)

use a http proxy that can specifiy bind address on its end and git thru the proxy


----------



## obsigna (Apr 24, 2021)

IP servers create sockets for binding to something for listening. IP clients create a socket and connect to servers. If you want, you perhaps can break this connection down into some sort of binding before, however this binding is not something which can be freely chosen like on the server side, since the client’s binding (if you insist on naming it as this) is determined by the IP address (or net) to which the client wants to connect.

That said, I fail to understand the rest of your problem. If the connection request from the git client does not want to go through your tunnel, then what is wrong with simply adjusting the routing table?

Look at it with `netstat -nr`, then add new routes using route(8).


----------



## PMc (Apr 24, 2021)

covacat said:


> use a http proxy that can specifiy bind address on its end and git thru the proxy


I agree, that would be a working solution. 
Only, I don't have a http proxy at hand on the client. I just went for the NAT solution - which then actually was a matter of copying two lines of config and entering five mouseclicks - as I have alreary enabled tooling that auto-creates `ipfw` rulesets with an arbitrary number of filters (blacklisters, nats, forwards...) - now finally this effort seems to pay off (the headless came up with no issue and worked).


----------



## PMc (Apr 24, 2021)

obsigna said:


> IP servers create a socket and bind to something for listening, IP clients create a socket and connect to servers. If you want, you perhaps can break this connection down into som sort of binding before, however this binding is not somthing which can be freely chosen as on the server side, since it is determined by the IP address (net) to which the client wants to connect.


From my experience it can be freely chosen amongst the locally configured IPs - only the client software must actively choose it instead accepting the default provided from the IP stack. It seems not to matter to which network the client then actually connects - I am rewriting and forwarding lots of things and actually do my own source-based routing from within `ipfw` - and all that works fine.


obsigna said:


> That said, I do not understand the rest of your problem. If the connection request from the git client does not want to go through your tunnel, then what is wrong with simply adjusting the routing table?


It is going thru the tunnel, and appears on the other side - with a client IP of `10.1.2.3` (which is the IP on the tun interface configured into openvpn).
Then any server that does any check on the client ip will not know that ip - because it is not the regular ip of the client (which it would use when going a different route). And any firewall that filters on rfc1918 does throw it away. So the consequence would be a configuration pain: making these tunnel ips known at every concerned place. That to avoid is the issue.


----------



## obsigna (Apr 24, 2021)

Well then this boils down to a matter of taste whether setting up NAT is more easy then one firewall rule like:
`ipfw -q add xyz allow ip from any to me via tun*`


----------



## PMc (Apr 24, 2021)

obsigna said:


> Well then this boils down to a matter of taste whether setting up NAT is more easy then one firewall rule like:
> `ipfw -q add xyz allow ip from any to me via tun*`


That would depend on the site configuration: specifically, this quoted rule would allow _everything from the Internet_ onto my machine. (That machine in question is my VPN server -etc etc- and you can reach it via that tunnel - to open another tunnel within that tunnel).


----------



## obsigna (Apr 25, 2021)

PMc said:


> That machine in question is my VPN server -etc etc- and you can reach it via that tunnel


I can reach your VPN server, really? You did not confuse the abbreviation VPN with Virtual Public Network, did you?


----------



## zirias@ (Apr 25, 2021)

See also: https://idea.popcount.org/2014-04-03-bind-before-connect/

It's talking a lot about Linux although little of this information is Linux specific. It contains a good summary at the end.


----------



## PMc (Apr 25, 2021)

Zirias said:


> See also: https://idea.popcount.org/2014-04-03-bind-before-connect/
> 
> It's talking a lot about Linux although little of this information is Linux specific. It contains a good summary at the end.



Now I get it: putting the bind-local-address option into a client program is not as simple as I thought; it is programming effort and it might introduce bottlenecks on the number of possible connections.
So one cannot expect this option to be available in any program one might want to use.


----------



## zirias@ (Apr 25, 2021)

Yep, that's the point. You _can_ bind(2) before you connect(2), but that's not the "normal" thing to do. So sure, it makes sense to offer such an option, but I wouldn't really expect such an option to be present. Normally, you should set up your networking in a way that doesn't require a specific client-side bind(2) for routing decisions


----------



## PMc (Apr 26, 2021)

Zirias said:


> Normally, you should set up your networking in a way that doesn't require a specific client-side bind(2) for routing decisions


Okay so far. And I certainly agree that issues should be solved where they arise, whenever possible, insead of spreading them around. So what is a good way to do so?

Let's look at a specific situation. Given there is such a layout of machines that should act in concert, but are not directly connected (I don't know if that is practically useful or should be done, it is just something we can look at and understand the matter):

```
|  ---------------                              ---------------
I |  | machine one |           openvpn            | machine three
N |--| official ip | ---------------------------- | official ip |
T |  |   1.2.3.1   |  10.0.1.1          10.0.1.2  |   1.2.3.3   |
E |  ---------------                              ---------------
R |
N |  ---------------                              ---------------
E |  | machine two |           openvpn            | machine four|
T |--| official ip | ---------------------------- | official ip |
  |  |   1.2.3.2   |  10.0.2.1          10.0.2.2  |   1.2.3.4   |
  |  ---------------                              ---------------
  |
  |.. and eventually more ...
   |
```

Now, when machine-one talks to machine-four, it uses it's regular IP, but when it talks to machine-three, it uses the local tunnel ip.
And any distributed application would need to know this: one cannot just say, the allowed peers are 1.2.3.0/24.


----------



## covacat (Apr 26, 2021)

just create a bogus route and use ipfw fwd
here is my setup
location1 is 10.1.1.0/24
location2 is 10.1.2.0/24
they are linked thru openvpn as
10.1.4.1 --> 10.1.4.2
the gw boxes are 10.1.1.1 and 10.1.2.1 which are also connected directly to the internet
now i telnet from 10.1.1.1 to 10.1.2.1 25
`telnet 10.1.2.1 25
Trying 10.1.2.1...
Connected to mail.box2.
Escape character is '^]'.
220 mail.box2 ESMTP of Borg. You will be assimilated; Mon, 26 Apr 2021 14:25:00 +0300 (EEST)
ehlo x
250-mail.box2 Hello [10.1.4.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING`
so the server sees my tunnel endpoint ip
now i add the bogus route
`route add 10.1.2.1 10.1.1.254
add host 10.1.2.1: gateway 10.1.1.254`
ping 10.1.2.1 normally times out because 10.1.1.254 does not exist / and does not even arp-resolve

now we force packets from 10.1.1.1 to 10.1.2.1 thru openvpn ignoring kernel route
`ipfw add 5 fwd 10.1.4.2 ip from 10.1.1.1 to 10.1.2.1
00005 fwd 10.1.4.2 ip from 10.1.1.1 to 10.1.2.1

telnet 10.1.2.1 25
Trying 10.1.2.1...
Connected to mail.box2
Escape character is '^]'.
220 mail.box2 ESMTP of Borg. You will be assimilated; Mon, 26 Apr 2021 14:32:58 +0300 (EEST)
ehlo x
250-mail.box2 Hello [10.1.1.1], pleased to meet you
250-ENHANCEDSTATUSCODES`
and im seen as 10.1.1.1

this was/is a common trick for ipsec ESP tunnels (create gif to get a tunnel-able ip without the need to specify a client bind address every time you needed to connect to services on the other part of the tunnel -- you just didn't need the ipfw fwd part because the ipsec policy was doing just that)


----------



## zirias@ (Apr 26, 2021)

PMc said:


> Now, when machine-one talks to machine-four, it uses it's regular IP, but when it talks to machine-three, it uses the local tunnel ip.
> And any distributed application would need to know this: one cannot just say, the allowed peers are 1.2.3.0/24.


Unless I'm missing something here, why not simply have a route to 1.2.3.3/32 via the tunnel on machine 1 and that's it (similar on machine 2)? You'll might need an OpenVPN `iroute` to go with that, but it shouldn't be a problem. Does the whole thing even work _without_ such a route?


----------



## covacat (Apr 26, 2021)

if 1.2.3.X are real public IPs and you just want traffic to be encrypted between you boxes its probably be easier to just use ipsec in transport mode and forget about tunnels


----------



## PMc (Apr 28, 2021)

covacat said:


> just create a bogus route and use ipfw fwd


That one does work, yes.



covacat said:


> if 1.2.3.X are real public IPs and you just want traffic to be encrypted between you boxes its probably be easier to just use ipsec in transport mode and forget about tunnels


In my case, I don't even care about the encryption, because it's public traffic. I just use the tunnels to move spare IP addresses to the place where I want to compute.


----------

