]> Cypherpunks.ru repositories - govpn.git/blobdiff - src/govpn/cmd/govpn-server/udp.go
Raise copyright years
[govpn.git] / src / govpn / cmd / govpn-server / udp.go
index d5e12968a8b4191b109ae9f13d7ed2e268f40ec5..e05f44d96e71011d7d49ac09618e25d35686104d 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
@@ -21,7 +21,6 @@ package main
 import (
        "log"
        "net"
-       "time"
 
        "govpn"
 )
@@ -35,38 +34,161 @@ func (c UDPSender) Write(data []byte) (int, error) {
        return c.conn.WriteToUDP(data, c.addr)
 }
 
-func startUDP() chan Pkt {
+var (
+       // Buffers for UDP parallel processing
+       udpBufs chan []byte = make(chan []byte, 1<<8)
+)
+
+func startUDP() {
        bind, err := net.ResolveUDPAddr("udp", *bindAddr)
-       ready := make(chan struct{})
        if err != nil {
                log.Fatalln("Can not resolve bind address:", err)
        }
-       lconn, err := net.ListenUDP("udp", bind)
+       conn, err := net.ListenUDP("udp", bind)
        if err != nil {
                log.Fatalln("Can not listen on UDP:", err)
        }
-       sink := make(chan Pkt)
+       log.Println("Listening on UDP:" + *bindAddr)
+
+       udpBufs <- make([]byte, govpn.MTU)
        go func() {
-               buf := make([]byte, govpn.MTU)
-               var n int
+               var buf []byte
                var raddr *net.UDPAddr
+               var addr string
+               var n int
                var err error
+               var ps *PeerState
+               var hs *govpn.Handshake
+               var addrPrev string
+               var exists bool
+               var peerId *govpn.PeerId
+               var peer *govpn.Peer
+               var conf *govpn.PeerConf
                for {
-                       <-ready
-                       lconn.SetReadDeadline(time.Now().Add(time.Second))
-                       n, raddr, err = lconn.ReadFromUDP(buf)
+                       buf = <-udpBufs
+                       n, raddr, err = conn.ReadFromUDP(buf)
                        if err != nil {
-                               sink <- Pkt{ready: ready}
-                               continue
+                               log.Println("Unexpected error when receiving", err)
+                               break
+                       }
+                       addr = raddr.String()
+
+                       peersLock.RLock()
+                       ps, exists = peers[addr]
+                       peersLock.RUnlock()
+                       if !exists {
+                               goto CheckHandshake
+                       }
+                       go func(ps *govpn.Peer, tap *govpn.TAP, buf []byte, n int) {
+                               peer.PktProcess(buf[:n], tap, true)
+                               udpBufs <- buf
+                       }(ps.peer, ps.tap, buf, n)
+                       continue
+               CheckHandshake:
+                       hsLock.RLock()
+                       hs, exists = handshakes[addr]
+                       hsLock.RUnlock()
+                       if !exists {
+                               goto CheckID
+                       }
+                       peer = hs.Server(buf[:n])
+                       if peer == nil {
+                               goto Finished
+                       }
+
+                       log.Println("Peer handshake finished:", addr, peer.Id.String())
+                       hs.Zero()
+                       hsLock.Lock()
+                       delete(handshakes, addr)
+                       hsLock.Unlock()
+
+                       go func() {
+                               udpBufs <- make([]byte, govpn.MTU)
+                               udpBufs <- make([]byte, govpn.MTU)
+                       }()
+                       peersByIdLock.RLock()
+                       addrPrev, exists = peersById[*peer.Id]
+                       peersByIdLock.RUnlock()
+                       if exists {
+                               peersLock.Lock()
+                               peers[addrPrev].terminator <- struct{}{}
+                               ps = &PeerState{
+                                       peer:       peer,
+                                       tap:        peers[addrPrev].tap,
+                                       terminator: make(chan struct{}),
+                               }
+                               go func(ps PeerState) {
+                                       peerReady(ps)
+                                       <-udpBufs
+                                       <-udpBufs
+                               }(*ps)
+                               peersByIdLock.Lock()
+                               kpLock.Lock()
+                               delete(peers, addrPrev)
+                               delete(knownPeers, addrPrev)
+                               peers[addr] = ps
+                               knownPeers[addr] = &peer
+                               peersById[*peer.Id] = addr
+                               peersLock.Unlock()
+                               peersByIdLock.Unlock()
+                               kpLock.Unlock()
+                               log.Println("Rehandshake processed:", peer.Id.String())
+                       } else {
+                               go func(addr string, peer *govpn.Peer) {
+                                       ifaceName, err := callUp(peer.Id)
+                                       if err != nil {
+                                               return
+                                       }
+                                       tap, err := govpn.TAPListen(ifaceName)
+                                       if err != nil {
+                                               log.Println("Unable to create TAP:", err)
+                                               return
+                                       }
+                                       ps = &PeerState{
+                                               peer:       peer,
+                                               tap:        tap,
+                                               terminator: make(chan struct{}),
+                                       }
+                                       go func(ps PeerState) {
+                                               peerReady(ps)
+                                               <-udpBufs
+                                               <-udpBufs
+                                       }(*ps)
+                                       peersLock.Lock()
+                                       peersByIdLock.Lock()
+                                       kpLock.Lock()
+                                       peers[addr] = ps
+                                       knownPeers[addr] = &peer
+                                       peersById[*peer.Id] = addr
+                                       peersLock.Unlock()
+                                       peersByIdLock.Unlock()
+                                       kpLock.Unlock()
+                                       log.Println("Peer created:", peer.Id.String())
+                               }(addr, peer)
+                       }
+                       goto Finished
+               CheckID:
+                       peerId = idsCache.Find(buf[:n])
+                       if peerId == nil {
+                               log.Println("Unknown identity from:", addr)
+                               goto Finished
                        }
-                       sink <- Pkt{
-                               raddr.String(),
-                               UDPSender{lconn, raddr},
-                               buf[:n],
-                               ready,
+                       conf = confs[*peerId]
+                       if conf == nil {
+                               log.Println("Unable to get peer configuration:", peerId.String())
+                               goto Finished
                        }
+                       hs = govpn.NewHandshake(
+                               addr,
+                               UDPSender{conn: conn, addr: raddr},
+                               conf,
+                       )
+                       hs.Server(buf[:n])
+                       hsLock.Lock()
+                       handshakes[addr] = hs
+                       hsLock.Unlock()
+               Finished:
+                       udpBufs <- buf
                }
        }()
-       ready <- struct{}{}
-       return sink
 }