]> Cypherpunks.ru repositories - govpn.git/blobdiff - src/govpn/cmd/govpn-server/main.go
Raise copyright years
[govpn.git] / src / govpn / cmd / govpn-server / main.go
index 8aa26ec83bdb8878766fd28efd96c06f6a6e9d98..d9de06a2c6b24f0550872f729f299e89b9439415 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -16,82 +16,56 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-// Simple secure free software virtual private network daemon.
+// Simple secure, DPI/censorship-resistant free software VPN daemon.
 package main
 
 import (
-       "bytes"
        "flag"
        "log"
        "net"
        "os"
        "os/signal"
-       "path"
        "time"
 
        "govpn"
 )
 
 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", 1452, "MTU for outgoing packets")
+       bindAddr = flag.String("bind", "[::]:1194", "Bind to address")
+       proto    = flag.String("proto", "udp", "Protocol to use: udp, tcp or all")
+       confPath = flag.String("conf", "peers.json", "Path to configuration JSON")
+       stats    = flag.String("stats", "", "Enable stats retrieving on host:port")
+       proxy    = flag.String("proxy", "", "Enable HTTP proxy on host:port")
+       mtu      = flag.Int("mtu", 1452, "MTU for outgoing packets")
+       egdPath  = flag.String("egd", "", "Optional path to EGD socket")
 )
 
