NEWS | 4 ++++ cmd/govpn-client/main.go | 4 +++- cmd/govpn-server/main.go | 2 +- common.go | 4 ++++ doc/download.texi | 4 ++-- doc/govpn.texi | 15 +++++++++------ makefile | 2 +- tap.go | 22 ++++++++++++---------- transport.go | 20 +++++++++++++------- diff --git a/NEWS b/NEWS index b56beacaddb7e660ecb0a56a59d78e003cd15e62..4500296c5f9358219e153fb49057ef65b2be6b26 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Release 2.2 +----------- +* Fixed several possible channel deadlocks. + Release 2.1 ----------- * Fixed Linux-related building. diff --git a/cmd/govpn-client/main.go b/cmd/govpn-client/main.go index e358d43f8b82dad67ad9c6de2bfc4afeffbf3422..f4a29eb82d2aea2a23d3fdb5eaad906cf41e677d 100644 --- a/cmd/govpn-client/main.go +++ b/cmd/govpn-client/main.go @@ -102,7 +102,9 @@ case <-termSignal: break MainCycle case ethPkt = <-ethSink: if peer == nil { - ethReady <- struct{}{} + if len(ethPkt) > 0 { + ethReady <- struct{}{} + } continue } peer.EthProcess(ethPkt, conn, ethReady) diff --git a/cmd/govpn-server/main.go b/cmd/govpn-server/main.go index f628244189ebe78b4468514443fec795f78ff96f..4fa5c96f8baa184c350e4362178b196dc14f1009 100644 --- a/cmd/govpn-server/main.go +++ b/cmd/govpn-server/main.go @@ -172,7 +172,7 @@ } } }(state) case ethEvent = <-ethSink: - if _, exists := peers[ethEvent.peer.Addr.String()]; !exists { + if s, exists := peers[ethEvent.peer.Addr.String()]; !exists || s.peer != ethEvent.peer { continue } ethEvent.peer.EthProcess(ethEvent.data, conn, ethEvent.ready) diff --git a/common.go b/common.go index b38f52b1d282035c6390daa22e6681dd7f84627a..b42673c98925f32be3b63948f7eaf30eccb186e9 100644 --- a/common.go +++ b/common.go @@ -23,6 +23,7 @@ "bytes" "encoding/hex" "io/ioutil" "log" + "os" "os/exec" ) @@ -40,6 +41,9 @@ // it's output and possible error. func ScriptCall(path, ifaceName string) ([]byte, error) { if path == "" { return nil, nil + } + if _, err := os.Stat(path); err != nil && os.IsNotExist(err) { + return nil, err } cmd := exec.Command(path, ifaceName) var out bytes.Buffer diff --git a/doc/download.texi b/doc/download.texi index d2ad657bf8368bad5538dc21b5ca769a979a439f..e0ae00d035748093430cc91ed148a72436adb406 100644 --- a/doc/download.texi +++ b/doc/download.texi @@ -8,8 +8,8 @@ @item 1.5 @tab 19 KiB @tab @url{download/govpn-1.5.tar.xz, link} @url{download/govpn-1.5.tar.xz.sig, sign} @item 2.0 @tab 31 KiB @tab @url{download/govpn-2.0.tar.xz, link} @url{download/govpn-2.0.tar.xz.sig, sign} -@item 2.1 @tab 32 KiB -@tab @url{download/govpn-2.1.tar.xz, link} @url{download/govpn-2.1.tar.xz.sig, sign} +@item 2.2 @tab 32 KiB +@tab @url{download/govpn-2.2.tar.xz, link} @url{download/govpn-2.2.tar.xz.sig, sign} @end multitable Sourceforge.net also provides mirror for the files above: diff --git a/doc/govpn.texi b/doc/govpn.texi index 9c53ba5b4214804d1ce44dec01b648ae8f704de6..3bdf72faddc3ccb254c9dfed48cad765bcec2600 100644 --- a/doc/govpn.texi +++ b/doc/govpn.texi @@ -17,13 +17,11 @@ GNU General Public License for more details. @end quotation @end copying -@ifnottex @node Top @top GoVPN This manual is for GoVPN -- simple secure free software virtual private network (VPN) daemon, written entirely on Go programming language. -@end ifnottex @menu * Overview:: @@ -202,6 +200,9 @@ transport. MTU for that wlan0 is 1500 bytes. GoVPN will say that maximum MTU for the link is 1476, however it does not take in account TAP's Ethernet frame header length, that in my case is 14 bytes long (1476 - 14). +Do not forget about setting @code{GOMAXPROC} environment variable for +using more than one CPU. + GNU/Linux IPv4 client-server example: @example @@ -216,7 +217,7 @@ server% tunctl -t tap10 server% ip link set mtu 1462 dev tap10 server% ip addr add 172.16.0.1/24 dev tap10 server% ip link set up dev tap10 -server% govpn -bind 192.168.0.1:1194 +server% GOMAXPROC=4 govpn-server -bind 192.168.0.1:1194 @end example @example @@ -228,8 +229,9 @@ client% ip link set mtu 1462 dev tap10 client% ip addr add 172.16.0.2/24 dev tap10 client% ip link set up dev tap10 client% ip route add default via 172.16.0.1 +client% export GOMAXPROC=4 client% while :; do - govpn -key key.txt -id CLIENTID -iface tap10 -remote 192.168.0.1:1194 + govpn-client -key key.txt -id CLIENTID -iface tap10 -remote 192.168.0.1:1194 done @end example @@ -248,7 +250,7 @@ echo $tap EOF server% chmod 500 peers/CLIENTID/up.sh server% ifconfig em0 inet6 fe80::1/64 -server% govpn -bind fe80::1%em0 +server% GOMAXPROC=4 govpn-server -bind fe80::1%em0 @end example @example @@ -256,8 +258,9 @@ client% ifconfig me0 inet6 -ifdisabled auto_linklocal client% ifconfig tap10 client% ifconfig tap10 inet6 fc00::2/96 mtu 1462 up client% route -6 add default fc00::1 +client% export GOMAXPROC=4 client% while :; do - govpn -key key.txt -id CLIENTID -iface tap10 -remote [fe80::1%me0]:1194 + govpn-client -key key.txt -id CLIENTID -iface tap10 -remote [fe80::1%me0]:1194 done @end example diff --git a/makefile b/makefile index b1e4229e7ceed501f81973c4850a07d3b0c9326b..59f148ee059bce4cdc7fa51580febd630f065e7f 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ .PHONY: govpn-client govpn-server -VERSION=2.0 +VERSION=2.2 LDFLAGS=-X govpn.Version $(VERSION) all: govpn-client govpn-server diff --git a/tap.go b/tap.go index 85926d7df9d1c4d290f85c77408251de0e50f417..4fee83a28c3ea920cb619da22a1a9ddc984d71e7 100644 --- a/tap.go +++ b/tap.go @@ -26,11 +26,12 @@ "golang.org/x/crypto/poly1305" ) type TAP struct { - Name string - dev io.ReadWriter - buf []byte - sink chan []byte - ready chan struct{} + Name string + dev io.ReadWriter + buf []byte + sink chan []byte + ready chan struct{} + synced bool } func NewTAP(ifaceName string) (*TAP, error) { @@ -40,11 +41,12 @@ if err != nil { return nil, err } tap := TAP{ - Name: ifaceName, - dev: tapRaw, - buf: make([]byte, maxIfacePktSize), - sink: make(chan []byte), - ready: make(chan struct{}), + Name: ifaceName, + dev: tapRaw, + buf: make([]byte, maxIfacePktSize), + sink: make(chan []byte), + ready: make(chan struct{}), + synced: false, } go func() { var n int diff --git a/transport.go b/transport.go index 3c460e61926c44d1c812f16a0c5377fac6ee25de..d72fcc15ea140c74584514dd380fbc3fe6dea607 100644 --- a/transport.go +++ b/transport.go @@ -102,6 +102,7 @@ } sink := make(chan []byte) sinkReady := make(chan struct{}) sinkTerminate := make(chan struct{}) + sinkSkip := make(chan struct{}) go func() { heartbeat := time.Tick(heartbeatPeriodGet()) @@ -112,29 +113,34 @@ select { case <-sinkTerminate: break ListenCycle case <-heartbeat: - sink <- make([]byte, 0) + go func() { sink <- make([]byte, 0) }() continue + case <-sinkSkip: case <-sinkReady: - if exists { - exists = false - break - } tap.ready <- struct{}{} + tap.synced = true } HeartbeatCatched: select { case <-heartbeat: - sink <- make([]byte, 0) + go func() { sink <- make([]byte, 0) }() goto HeartbeatCatched case <-sinkTerminate: break ListenCycle case pkt = <-tap.sink: + tap.synced = false sink <- pkt } } close(sink) + close(sinkReady) + close(sinkTerminate) }() - sinkReady <- struct{}{} + if exists && tap.synced { + sinkSkip <- struct{}{} + } else { + sinkReady <- struct{}{} + } return tap, sink, sinkReady, sinkTerminate, nil }