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 <aik@ozlabs.ru>
This commit is contained in:
Alexey Kardashevskiy 2025-01-01 11:43:44 +11:00 committed by Alexey Kardashevskiy
parent 1801e5c552
commit 66abfe58a1
5 changed files with 29 additions and 2 deletions

View File

@ -60,6 +60,8 @@ This allows you to specify which address Tinyproxy will bind
to for outgoing connections. to for outgoing connections.
This parameter may be specified multiple times, then Tinyproxy This parameter may be specified multiple times, then Tinyproxy
will try all the specified addresses in order. will try all the specified addresses in order.
When SO_BINDTODEVICE present, this parameter allows interface
names.
=item B<BindSame> =item B<BindSame>

View File

@ -33,7 +33,7 @@ Port 8888
# Bind: This allows you to specify which interface will be used for # Bind: This allows you to specify which interface will be used for
# outgoing connections. This is useful for multi-home'd machines where # outgoing connections. This is useful for multi-home'd machines where
# you want all traffic to appear outgoing from one particular interface. # 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 #Bind 192.168.0.1
# #

View File

@ -225,7 +225,11 @@ struct {
handle_allow), handle_allow),
STDCONF (deny, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", STDCONF (deny, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
handle_deny), handle_deny),
STDCONF (bind, "(" IP "|" IPV6 ")", handle_bind), STDCONF (bind, "(" IP "|" IPV6
#ifdef SO_BINDTODEVICE
"|" INTERFACE
#endif
")", handle_bind),
/* other */ /* other */
STDCONF (basicauth, USERNAME WS PASSWORD, handle_basicauth), STDCONF (basicauth, USERNAME WS PASSWORD, handle_basicauth),
STDCONF (errorfile, INT WS STR, handle_errorfile), STDCONF (errorfile, INT WS STR, handle_errorfile),

View File

@ -145,6 +145,10 @@ display_usage (void)
printf (" Upstream proxy support\n"); printf (" Upstream proxy support\n");
features++; features++;
#endif /* UPSTREAM_SUPPORT */ #endif /* UPSTREAM_SUPPORT */
#ifdef SO_BINDTODEVICE
printf (" BindToDevice\n");
features++;
#endif
if (0 == features) if (0 == features)
printf (" None\n"); printf (" None\n");

View File

@ -71,6 +71,23 @@ bind_socket (int sockfd, const char *addr, int family)
assert (sockfd >= 0); assert (sockfd >= 0);
assert (addr != NULL && strlen (addr) != 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)); memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = family; hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;