From 7ee885a1f6776be85e5397eda04f75d98ff0b631 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Mon, 2 Apr 2018 16:33:14 +0200 Subject: [PATCH] Add the ability to set a firewall mark on sockets. The FWMark option is added, when set it will use setsockopt(SOL_SOCKET, SO_MARK) to set the given value as the mark on all sockets created by tinc. Thanks to Olivier Tirat for submitting a similar patch in the past. --- bash_completion.d/tinc | 2 +- doc/tinc.conf.5.in | 4 ++++ doc/tinc.texi | 6 ++++++ src/net.h | 1 + src/net_setup.c | 10 ++++++++++ src/net_socket.c | 25 +++++++++++++++++++++++++ src/tincctl.c | 1 + 7 files changed, 48 insertions(+), 1 deletion(-) diff --git a/bash_completion.d/tinc b/bash_completion.d/tinc index de2717ef..575f412a 100644 --- a/bash_completion.d/tinc +++ b/bash_completion.d/tinc @@ -4,7 +4,7 @@ _tinc() { cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" opts="-c -d -D -K -n -o -L -R -U --config --no-detach --debug --net --option --mlock --logfile --pidfile --chroot --user --help --version" - confvars="Address AddressFamily BindToAddress BindToInterface Broadcast BroadcastSubnet Cipher ClampMSS Compression ConnectTo DecrementTTL Device DeviceStandby DeviceType Digest DirectOnly Ed25519PrivateKeyFile Ed25519PublicKey Ed25519PublicKeyFile ExperimentalProtocol Forwarding GraphDumpFile Hostnames IffOneQueue IndirectData Interface InvitationExpire KeyExpire ListenAddress LocalDiscovery MACExpire MACLength MaxOutputBufferSize MaxTimeout Mode MTUInfoInterval Name PMTU PMTUDiscovery PingInterval PingTimeout Port PriorityInheritance PrivateKeyFile ProcessPriority Proxy PublicKeyFile ReplayWindow StrictSubnets Subnet TCPOnly TunnelServer UDPDiscovery UDPDiscoveryKeepaliveInterval UDPDiscoveryInterval UDPDiscoveryTimeout UDPInfoInterval UDPRcvBuf UDPSndBuf UPnP UPnPDiscoverWait UPnPRefreshPeriod VDEGroup VDEPort Weight" + confvars="Address AddressFamily BindToAddress BindToInterface Broadcast BroadcastSubnet Cipher ClampMSS Compression ConnectTo DecrementTTL Device DeviceStandby DeviceType Digest DirectOnly Ed25519PrivateKeyFile Ed25519PublicKey Ed25519PublicKeyFile ExperimentalProtocol Forwarding FWMark GraphDumpFile Hostnames IffOneQueue IndirectData Interface InvitationExpire KeyExpire ListenAddress LocalDiscovery MACExpire MACLength MaxOutputBufferSize MaxTimeout Mode MTUInfoInterval Name PMTU PMTUDiscovery PingInterval PingTimeout Port PriorityInheritance PrivateKeyFile ProcessPriority Proxy PublicKeyFile ReplayWindow StrictSubnets Subnet TCPOnly TunnelServer UDPDiscovery UDPDiscoveryKeepaliveInterval UDPDiscoveryInterval UDPDiscoveryTimeout UDPInfoInterval UDPRcvBuf UDPSndBuf UPnP UPnPDiscoverWait UPnPRefreshPeriod VDEGroup VDEPort Weight" commands="add connect debug del disconnect dump edit export export-all generate-ed25519-keys generate-keys generate-rsa-keys get help import info init invite join list log network pcap pid purge reload restart retry set sign start stop top verify version" case ${prev} in diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index ed9709a6..fa0f2fd0 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -312,6 +312,10 @@ This is less efficient, but allows the kernel to apply its routing and firewall and can also help debugging. Incoming packets using the SPTPS protocol are dropped, since they are end-to-end encrypted. .El +.It Va FWMark Li = Ar value Po 0 Pc Bq experimental +When set to a non-zero value, all TCP and UDP sockets created by tinc will use the given value as the firewall mark. +This can be used for mark-based routing or for packet filtering. +This option is currently only supported on Linux. .It Va Hostnames Li = yes | no Pq no This option selects whether IP addresses (both real and on the VPN) should be resolved. Since DNS lookups are blocking, it might affect tinc's diff --git a/doc/tinc.texi b/doc/tinc.texi index c9bda8e5..7a4d8b80 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -1055,6 +1055,12 @@ and can also help debugging. Incoming packets using the SPTPS protocol are dropped, since they are end-to-end encrypted. @end table +@cindex FWMark +@item FWMark = <@var{value}> (0) [experimental] +When set to a non-zero value, all TCP and UDP sockets created by tinc will use the given value as the firewall mark. +This can be used for mark-based routing or for packet filtering. +This option is currently only supported on Linux. + @cindex Hostnames @item Hostnames = (no) This option selects whether IP addresses (both real and on the VPN) diff --git a/src/net.h b/src/net.h index 90cbdbb4..d69eabda 100644 --- a/src/net.h +++ b/src/net.h @@ -148,6 +148,7 @@ extern int keylifetime; extern int udp_rcvbuf; extern int udp_sndbuf; extern int max_connection_burst; +extern int fwmark; extern bool do_prune; extern char *myport; extern bool device_standby; diff --git a/src/net_setup.c b/src/net_setup.c index 17675aec..455f66c6 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -949,6 +949,16 @@ static bool setup_myself(void) { } } + get_config_int(lookup_config(config_tree, "FWMark"), &fwmark); +#ifndef SO_MARK + + if(fwmark) { + logger(DEBUG_ALWAYS, LOG_ERR, "FWMark not supported on this platform!"); + return false; + } + +#endif + int replaywin_int; if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) { diff --git a/src/net_socket.c b/src/net_socket.c index cd6a5c2f..2da6253e 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -42,6 +42,7 @@ int seconds_till_retry = 5; int udp_rcvbuf = 1024 * 1024; int udp_sndbuf = 1024 * 1024; int max_connection_burst = 100; +int fwmark; listen_socket_t listen_socket[MAXSOCKETS]; int listen_sockets; @@ -85,6 +86,14 @@ static void configure_tcp(connection_t *c) { option = IPTOS_LOWDELAY; setsockopt(c->socket, IPPROTO_IPV6, IPV6_TCLASS, (void *)&option, sizeof(option)); #endif + +#if defined(SO_MARK) + + if(fwmark) { + setsockopt(c->socket, SOL_SOCKET, SO_MARK, (void *)&fwmark, sizeof(fwmark)); + } + +#endif } static bool bind_to_interface(int sd) { @@ -184,6 +193,14 @@ int setup_listen_socket(const sockaddr_t *sa) { #else #warning IPV6_V6ONLY not defined +#endif + +#if defined(SO_MARK) + + if(fwmark) { + setsockopt(nfd, SOL_SOCKET, SO_MARK, (void *)&fwmark, sizeof(fwmark)); + } + #endif if(get_config_string @@ -316,6 +333,14 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option)); } +#endif + +#if defined(SO_MARK) + + if(fwmark) { + setsockopt(nfd, SOL_SOCKET, SO_MARK, (void *)&fwmark, sizeof(fwmark)); + } + #endif if(!bind_to_interface(nfd)) { diff --git a/src/tincctl.c b/src/tincctl.c index 5ba71613..79762e3a 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -1695,6 +1695,7 @@ const var_t variables[] = { {"Ed25519PrivateKeyFile", VAR_SERVER}, {"ExperimentalProtocol", VAR_SERVER}, {"Forwarding", VAR_SERVER}, + {"FWMark", VAR_SERVER}, {"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE}, {"Hostnames", VAR_SERVER}, {"IffOneQueue", VAR_SERVER}, -- 2.20.1