From 66abfe58a15a089636d13253d078e8ab0f7c88bd Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 1 Jan 2025 11:43:44 +1100 Subject: [PATCH] sock: Allow binding outgoing connections to an interface The current "Bind" allows IP addresses which does not work with dynamically changing IPs such as VPN. Extend "Bind" to accept an interface name if SO_BINDTODEVICE is supported (Linux). For example, "Bind tun0". Signed-off-by: Alexey Kardashevskiy --- docs/man5/tinyproxy.conf.txt.in | 2 ++ etc/tinyproxy.conf.in | 2 +- src/conf.c | 6 +++++- src/main.c | 4 ++++ src/sock.c | 17 +++++++++++++++++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/man5/tinyproxy.conf.txt.in b/docs/man5/tinyproxy.conf.txt.in index 4471cbd..f43d826 100644 --- a/docs/man5/tinyproxy.conf.txt.in +++ b/docs/man5/tinyproxy.conf.txt.in @@ -60,6 +60,8 @@ This allows you to specify which address Tinyproxy will bind to for outgoing connections. This parameter may be specified multiple times, then Tinyproxy will try all the specified addresses in order. +When SO_BINDTODEVICE present, this parameter allows interface +names. =item B diff --git a/etc/tinyproxy.conf.in b/etc/tinyproxy.conf.in index b7d46a7..b3fc1b5 100644 --- a/etc/tinyproxy.conf.in +++ b/etc/tinyproxy.conf.in @@ -33,7 +33,7 @@ Port 8888 # Bind: This allows you to specify which interface will be used for # outgoing connections. This is useful for multi-home'd machines where # you want all traffic to appear outgoing from one particular interface. -# +# This allows using the name of an interface, useful for tun devices. #Bind 192.168.0.1 # diff --git a/src/conf.c b/src/conf.c index 372c73f..5b140f7 100644 --- a/src/conf.c +++ b/src/conf.c @@ -225,7 +225,11 @@ struct { handle_allow), STDCONF (deny, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", handle_deny), - STDCONF (bind, "(" IP "|" IPV6 ")", handle_bind), + STDCONF (bind, "(" IP "|" IPV6 +#ifdef SO_BINDTODEVICE + "|" INTERFACE +#endif + ")", handle_bind), /* other */ STDCONF (basicauth, USERNAME WS PASSWORD, handle_basicauth), STDCONF (errorfile, INT WS STR, handle_errorfile), diff --git a/src/main.c b/src/main.c index 268255f..4073d6e 100644 --- a/src/main.c +++ b/src/main.c @@ -145,6 +145,10 @@ display_usage (void) printf (" Upstream proxy support\n"); features++; #endif /* UPSTREAM_SUPPORT */ +#ifdef SO_BINDTODEVICE + printf (" BindToDevice\n"); + features++; +#endif if (0 == features) printf (" None\n"); diff --git a/src/sock.c b/src/sock.c index b3b0920..71c83b7 100644 --- a/src/sock.c +++ b/src/sock.c @@ -71,6 +71,23 @@ bind_socket (int sockfd, const char *addr, int family) assert (sockfd >= 0); assert (addr != NULL && strlen (addr) != 0); +#ifdef SO_BINDTODEVICE + if (addr && if_nametoindex(addr)) { + struct ifreq interface = {}; + + strcpy(interface.ifr_name, addr); + n = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, + &interface, sizeof(interface)); + if (n < 0) { + log_message (LOG_INFO, + "bind_socket: SO_BINDTODEVICE to %s %s", + addr, get_gai_error (n)); + return n; + } + return sockfd; + } +#endif + memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM;