+Release 2.2
+-----------
+* Fixed several possible channel deadlocks.
+
Release 2.1
-----------
* Fixed Linux-related building.
break MainCycle
case ethPkt = <-ethSink:
if peer == nil {
- ethReady <- struct{}{}
+ if len(ethPkt) > 0 {
+ ethReady <- struct{}{}
+ }
continue
}
peer.EthProcess(ethPkt, conn, ethReady)
}
}(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)
"encoding/hex"
"io/ioutil"
"log"
+ "os"
"os/exec"
)
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
cmd.Stdout = &out
@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:
@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::
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
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
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
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
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
.PHONY: govpn-client govpn-server
-VERSION=2.0
+VERSION=2.2
LDFLAGS=-X govpn.Version $(VERSION)
all: govpn-client govpn-server
)
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) {
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
sink := make(chan []byte)
sinkReady := make(chan struct{})
sinkTerminate := make(chan struct{})
+ sinkSkip := make(chan struct{})
go func() {
heartbeat := time.Tick(heartbeatPeriodGet())
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
}