-type PeerReadyEvent struct {
-       peer  *govpn.Peer
-       iface string
-}
-
-type PeerState struct {
-       peer      *govpn.Peer
-       tap       *govpn.TAP
-       sink      chan []byte
-       ready     chan struct{}
-       terminate chan struct{}
-}
-
-func NewPeerState(peer *govpn.Peer, iface string) *PeerState {
-       tap, sink, ready, terminate, err := govpn.TAPListen(iface, peer.Timeout, peer.CPR)
-       if err != nil {
-               log.Println("Unable to create Eth", err)
-               return nil
-       }
-       state := PeerState{
-               peer:      peer,
-               tap:       tap,
-               sink:      sink,
-               ready:     ready,
-               terminate: terminate,
-       }
-       return &state
-}
-
-type EthEvent struct {
-       peer  *govpn.Peer
-       data  []byte
-       ready chan struct{}
-}
-
 func main() {
        flag.Parse()
        timeout := time.Second * time.Duration(govpn.TimeoutDefault)
-       var err error
        log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
+       log.Println(govpn.VersionGet())
 
        govpn.MTU = *mtu
-       govpn.PeersInit(*peersPath)
+       confInit()
+       knownPeers = govpn.KnownPeers(make(map[string]**govpn.Peer))
 
-       bind, err := net.ResolveUDPAddr("udp", *bindAddr)
-       if err != nil {
-               panic(err)
+       if *egdPath != "" {
+               log.Println("Using", *egdPath, "EGD")
+               govpn.EGDInit(*egdPath)
        }
-       conn, err := net.ListenUDP("udp", bind)
-       if err != nil {
-               panic(err)
+
+       switch *proto {
+       case "udp":
+               startUDP()
+       case "tcp":
+               startTCP()
+       case "all":
+               startUDP()
+               startTCP()
+       default:
+               log.Fatalln("Unknown protocol specified")
        }
-       udpSink, udpBuf, udpReady := govpn.ConnListen(conn)
 
        termSignal := make(chan os.Signal, 1)
        signal.Notify(termSignal, os.Interrupt, os.Kill)
@@ -99,36 +73,21 @@ func main() {
        hsHeartbeat := time.Tick(timeout)
        go func() { <-hsHeartbeat }()
 
-       var addr string
-       var state *govpn.Handshake
-       var peerState *PeerState
-       var peer *govpn.Peer
-       var exists bool
-       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
-       var ethEvent EthEvent
-       var peerId *govpn.PeerId
-       var peerConf *govpn.PeerConf
-       var handshakeProcessForce bool
-       ethSink := make(chan EthEvent)
-
-       log.Println(govpn.VersionGet())
        log.Println("Max MTU on TAP interface:", govpn.TAPMaxMTU())
        if *stats != "" {
                log.Println("Stats are going to listen on", *stats)
                statsPort, err := net.Listen("tcp", *stats)
                if err != nil {
-                       panic(err)
+                       log.Fatalln("Can not listen on stats port:", err)
                }
                go govpn.StatsProcessor(statsPort, &knownPeers)
        }
+       if *proxy != "" {
+               go proxyStart()
+       }
        log.Println("Server started")
 
+       var needsDeletion bool
 MainCycle:
        for {
                select {
@@ -136,129 +95,37 @@ MainCycle:
                        break MainCycle
                case <-hsHeartbeat:
                        now := time.Now()
-                       for addr, hs := range states {
+                       hsLock.Lock()
+                       for addr, hs := range handshakes {
                                if hs.LastPing.Add(timeout).Before(now) {
                                        log.Println("Deleting handshake state", addr)
                                        hs.Zero()
-                                       delete(states, addr)
+                                       delete(handshakes, addr)
                                }
                        }
-                       for addr, state := range peers {
-                               if state.peer.LastPing.Add(timeout).Before(now) {
-                                       log.Println("Deleting peer", state.peer)
+                       peersLock.Lock()
+                       peersByIdLock.Lock()
+                       kpLock.Lock()
+                       for addr, ps := range peers {
+                               ps.peer.BusyR.Lock()
+                               needsDeletion = ps.peer.LastPing.Add(timeout).Before(now)
+                               ps.peer.BusyR.Unlock()
+                               if needsDeletion {
+                                       log.Println("Deleting peer", ps.peer)
                                        delete(peers, addr)
                                        delete(knownPeers, addr)
-                                       downPath := path.Join(
-                                               govpn.PeersPath,
-                                               state.peer.Id.String(),
-                                               "down.sh",
+                                       delete(peersById, *ps.peer.Id)
+                                       go govpn.ScriptCall(
+                                               confs[*ps.peer.Id].Down,
+                                               ps.tap.Name,
                                        )
-                                       go govpn.ScriptCall(downPath, state.tap.Name)
-                                       state.terminate <- struct{}{}
-                                       state.peer.Zero()
+                                       ps.terminator <- struct{}{}
                                }
                        }
-               case peerReady = <-peerReadySink:
-                       for addr, state := range peers {
-                               if state.tap.Name != peerReady.iface {
-                                       continue
-                               }
-                               delete(peers, addr)
-                               delete(knownPeers, addr)
-                               state.terminate <- struct{}{}
-                               state.peer.Zero()
-                               break
-                       }
-                       addr = peerReady.peer.Addr.String()
-                       state := NewPeerState(peerReady.peer, peerReady.iface)
-                       if state == nil {
-                               continue
-                       }
-                       peers[addr] = state
-                       knownPeers[addr] = &peerReady.peer
-                       states[addr].Zero()
-                       delete(states, addr)
-                       log.Println("Registered interface", peerReady.iface, "with peer", peer)
-                       go func(state *PeerState) {
-                               for data := range state.sink {
-                                       ethSink <- EthEvent{
-                                               peer:  state.peer,
-                                               data:  data,
-                                               ready: state.ready,
-                                       }
-                               }
-                       }(state)
-               case ethEvent = <-ethSink:
-                       if s, exists := peers[ethEvent.peer.Addr.String()]; !exists || s.peer != ethEvent.peer {
-                               continue
-                       }
-                       ethEvent.peer.EthProcess(ethEvent.data, conn, ethEvent.ready)
-               case udpPkt = <-udpSink:
-                       if udpPkt.Addr == nil {
-                               udpReady <- struct{}{}
-                               continue
-                       }
-                       udpPktData = udpBuf[:udpPkt.Size]
-                       addr = udpPkt.Addr.String()
-                       handshakeProcessForce = false
-               HandshakeProcess:
-                       if _, exists = peers[addr]; handshakeProcessForce || !exists {
-                               peerId = govpn.IDsCache.Find(udpPktData)
-                               if peerId == nil {
-                                       log.Println("Unknown identity from", addr)
-                                       udpReady <- struct{}{}
-                                       continue
-                               }
-                               peerConf = peerId.Conf()
-                               if peerConf == nil {
-                                       log.Println("Can not get peer configuration", peerId.String())
-                                       udpReady <- struct{}{}
-                                       continue
-                               }
-                               state, exists = states[addr]
-                               if !exists {
-                                       state = govpn.HandshakeNew(udpPkt.Addr, peerConf)
-                                       states[addr] = state
-                               }
-                               peer = state.Server(conn, udpPktData)
-                               if peer != nil {
-                                       log.Println("Peer handshake finished", peer)
-                                       if _, exists = peers[addr]; exists {
-                                               go func() {
-                                                       peerReadySink <- PeerReadyEvent{peer, peers[addr].tap.Name}
-                                               }()
-                                       } else {
-                                               go func() {
-                                                       upPath := path.Join(govpn.PeersPath, peer.Id.String(), "up.sh")
-                                                       result, err := govpn.ScriptCall(upPath, "")
-                                                       if err != nil {
-                                                               return
-                                                       }
-                                                       sepIndex := bytes.Index(result, []byte{'\n'})
-                                                       if sepIndex < 0 {
-                                                               sepIndex = len(result)
-                                                       }
-                                                       ifaceName := string(result[:sepIndex])
-                                                       peerReadySink <- PeerReadyEvent{peer, ifaceName}
-                                               }()
-                                       }
-                               }
-                               if !handshakeProcessForce {
-                                       udpReady <- struct{}{}
-                               }
-                               continue
-                       }
-                       peerState, exists = peers[addr]
-                       if !exists {
-                               udpReady <- struct{}{}
-                               continue
-                       }
-                       // If it fails during processing, then try to work with it
-                       // as with handshake packet
-                       if !peerState.peer.UDPProcess(udpPktData, peerState.tap, udpReady) {
-                               handshakeProcessForce = true
-                               goto HandshakeProcess
-                       }
+                       hsLock.Unlock()
+                       peersLock.Unlock()
+                       peersByIdLock.Unlock()
+                       kpLock.Unlock()
                }
        }
 }