Exchange (DH-EKE) for mutual zero-knowledge peers authentication and
authenticated encrypted data transport. Other features include:
IPv4/IPv6, rehandshake, heartbeat, pre-shared authentication keys (PSK),
-perfect forward secrecy (PFS), replay attack protection.
-GNU/Linux and FreeBSD support.
+perfect forward secrecy (PFS), replay attack protection, JSON real-time
+statistics. GNU/Linux and FreeBSD support.
Home page: http://www.cypherpunks.ru/govpn/
also available as Tor hidden service: http://vabu56j2ep2rwv3b.onion/govpn/
keyPath = flag.String("key", "", "Path to authentication key file")
upPath = flag.String("up", "", "Path to up-script")
downPath = flag.String("down", "", "Path to down-script")
+ stats = flag.String("stats", "", "Enable stats retrieving on host:port")
mtu = flag.Int("mtu", 1500, "MTU")
nonceDiff = flag.Int("noncediff", 1, "Allow nonce difference")
timeoutP = flag.Int("timeout", 60, "Timeout seconds")
var ethPkt []byte
var udpPkt *govpn.UDPPkt
var udpPktData []byte
+ knownPeers := govpn.KnownPeers(map[string]**govpn.Peer{remote.String(): &peer})
+
+ log.Println(govpn.VersionGet())
+ if *stats != "" {
+ log.Println("Stats are going to listen on", *stats)
+ statsPort, err := net.Listen("tcp", *stats)
+ if err != nil {
+ panic(err)
+ }
+ go govpn.StatsProcessor(statsPort, &knownPeers)
+ }
termSignal := make(chan os.Signal, 1)
signal.Notify(termSignal, os.Interrupt, os.Kill)
- log.Println(govpn.VersionGet())
log.Println("Starting handshake")
handshake := govpn.HandshakeStart(conn, remote, id, key)
var (
bindAddr = flag.String("bind", "[::]:1194", "Bind to address")
peersPath = flag.String("peers", "peers", "Path to peers keys directory")
+ stats = flag.String("stats", "", "Enable stats retrieving on host:port")
mtu = flag.Int("mtu", 1500, "MTU")
nonceDiff = flag.Int("noncediff", 1, "Allow nonce difference")
timeoutP = flag.Int("timeout", 60, "Timeout seconds")
states := make(map[string]*govpn.Handshake)
peers := make(map[string]*PeerState)
peerReadySink := make(chan PeerReadyEvent)
+ knownPeers := govpn.KnownPeers(make(map[string]**govpn.Peer))
var peerReady PeerReadyEvent
var udpPkt *govpn.UDPPkt
var udpPktData []byte
ethSink := make(chan EthEvent)
log.Println(govpn.VersionGet())
+ if *stats != "" {
+ log.Println("Stats are going to listen on", *stats)
+ statsPort, err := net.Listen("tcp", *stats)
+ if err != nil {
+ panic(err)
+ }
+ go govpn.StatsProcessor(statsPort, &knownPeers)
+ }
log.Println("Server started")
MainCycle:
if state.peer.LastPing.Add(timeout).Before(now) {
log.Println("Deleting peer", state.peer)
delete(peers, addr)
+ delete(knownPeers, addr)
downPath := path.Join(
govpn.PeersPath,
state.peer.Id.String(),
continue
}
delete(peers, addr)
+ delete(knownPeers, addr)
state.terminate <- struct{}{}
state.peer.Zero()
break
continue
}
peers[addr] = state
+ knownPeers[addr] = &peerReady.peer
states[addr].Zero()
delete(states, addr)
log.Println("Registered interface", peerReady.iface, "with peer", peer)
the peers, not even it's hash value)
@item Built-in rehandshake and heartbeat features
@item Several simultaneous clients support
+@item Optional built-in HTTP-server for retrieving information about
+known connected peers in @url{http://json.org/, JSON} format
@end itemize
Optionally there can be @code{down.sh} that will be executed when client
disconnects, and @code{name} file containing human readable client's name.
+Each of them have ability to show statistics about known connected
+peers. If you specify @emph{host:port} in @code{-stats} argument, then
+it will run HTTP server on it, responding with JSON documents.
+
@menu
* Example usage::
@end menu
done
@end example
-FreeBSD IPv6 client-server example:
+FreeBSD IPv6 client-server example, with stats enabled on the server
+(localhost's 5678 port):
@example
server% cat > peers/CLIENTID/up.sh <<EOF
echo $tap
EOF
server% ifconfig em0 inet6 fe80::1/64
-server% GOMAXPROC=4 govpn-server -bind fe80::1%em0
+server% GOMAXPROC=4 govpn-server -bind fe80::1%em0 -stats [::1]:5678
@end example
@example
--- /dev/null
+package govpn
+
+import (
+ "encoding/json"
+ "log"
+ "net"
+ "time"
+)
+
+const (
+ RWTimeout = 10 * time.Second
+)
+
+type KnownPeers map[string]**Peer
+
+// StatsProcessor is assumed to be run in background. It accepts
+// connection on statsPort, reads anything one send to them and show
+// information about known peers in serialized JSON format. peers
+// argument is a reference to the map with references to the peers as
+// values. Map is used here because of ease of adding and removing
+// elements in it.
+func StatsProcessor(statsPort net.Listener, peers *KnownPeers) {
+ var conn net.Conn
+ var err error
+ var data []byte
+ buf := make([]byte, 2<<8)
+ for {
+ conn, err = statsPort.Accept()
+ if err != nil {
+ log.Println("Error during accepting connection", err.Error())
+ continue
+ }
+ conn.SetDeadline(time.Now().Add(RWTimeout))
+ conn.Read(buf)
+ conn.Write([]byte("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n"))
+ var peersList []*Peer
+ for _, peer := range *peers {
+ peersList = append(peersList, *peer)
+ }
+ data, err = json.Marshal(peersList)
+ if err != nil {
+ panic(err)
+ }
+ conn.Write(data)
+ conn.Close()
+ }
+}