diff --git a/CHANGELOG.md b/CHANGELOG.md index 872c297..c8d4ebb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.2.5] - 2018-07-19 +### Changed +- Make `yggdrasilctl` less case sensitive +- More verbose TCP disconnect messages + +### Fixed +- Fixed debug builds +- Cap maximum MTU on Linux in TAP mode +- Process successfully-read TCP traffic before checking for / handling errors (fixes EOF behavior) + ## [0.2.4] - 2018-07-08 ### Added - Support for UNIX domain sockets for the admin socket using `unix:///path/to/file.sock` diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index cf56d41..0a7314c 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -309,7 +309,7 @@ func (a *admin) handleRequest(conn net.Conn) { handlers: for _, handler := range a.handlers { // We've found the handler that matches the request - if recv["request"] == handler.name { + if strings.ToLower(recv["request"].(string)) == strings.ToLower(handler.name) { // Check that we have all the required arguments for _, arg := range handler.args { // An argument in [square brackets] is optional and not required, diff --git a/src/yggdrasil/debug.go b/src/yggdrasil/debug.go index 564d59c..4cb1072 100644 --- a/src/yggdrasil/debug.go +++ b/src/yggdrasil/debug.go @@ -22,6 +22,8 @@ import "net/http" import "runtime" import "os" +import "yggdrasil/defaults" + // Start the profiler in debug builds, if the required environment variable is set. func init() { envVarName := "PPROFLISTEN" @@ -239,15 +241,15 @@ func (c *Core) DEBUG_getDHTSize() int { // TUN defaults func (c *Core) DEBUG_GetTUNDefaultIfName() string { - return getDefaults().defaultIfName + return defaults.GetDefaults().DefaultIfName } func (c *Core) DEBUG_GetTUNDefaultIfMTU() int { - return getDefaults().defaultIfMTU + return defaults.GetDefaults().DefaultIfMTU } func (c *Core) DEBUG_GetTUNDefaultIfTAPMode() bool { - return getDefaults().defaultIfTAPMode + return defaults.GetDefaults().DefaultIfTAPMode } // udpInterface diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 80ae284..3372fe6 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -17,6 +17,7 @@ package yggdrasil import ( "errors" "fmt" + "io" "math/rand" "net" "sync" @@ -304,38 +305,48 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { themAddrString := net.IP(themAddr[:]).String() themString := fmt.Sprintf("%s@%s", themAddrString, them) iface.core.log.Println("Connected:", themString) - iface.reader(sock, in) // In this goroutine, because of defers - iface.core.log.Println("Disconnected:", themString) + err = iface.reader(sock, in) // In this goroutine, because of defers + if err == nil { + iface.core.log.Println("Disconnected:", themString) + } else { + iface.core.log.Println("Disconnected:", themString, "with error:", err) + } return } // This reads from the socket into a []byte buffer for incomping messages. // It copies completed messages out of the cache into a new slice, and passes them to the peer struct via the provided `in func([]byte)` argument. // Then it shifts the incomplete fragments of data forward so future reads won't overwrite it. -func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) { +func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) error { bs := make([]byte, 2*tcp_msgSize) frag := bs[:0] for { timeout := time.Now().Add(tcp_timeout) sock.SetReadDeadline(timeout) n, err := sock.Read(bs[len(frag):]) - if err != nil || n == 0 { - break - } - frag = bs[:len(frag)+n] - for { - msg, ok, err := tcp_chop_msg(&frag) - if err != nil { - return + if n > 0 { + frag = bs[:len(frag)+n] + for { + msg, ok, err2 := tcp_chop_msg(&frag) + if err2 != nil { + return fmt.Errorf("Message error: %v", err2) + } + if !ok { + // We didn't get the whole message yet + break + } + newMsg := append(util_getBytes(), msg...) + in(newMsg) + util_yield() } - if !ok { - break - } // We didn't get the whole message yet - newMsg := append(util_getBytes(), msg...) - in(newMsg) - util_yield() + frag = append(bs[:0], frag...) + } + if err != nil || n == 0 { + if err != io.EOF { + return err + } + return nil } - frag = append(bs[:0], frag...) } } diff --git a/src/yggdrasil/tun_linux.go b/src/yggdrasil/tun_linux.go index 24c5aa9..a1f8abd 100644 --- a/src/yggdrasil/tun_linux.go +++ b/src/yggdrasil/tun_linux.go @@ -29,6 +29,18 @@ func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) } tun.iface = iface tun.mtu = getSupportedMTU(mtu) + // The following check is specific to Linux, as the TAP driver only supports + // an MTU of 65535-14 to make room for the ethernet headers. This makes sure + // that the MTU gets rounded down to 65521 instead of causing a panic. + if iftapmode { + if tun.mtu > 65535-tun_ETHER_HEADER_LENGTH { + tun.mtu = 65535-tun_ETHER_HEADER_LENGTH + } + } + // Friendly output + tun.core.log.Printf("Interface name: %s", tun.iface.Name()) + tun.core.log.Printf("Interface IPv6: %s", addr) + tun.core.log.Printf("Interface MTU: %d", tun.mtu) return tun.setupAddress(addr) } diff --git a/src/yggdrasil/tun_windows.go b/src/yggdrasil/tun_windows.go index c6e5770..d3420df 100644 --- a/src/yggdrasil/tun_windows.go +++ b/src/yggdrasil/tun_windows.go @@ -57,6 +57,10 @@ func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) if err != nil { panic(err) } + // Friendly output + tun.core.log.Printf("Interface name: %s", tun.iface.Name()) + tun.core.log.Printf("Interface IPv6: %s", addr) + tun.core.log.Printf("Interface MTU: %d", tun.mtu) return tun.setupAddress(addr) } diff --git a/yggdrasilctl.go b/yggdrasilctl.go index 6281b16..9d3fbb1 100644 --- a/yggdrasilctl.go +++ b/yggdrasilctl.go @@ -63,7 +63,7 @@ func main() { if i, err := strconv.Atoi(tokens[1]); err == nil { send[tokens[0]] = i } else { - switch tokens[1] { + switch strings.ToLower(tokens[1]) { case "true": send[tokens[0]] = true case "false": @@ -104,10 +104,10 @@ func main() { os.Exit(0) } - switch req["request"] { + switch strings.ToLower(req["request"].(string)) { case "dot": fmt.Println(res["dot"]) - case "help", "getPeers", "getSwitchPeers", "getDHT", "getSessions": + case "help", "getpeers", "getswitchpeers", "getdht", "getsessions": maxWidths := make(map[string]int) var keyOrder []string keysOrdered := false @@ -163,7 +163,7 @@ func main() { fmt.Println() } } - case "getTunTap", "setTunTap": + case "gettuntap", "settuntap": for k, v := range res { fmt.Println("Interface name:", k) if mtu, ok := v.(map[string]interface{})["mtu"].(float64); ok { @@ -173,7 +173,7 @@ func main() { fmt.Println("TAP mode:", tap_mode) } } - case "getSelf": + case "getself": for k, v := range res["self"].(map[string]interface{}) { fmt.Println("IPv6 address:", k) if subnet, ok := v.(map[string]interface{})["subnet"].(string); ok { @@ -183,7 +183,7 @@ func main() { fmt.Println("Coords:", coords) } } - case "addPeer", "removePeer", "addAllowedEncryptionPublicKey", "removeAllowedEncryptionPublicKey": + case "addpeer", "removepeer", "addallowedencryptionpublickey", "removeallowedencryptionpublickey": if _, ok := res["added"]; ok { for _, v := range res["added"].([]interface{}) { fmt.Println("Added:", fmt.Sprint(v)) @@ -204,7 +204,7 @@ func main() { fmt.Println("Not removed:", fmt.Sprint(v)) } } - case "getAllowedEncryptionPublicKeys": + case "getallowedencryptionpublickeys": if _, ok := res["allowed_box_pubs"]; !ok { fmt.Println("All connections are allowed") } else if res["allowed_box_pubs"] == nil { @@ -215,7 +215,7 @@ func main() { fmt.Println("-", v) } } - case "getMulticastInterfaces": + case "getmulticastinterfaces": if _, ok := res["multicast_interfaces"]; !ok { fmt.Println("No multicast interfaces found") } else if res["multicast_interfaces"] == nil {