From fd6f2e1f554cb545c7c554b56e2ac77308822680 Mon Sep 17 00:00:00 2001
From: Mathias Hall-Andersen <mathias@hall-andersen.dk>
Date: Tue, 17 Oct 2017 16:50:23 +0200
Subject: [PATCH] Fixed timer issue when failing to send handshake

+ Identified send4 issue
---
 src/conn_linux.go | 62 ++++++++++++++++++++++++++++++-----------------
 src/timers.go     | 27 +++++++++------------
 src/uapi.go       |  3 ++-
 3 files changed, 54 insertions(+), 38 deletions(-)

diff --git a/src/conn_linux.go b/src/conn_linux.go
index 4a5a3f0..51ca4f3 100644
--- a/src/conn_linux.go
+++ b/src/conn_linux.go
@@ -8,6 +8,7 @@ package main
 
 import (
 	"errors"
+	"fmt"
 	"golang.org/x/sys/unix"
 	"net"
 	"strconv"
@@ -31,14 +32,14 @@ type IPv4Source struct {
 	Ifindex int32
 }
 
-type Bind struct {
+type NativeBind struct {
 	sock4 int
 	sock6 int
 }
 
 func CreateUDPBind(port uint16) (UDPBind, uint16, error) {
 	var err error
-	var bind Bind
+	var bind NativeBind
 
 	bind.sock6, port, err = create6(port)
 	if err != nil {
@@ -52,7 +53,7 @@ func CreateUDPBind(port uint16) (UDPBind, uint16, error) {
 	return &bind, port, err
 }
 
-func (bind *Bind) SetMark(value uint32) error {
+func (bind *NativeBind) SetMark(value uint32) error {
 	err := unix.SetsockoptInt(
 		bind.sock6,
 		unix.SOL_SOCKET,
@@ -72,7 +73,7 @@ func (bind *Bind) SetMark(value uint32) error {
 	)
 }
 
-func (bind *Bind) Close() error {
+func (bind *NativeBind) Close() error {
 	err1 := unix.Close(bind.sock6)
 	err2 := unix.Close(bind.sock4)
 	if err1 != nil {
@@ -81,7 +82,7 @@ func (bind *Bind) Close() error {
 	return err2
 }
 
-func (bind *Bind) ReceiveIPv6(buff []byte, end *Endpoint) (int, error) {
+func (bind *NativeBind) ReceiveIPv6(buff []byte, end *Endpoint) (int, error) {
 	return receive6(
 		bind.sock6,
 		buff,
@@ -89,7 +90,7 @@ func (bind *Bind) ReceiveIPv6(buff []byte, end *Endpoint) (int, error) {
 	)
 }
 
-func (bind *Bind) ReceiveIPv4(buff []byte, end *Endpoint) (int, error) {
+func (bind *NativeBind) ReceiveIPv4(buff []byte, end *Endpoint) (int, error) {
 	return receive4(
 		bind.sock4,
 		buff,
@@ -97,14 +98,14 @@ func (bind *Bind) ReceiveIPv4(buff []byte, end *Endpoint) (int, error) {
 	)
 }
 
-func (bind *Bind) Send(buff []byte, end *Endpoint) error {
-	switch end.src.Family {
+func (bind *NativeBind) Send(buff []byte, end *Endpoint) error {
+	switch end.dst.Family {
 	case unix.AF_INET6:
 		return send6(bind.sock6, end, buff)
 	case unix.AF_INET:
 		return send4(bind.sock4, end, buff)
 	default:
-		return errors.New("Unknown address family of source")
+		return errors.New("Unknown address family of destination")
 	}
 }
 
@@ -288,12 +289,25 @@ func create6(port uint16) (int, uint16, error) {
 	return fd, uint16(addr.Port), err
 }
 
-func (end *Endpoint) Set(s string) error {
+func (end *Endpoint) SetDst(s string) error {
 	addr, err := parseEndpoint(s)
 	if err != nil {
 		return err
 	}
 
+	fmt.Println(addr, err)
+
+	ipv4 := addr.IP.To4()
+	if ipv4 != nil {
+		dst := (*unix.RawSockaddrInet4)(unsafe.Pointer(&end.dst))
+		dst.Family = unix.AF_INET
+		dst.Port = uint16(addr.Port)
+		dst.Zero = [8]byte{}
+		copy(dst.Addr[:], ipv4)
+		end.ClearSrc()
+		return nil
+	}
+
 	ipv6 := addr.IP.To16()
 	if ipv6 != nil {
 		zone, err := zoneToUint32(addr.Zone)
@@ -310,17 +324,6 @@ func (end *Endpoint) Set(s string) error {
 		return nil
 	}
 
-	ipv4 := addr.IP.To4()
-	if ipv4 != nil {
-		dst := (*unix.RawSockaddrInet4)(unsafe.Pointer(&end.dst))
-		dst.Family = unix.AF_INET
-		dst.Port = uint16(addr.Port)
-		dst.Zero = [8]byte{}
-		copy(dst.Addr[:], ipv4)
-		end.ClearSrc()
-		return nil
-	}
-
 	return errors.New("Failed to recognize IP address format")
 }
 
@@ -372,6 +375,8 @@ func send6(sock int, end *Endpoint, buff []byte) error {
 }
 
 func send4(sock int, end *Endpoint, buff []byte) error {
+	println("send 4")
+	println(end.DstToString())
 
 	// construct message header
 
@@ -403,7 +408,6 @@ func send4(sock int, end *Endpoint, buff []byte) error {
 		Namelen: unix.SizeofSockaddrInet4,
 		Control: (*byte)(unsafe.Pointer(&cmsg)),
 	}
-
 	msghdr.SetControllen(int(unsafe.Sizeof(cmsg)))
 
 	// sendmsg(sock, &msghdr, 0)
@@ -414,9 +418,23 @@ func send4(sock int, end *Endpoint, buff []byte) error {
 		uintptr(unsafe.Pointer(&msghdr)),
 		0,
 	)
+
+	println(sock)
+	fmt.Println(errno)
+
+	// clear source cache and try again
+
 	if errno == unix.EINVAL {
 		end.ClearSrc()
+		cmsg.pktinfo = unix.Inet4Pktinfo{}
+		_, _, errno = unix.Syscall(
+			unix.SYS_SENDMSG,
+			uintptr(sock),
+			uintptr(unsafe.Pointer(&msghdr)),
+			0,
+		)
 	}
+
 	return errno
 }
 
diff --git a/src/timers.go b/src/timers.go
index 2a94005..31165a3 100644
--- a/src/timers.go
+++ b/src/timers.go
@@ -279,34 +279,31 @@ func (peer *Peer) RoutineHandshakeInitiator() {
 				break AttemptHandshakes
 			}
 
-			jitter := time.Millisecond * time.Duration(rand.Uint32()%334)
-
-			// marshal and send
+			// marshal handshake message
 
 			writer := bytes.NewBuffer(temp[:0])
 			binary.Write(writer, binary.LittleEndian, msg)
 			packet := writer.Bytes()
 			peer.mac.AddMacs(packet)
 
+			// send to endpoint
+
 			err = peer.SendBuffer(packet)
-			if err != nil {
+			jitter := time.Millisecond * time.Duration(rand.Uint32()%334)
+			timeout := time.NewTimer(RekeyTimeout + jitter)
+			if err == nil {
+				peer.TimerAnyAuthenticatedPacketTraversal()
+				logDebug.Println(
+					"Handshake initiation attempt",
+					attempts, "sent to", peer.String(),
+				)
+			} else {
 				logError.Println(
 					"Failed to send handshake initiation message to",
 					peer.String(), ":", err,
 				)
-				continue
 			}
 
-			peer.TimerAnyAuthenticatedPacketTraversal()
-
-			// set handshake timeout
-
-			timeout := time.NewTimer(RekeyTimeout + jitter)
-			logDebug.Println(
-				"Handshake initiation attempt",
-				attempts, "sent to", peer.String(),
-			)
-
 			// wait for handshake or timeout
 
 			select {
diff --git a/src/uapi.go b/src/uapi.go
index 2de26ee..accffd1 100644
--- a/src/uapi.go
+++ b/src/uapi.go
@@ -247,7 +247,8 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
 				// set endpoint destination and reset handshake timer
 
 				peer.mutex.Lock()
-				err := peer.endpoint.value.Set(value)
+				err := peer.endpoint.value.SetDst(value)
+				fmt.Println(peer.endpoint.value.DstToString(), err)
 				peer.endpoint.set = (err == nil)
 				peer.mutex.Unlock()
 				if err != nil {