From 3f729c2fb4a84eeaa9444493d3369fb9e656cd1b Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 8 Oct 2018 00:05:37 +0100 Subject: [PATCH 1/2] Add DSCP classification to TCP --- src/yggdrasil/config/config.go | 1 + src/yggdrasil/core.go | 2 +- src/yggdrasil/tcp.go | 38 ++++++++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/yggdrasil/config/config.go b/src/yggdrasil/config/config.go index 5a081b68..fd399aa2 100644 --- a/src/yggdrasil/config/config.go +++ b/src/yggdrasil/config/config.go @@ -7,6 +7,7 @@ type NodeConfig struct { Peers []string `comment:"List of connection strings for static peers in URI format, i.e.\ntcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j."` InterfacePeers map[string][]string `comment:"List of connection strings for static peers in URI format, arranged\nby source interface, i.e. { \"eth0\": [ tcp://a.b.c.d:e ] }. Note that\nSOCKS peerings will NOT be affected by this option and should go in\nthe \"Peers\" section instead."` ReadTimeout int32 `comment:"Read timeout for connections, specified in milliseconds. If less\nthan 6000 and not negative, 6000 (the default) is used. If negative,\nreads won't time out."` + DSCPClassification uint8 `comment:"DSCP classification, in decimal, for applying Quality of Service\n(QoS) markings to outbound peering traffic. This value will more\nthan likely be ignored if peering over the Internet."` AllowedEncryptionPublicKeys []string `comment:"List of peer encryption public keys to allow or incoming TCP\nconnections from. If left empty/undefined then all connections\nwill be allowed by default."` EncryptionPublicKey string `comment:"Your public encryption key. Your peers may ask you for this to put\ninto their AllowedEncryptionPublicKeys configuration."` EncryptionPrivateKey string `comment:"Your private encryption key. DO NOT share this with anyone!"` diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 224bad99..9b531bd8 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -97,7 +97,7 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { c.init(&boxPub, &boxPriv, &sigPub, &sigPriv) c.admin.init(c, nc.AdminListen) - if err := c.tcp.init(c, nc.Listen, nc.ReadTimeout); err != nil { + if err := c.tcp.init(c, nc.Listen, nc.ReadTimeout, nc.DSCPClassification); err != nil { c.log.Println("Failed to start TCP interface") return err } diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 1942acd0..d9a08b22 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -24,6 +24,8 @@ import ( "sync/atomic" "time" + "golang.org/x/net/ipv4" + "golang.org/x/net/ipv6" "golang.org/x/net/proxy" ) @@ -47,6 +49,7 @@ type tcpInterface struct { mutex sync.Mutex // Protecting the below calls map[string]struct{} conns map[tcpInfo](chan struct{}) + dscp uint8 } // This is used as the key to a map that tracks existing connections, to prevent multiple connections to the same keys and local/remote address pair from occuring. @@ -74,9 +77,14 @@ func (iface *tcpInterface) connectSOCKS(socksaddr, peeraddr string) { } // Initializes the struct. -func (iface *tcpInterface) init(core *Core, addr string, readTimeout int32) (err error) { +func (iface *tcpInterface) init(core *Core, addr string, readTimeout int32, dscp uint8) (err error) { iface.core = core + // The DSCP value is 6-bit + if dscp >= 0 && dscp <= 63 { + iface.dscp = dscp + } + iface.tcp_timeout = time.Duration(readTimeout) * time.Millisecond if iface.tcp_timeout >= 0 && iface.tcp_timeout < default_tcp_timeout { iface.tcp_timeout = default_tcp_timeout @@ -164,7 +172,7 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string, sintf string) { if err != nil { return } else { - if ief.Flags & net.FlagUp == 0 { + if ief.Flags&net.FlagUp == 0 { return } addrs, err := ief.Addrs() @@ -197,6 +205,19 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string, sintf string) { return } } + // Configure DSCP on the connection, if set + if iface.dscp != 0 { + addr := conn.RemoteAddr().(*net.TCPAddr) + if addr.IP.To16() != nil && addr.IP.To4() == nil { + if err := ipv6.NewConn(conn).SetTrafficClass(int(iface.dscp << 2)); err != nil { + iface.core.log.Println("Failed to set traffic class:", err) + } + } else { + if err := ipv4.NewConn(conn).SetTOS(int(iface.dscp << 2)); err != nil { + iface.core.log.Println("Failed to set TOS:", err) + } + } + } iface.handler(conn, false) }() } @@ -223,6 +244,19 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { if err != nil { return } + // Configure DSCP on the connection, if set + if iface.dscp != 0 { + addr := sock.RemoteAddr().(*net.TCPAddr) + if addr.IP.To16() != nil && addr.IP.To4() == nil { + if err := ipv6.NewConn(sock).SetTrafficClass(int(iface.dscp << 2)); err != nil { + iface.core.log.Println("Failed to set traffic class:", err) + } + } else { + if err := ipv4.NewConn(sock).SetTOS(int(iface.dscp << 2)); err != nil { + iface.core.log.Println("Failed to set TOS:", err) + } + } + } meta = version_metadata{} // Reset to zero value if !meta.decode(metaBytes) || !meta.check() { // Failed to decode and check the metadata From 4f49d2622f0f32ee98ebb3a866993f35d3a85021 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 8 Oct 2018 00:10:30 +0100 Subject: [PATCH 2/2] Fix debug build with DSCP --- src/yggdrasil/debug.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yggdrasil/debug.go b/src/yggdrasil/debug.go index 892529b6..eea91840 100644 --- a/src/yggdrasil/debug.go +++ b/src/yggdrasil/debug.go @@ -427,7 +427,7 @@ func (c *Core) DEBUG_addSOCKSConn(socksaddr, peeraddr string) { //* func (c *Core) DEBUG_setupAndStartGlobalTCPInterface(addrport string) { - if err := c.tcp.init(c, addrport, 0); err != nil { + if err := c.tcp.init(c, addrport, 0, 0); err != nil { c.log.Println("Failed to start TCP interface:", err) panic(err) }