]> Cypherpunks.ru repositories - govpn.git/blobdiff - src/govpn/cmd/govpn-server/main.go
Huge code refactoring
[govpn.git] / src / govpn / cmd / govpn-server / main.go
index 2aa5100e03627643da236dcc35c943903bc58ac9..dd338a2ce913dc596f3e29b98428aaf9bc1519f1 100644 (file)
@@ -16,11 +16,10 @@ 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"
@@ -42,48 +41,6 @@ var (
        egdPath   = flag.String("egd", "", "Optional path to EGD socket")
 )
 
-type Pkt struct {
-       addr  string
-       conn  govpn.RemoteConn
-       data  []byte
-       ready chan struct{}
-}
-
-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)
@@ -92,21 +49,21 @@ func main() {
 
        govpn.MTU = *mtu
        govpn.PeersInit(*peersPath)
+       knownPeers = govpn.KnownPeers(make(map[string]**govpn.Peer))
 
        if *egdPath != "" {
                log.Println("Using", *egdPath, "EGD")
                govpn.EGDInit(*egdPath)
        }
 
-       sink := make(chan Pkt)
        switch *proto {
        case "udp":
-               startUDP(sink)
+               startUDP()
        case "tcp":
-               startTCP(sink)
+               startTCP()
        case "all":
-               startUDP(sink)
-               startTCP(sink)
+               startUDP()
+               startTCP()
        default:
                log.Fatalln("Unknown protocol specified")
        }
@@ -117,22 +74,6 @@ func main() {
        hsHeartbeat := time.Tick(timeout)
        go func() { <-hsHeartbeat }()
 
-       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 pkt Pkt
-       var ethEvent EthEvent
-       var peerId *govpn.PeerId
-       var peerConf *govpn.PeerConf
-       var handshakeProcessForce bool
-       ethSink := make(chan EthEvent)
-
        log.Println("Max MTU on TAP interface:", govpn.TAPMaxMTU())
        if *stats != "" {
                log.Println("Stats are going to listen on", *stats)
@@ -143,10 +84,11 @@ func main() {
                go govpn.StatsProcessor(statsPort, &knownPeers)
        }
        if *proxy != "" {
-               go proxyStart(sink)
+               go proxyStart()
        }
        log.Println("Server started")
 
+       var needsDeletion bool
 MainCycle:
        for {
                select {
@@ -154,128 +96,39 @@ 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)
+                                       delete(peersById, *ps.peer.Id)
                                        downPath := path.Join(
                                                govpn.PeersPath,
-                                               state.peer.Id.String(),
+                                               ps.peer.Id.String(),
                                                "down.sh",
                                        )
-                                       go govpn.ScriptCall(downPath, state.tap.Name)
-                                       state.terminate <- struct{}{}
-                                       state.peer.Zero()
+                                       go govpn.ScriptCall(downPath, ps.tap.Name)
+                                       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
-                       }
-                       state := NewPeerState(peerReady.peer, peerReady.iface)
-                       if state == nil {
-                               continue
-                       }
-                       peers[peerReady.peer.Addr] = state
-                       knownPeers[peerReady.peer.Addr] = &peerReady.peer
-                       states[peerReady.peer.Addr].Zero()
-                       delete(states, peerReady.peer.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]; !exists || s.peer != ethEvent.peer {
-                               continue
-                       }
-                       ethEvent.peer.EthProcess(ethEvent.data, ethEvent.ready)
-               case pkt = <-sink:
-                       if pkt.data == nil {
-                               pkt.ready <- struct{}{}
-                               continue
-                       }
-                       handshakeProcessForce = false
-               HandshakeProcess:
-                       if _, exists = peers[pkt.addr]; handshakeProcessForce || !exists {
-                               peerId = govpn.IDsCache.Find(pkt.data)
-                               if peerId == nil {
-                                       log.Println("Unknown identity from", pkt.addr)
-                                       pkt.ready <- struct{}{}
-                                       continue
-                               }
-                               peerConf = peerId.Conf()
-                               if peerConf == nil {
-                                       log.Println("Can not get peer configuration", peerId.String())
-                                       pkt.ready <- struct{}{}
-                                       continue
-                               }
-                               state, exists = states[pkt.addr]
-                               if !exists {
-                                       state = govpn.HandshakeNew(pkt.addr, pkt.conn, peerConf)
-                                       states[pkt.addr] = state
-                               }
-                               peer = state.Server(pkt.data)
-                               if peer != nil {
-                                       log.Println("Peer handshake finished", peer)
-                                       if _, exists = peers[pkt.addr]; exists {
-                                               go func() {
-                                                       peerReadySink <- PeerReadyEvent{
-                                                               peer, peers[pkt.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 {
-                                       pkt.ready <- struct{}{}
-                               }
-                               continue
-                       }
-                       peerState, exists = peers[pkt.addr]
-                       if !exists {
-                               pkt.ready <- struct{}{}
-                               continue
-                       }
-                       // If it fails during processing, then try to work with it
-                       // as with handshake packet
-                       if !peerState.peer.PktProcess(pkt.data, peerState.tap, pkt.ready) {
-                               handshakeProcessForce = true
-                               goto HandshakeProcess
-                       }
+                       hsLock.Unlock()
+                       peersLock.Unlock()
+                       peersByIdLock.Unlock()
+                       kpLock.Unlock()
                }
        }
 }