JsBergbau / BindToInterface

With this program you can bind applications to a specific network interface / network adapter. This is very useful if you have multiple (internet) connections and want your program to use a specific one.
GNU Affero General Public License v3.0
113 stars 14 forks source link

allow source IP binding #12

Closed sh4dowb closed 1 year ago

sh4dowb commented 1 year ago

allow source IP binding for when there's multiple IPs on one interface

JsBergbau commented 1 year ago

Hi sh4dowb,

thanks for your contribution. I didn't test the code, but looks good so far.

Can you please add a section in Readme.md for documentation of the new env variable BIND_SOURCE_IP and then I'll merge the code.

Sorry for the late reply, was busy.

sh4dowb commented 1 year ago

done!

JsBergbau commented 1 year ago

Thanks.

On which operating system and kernel version are you using it? I did some tests. Basic IP binding works, when there are 2 IPs on eth0, but no other network connection on Debian 11 (Kernel 5.15.x). IP Binding doesn't work anymore on Debian 10 (Kernel 5.10.x) with multiple VPNs (wherefore I have developed it). Even with multiple IPs on eth0 and using the added IP for BIND_SOURCE_IP=192.168.178.199 it still gets out with the original IP of 192.168.178.150. When using an IP of VPN like LD_PRELOAD=./bindToInterface.so BIND_SOURCE_IP=10.8.0.6 curl ifconfig.me curl still gets the IP without VPN, whereas LD_PRELOAD=./bindToInterface.so BIND_INTERFACE=vpngr DNS_OVERRIDE_IP=8.8.8.8 curl ifconfig.me works as expected.

sh4dowb commented 1 year ago

Thanks.

On which operating system and kernel version are you using it? I did some tests. Basic IP binding works, when there are 2 IPs on eth0, but no other network connection on Debian 11 (Kernel 5.15.x). IP Binding doesn't work anymore on Debian 10 (Kernel 5.10.x) with multiple VPNs (wherefore I have developed it). Even with multiple IPs on eth0 and using the added IP for BIND_SOURCE_IP=192.168.178.199 it still gets out with the original IP of 192.168.178.150. When using an IP of VPN like LD_PRELOAD=./bindToInterface.so BIND_SOURCE_IP=10.8.0.6 curl ifconfig.me curl still gets the IP without VPN, whereas LD_PRELOAD=./bindToInterface.so BIND_INTERFACE=vpngr DNS_OVERRIDE_IP=8.8.8.8 curl ifconfig.me works as expected.

you still need to set the interface if it's not default, this is to set the source IP for when one interface has more than one IP address attached. in my case I have 5 IP addresses on enp4s0f0, and for example default IP is ....15

BIND_SOURCE_IP=xx.xx.xx.16 LD_PRELOAD=./bindToInterface.so curl ipinfo.io

this will return IP as ...16, without the module it returns ...15

it's my default interface, so I didn't need to set the interface as well. did you try supplying both interface and source ip variables? Ubuntu 22.04 LTS kernel 5.15.0-86

edit: curl --interface x.x.x.x does the same I guess, also try like that maybe?

JsBergbau commented 1 year ago

For eth0 I have

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.178.150  netmask 255.255.255.0  broadcast 192.168.178.255
        inet6 XXX  prefixlen 64  scopeid 0x20<link>
        ether XXX  txqueuelen 1000  (Ethernet)
        RX packets 38573107  bytes 23983577586 (22.3 GiB)
        RX errors 1  dropped 0  overruns 0  frame 0
        TX packets 33775751  bytes 25159929233 (23.4 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0:2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.178.199  netmask 255.255.255.0  broadcast 192.168.178.255
        ether XXXXX  txqueuelen 1000  (Ethernet)

eth0.18: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.180.1  netmask 255.255.255.0  broadcast 192.168.180.255
        inet6 XXX  prefixlen 64  scopeid 0x20<link>
        inet6 XXX  prefixlen 64  scopeid 0x20<link>
        ether XXX  txqueuelen 1000  (Ethernet)
        RX packets 43811  bytes 6205812 (5.9 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 61895  bytes 52962991 (50.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

LD_PRELOAD=./bindToInterface.so BIND_INTERFACE=eth0:2 BIND_SOURCE_IP=192.168.178.199 curl 192.168.178.40:6080 gives as IP 192.168.178.150. On the easier setup with the newer kernel, it is sufficient to use the IP of eth0:2 and this IP will be used.

sh4dowb commented 1 year ago

in my case I was testing with this setup:

2: enp1s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether xxx brd ff:ff:ff:ff:ff:ff
3: enp4s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether xxx brd ff:ff:ff:ff:ff:ff
    inet x.x.x.15/29 brd xxx scope global enp4s0f0
       valid_lft forever preferred_lft forever
    inet x.x.x.16/29 brd xxx scope global secondary enp4s0f0
       valid_lft forever preferred_lft forever
    inet x.x.x.17/29 brd xxx scope global secondary enp4s0f0
       valid_lft forever preferred_lft forever
    inet x.x.x.18/29 brd xxx scope global secondary enp4s0f0
       valid_lft forever preferred_lft forever
    inet x.x.x.19/29 brd xxx scope global secondary enp4s0f0
       valid_lft forever preferred_lft forever
4: enp4s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether xxx brd ff:ff:ff:ff:ff:ff
5: enp1s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether xxx brd ff:ff:ff:ff:ff:ff
root@server:~# curl myip.wtf/text
x.x.x.15
root@server:~# curl myip.wtf/text --interface x.x.x.16
x.x.x.16
root@server:~# LD_PRELOAD=./bindToInterface.so BIND_INTERFACE=enp4s0f0 BIND_SOURCE_IP=x.x.x.16 curl myip.wtf/text
x.x.x.16
JsBergbau commented 1 year ago

I've added a warning and merged the request. Thanks for your contribution.

sh4dowb commented 1 year ago

@JsBergbau just an idea, not sure if it's going to work but, can you try switching the order of interface/ip binding? I added ip binding after interface binding. the other way around might work better

JsBergbau commented 1 year ago

Changing the order of env variables doesn't make a difference. Shouldn't change anything in the runtime behavior, because both variables are set, when program executes.

sh4dowb commented 1 year ago

Changing the order of env variables doesn't make a difference. Shouldn't change anything in the runtime behavior, because both variables are set, when program executes.

I know, I mean in the program. Its currently setting the interface then IP, maybe switching the order will work