From: Bruno Clermont Date: Thu, 8 Dec 2016 10:21:42 +0000 (+0800) Subject: Refactor govpn-client. X-Git-Tag: 7.1^2~28 X-Git-Url: http://www.git.cypherpunks.ru/?p=govpn.git;a=commitdiff_plain;h=b69a57fb98ca6b03477487176021c2de053af5a7 Refactor govpn-client. - move out of main client logic, allowing it to be imported from other Go code. - evaluate all errors values - client package only return `error`, it don't `os.Exit` anymore - add a new `Protocol` type --- diff --git a/src/cypherpunks.ru/govpn/client/client.go b/src/cypherpunks.ru/govpn/client/client.go new file mode 100644 index 0000000..ac54a86 --- /dev/null +++ b/src/cypherpunks.ru/govpn/client/client.go @@ -0,0 +1,136 @@ +package client + +import ( + "fmt" + "net" + "os" + "errors" + "time" + + "github.com/agl/ed25519" + "cypherpunks.ru/govpn" +) + +type Protocol uint8 + +const ( + ProtocolUDP Protocol = iota + ProtocolTCP +) + +type Configuration struct { + PrivateKey *[ed25519.PrivateKeySize]byte + Peer *govpn.PeerConf + Protocol Protocol + InterfaceName string + ProxyAddress string + ProxyAuthentication string + RemoteAddress string + UpPath, DownPath string + StatsAddress string + NoReconnect bool + MTU int +} + +func (c *Configuration) Validate() error { + if c.MTU > govpn.MTUMax { + return fmt.Errorf("Invalid MTU %d, maximum allowable is %d",c.MTU, govpn.MTUMax) + } + if len(c.RemoteAddress) == 0 { + return errors.New("Missing RemoteAddress") + } + if len(c.InterfaceName) == 0 { + return errors.New("Missing InterfaceName") + } + return nil +} + +func (c *Configuration) isProxy() bool { + return len(c.ProxyAddress) > 0 +} + +type Client struct { + idsCache *govpn.MACCache + tap *govpn.TAP + knownPeers govpn.KnownPeers + statsPort net.Listener + timeouted chan struct{} + rehandshaking chan struct{} + termination chan struct{} + firstUpCall bool + termSignal chan os.Signal + config Configuration + + // Error receive any error of all routines + Error chan error +} + +func (c *Client) MainCycle() { + var err error + c.tap, err = govpn.TAPListen(c.config.InterfaceName, c.config.MTU) + if err != nil { + c.Error <- fmt.Errorf("Can not listen on TUN/TAP interface: %s", err.Error()) + return + } + + if len(c.config.StatsAddress) > 0 { + c.statsPort, err = net.Listen("tcp", c.config.StatsAddress) + if err != nil { + c.Error <- fmt.Errorf("Can't listen on stats port: %s", err.Error()) + return + } + c.knownPeers = govpn.KnownPeers(make(map[string]**govpn.Peer)) + go govpn.StatsProcessor(c.statsPort, &c.knownPeers) + } + + MainCycle: + for { + c.timeouted = make(chan struct{}) + c.rehandshaking = make(chan struct{}) + c.termination = make(chan struct{}) + switch c.config.Protocol { + case ProtocolUDP: + go c.startUDP() + case ProtocolTCP: + if c.config.isProxy() { + go c.proxyTCP() + } else { + go c.startTCP() + } + } + select { + case <-c.termSignal: + govpn.BothPrintf(`[finish remote="%s"]`, c.config.RemoteAddress) + c.termination <- struct{}{} + // send a non-error to let know everything went fine + c.Error <- nil + break MainCycle + case <-c.timeouted: + if c.config.NoReconnect { + break MainCycle + } + govpn.BothPrintf(`[sleep seconds="%d"]`, c.config.Peer.Timeout) + time.Sleep(c.config.Peer.Timeout) + case <-c.rehandshaking: + } + close(c.timeouted) + close(c.rehandshaking) + close(c.termination) + } + if _, err = govpn.ScriptCall(c.config.DownPath, c.config.InterfaceName, c.config.RemoteAddress); err != nil { + c.Error <- err + } +} + +func NewClient(conf Configuration, verifier *govpn.Verifier, termSignal chan os.Signal) *Client { + client := &Client{ + idsCache: govpn.NewMACCache(), + firstUpCall: true, + config: conf, + termSignal: termSignal, + Error: make(chan error, 1), + } + confs := map[govpn.PeerId]*govpn.PeerConf{*verifier.Id: conf.Peer} + client.idsCache.Update(&confs) + return client +} diff --git a/src/cypherpunks.ru/govpn/cmd/govpn-client/proxy.go b/src/cypherpunks.ru/govpn/client/proxy.go similarity index 65% rename from src/cypherpunks.ru/govpn/cmd/govpn-client/proxy.go rename to src/cypherpunks.ru/govpn/client/proxy.go index 0a6729c..9f8e684 100644 --- a/src/cypherpunks.ru/govpn/cmd/govpn-client/proxy.go +++ b/src/cypherpunks.ru/govpn/client/proxy.go @@ -16,32 +16,34 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -package main +package client import ( "bufio" "encoding/base64" - "log" "net" + "fmt" "net/http" "cypherpunks.ru/govpn" ) -func proxyTCP(timeouted, rehandshaking, termination chan struct{}) { - proxyAddr, err := net.ResolveTCPAddr("tcp", *proxyAddr) +func (c *Client) proxyTCP() { + proxyAddr, err := net.ResolveTCPAddr("tcp", c.config.ProxyAddress) if err != nil { - log.Fatalln("Can not resolve proxy address:", err) + c.Error <- err + return } conn, err := net.DialTCP("tcp", nil, proxyAddr) if err != nil { - log.Fatalln("Can not connect to proxy:", err) + c.Error <- err + return } - req := "CONNECT " + *remoteAddr + " HTTP/1.1\n" - req += "Host: " + *remoteAddr + "\n" - if *proxyAuth != "" { + req := "CONNECT " + c.config.ProxyAddress + " HTTP/1.1\n" + req += "Host: " + c.config.ProxyAddress + "\n" + if c.config.ProxyAuthentication != "" { req += "Proxy-Authorization: Basic " - req += base64.StdEncoding.EncodeToString([]byte(*proxyAuth)) + "\n" + req += base64.StdEncoding.EncodeToString([]byte(c.config.ProxyAuthentication)) + "\n" } req += "\n" conn.Write([]byte(req)) @@ -50,8 +52,9 @@ func proxyTCP(timeouted, rehandshaking, termination chan struct{}) { &http.Request{Method: "CONNECT"}, ) if err != nil || resp.StatusCode != http.StatusOK { - log.Fatalln("Unexpected response from proxy") + c.Error <- fmt.Errorf("Unexpected response from proxy: %s", err.Error()) + return } - govpn.Printf(`[proxy-connected remote="%s" addr="%s"]`, *remoteAddr, *proxyAddr) - go handleTCP(conn, timeouted, rehandshaking, termination) + govpn.Printf(`[proxy-connected remote="%s" addr="%s"]`, c.config.RemoteAddress, *proxyAddr) + go c.handleTCP(conn) } diff --git a/src/cypherpunks.ru/govpn/cmd/govpn-client/tcp.go b/src/cypherpunks.ru/govpn/client/tcp.go similarity index 52% rename from src/cypherpunks.ru/govpn/cmd/govpn-client/tcp.go rename to src/cypherpunks.ru/govpn/client/tcp.go index 57a412d..85e2ec3 100644 --- a/src/cypherpunks.ru/govpn/cmd/govpn-client/tcp.go +++ b/src/cypherpunks.ru/govpn/client/tcp.go @@ -16,11 +16,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -package main +package client import ( "bytes" - "log" + "fmt" "net" "sync/atomic" "time" @@ -28,22 +28,24 @@ import ( "cypherpunks.ru/govpn" ) -func startTCP(timeouted, rehandshaking, termination chan struct{}) { - remote, err := net.ResolveTCPAddr("tcp", *remoteAddr) +func (c *Client) startTCP() { + remote, err := net.ResolveTCPAddr("tcp", c.config.RemoteAddress) if err != nil { - log.Fatalln("Can not resolve remote address:", err) + c.Error <- fmt.Errorf("Can not resolve remote address: %s", err) + return } conn, err := net.DialTCP("tcp", nil, remote) if err != nil { - log.Fatalln("Can not connect to address:", err) + c.Error <- fmt.Errorf("Can not connect to address: %s", err) + return } - govpn.Printf(`[connected remote="%s"]`, *remoteAddr) - handleTCP(conn, timeouted, rehandshaking, termination) + govpn.Printf(`[connected remote="%s"]`, c.config.RemoteAddress) + c.handleTCP(conn) } -func handleTCP(conn *net.TCPConn, timeouted, rehandshaking, termination chan struct{}) { - hs := govpn.HandshakeStart(*remoteAddr, conn, conf) - buf := make([]byte, 2*(govpn.EnclessEnlargeSize+*mtu)+*mtu) +func (c *Client) handleTCP(conn *net.TCPConn) { + hs := govpn.HandshakeStart(c.config.RemoteAddress, conn, c.config.Peer) + buf := make([]byte, 2*(govpn.EnclessEnlargeSize+c.config.MTU)+c.config.MTU) var n int var err error var prev int @@ -52,26 +54,29 @@ func handleTCP(conn *net.TCPConn, timeouted, rehandshaking, termination chan str HandshakeCycle: for { select { - case <-termination: + case <-c.termination: break HandshakeCycle default: } if prev == len(buf) { - govpn.Printf(`[packet-timeouted remote="%s"]`, *remoteAddr) - timeouted <- struct{}{} + govpn.Printf(`[packet-timeouted remote="%s"]`, c.config.RemoteAddress) + c.timeouted <- struct{}{} break HandshakeCycle } - conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Second)) + if err = conn.SetReadDeadline(time.Now().Add(c.config.Peer.Timeout)); err != nil { + c.Error <- err + break HandshakeCycle + } n, err = conn.Read(buf[prev:]) if err != nil { - govpn.Printf(`[connection-timeouted remote="%s"]`, *remoteAddr) - timeouted <- struct{}{} + govpn.Printf(`[connection-timeouted remote="%s"]`, c.config.RemoteAddress) + c.timeouted <- struct{}{} break HandshakeCycle } prev += n - peerId := idsCache.Find(buf[:prev]) + peerId := c.idsCache.Find(buf[:prev]) if peerId == nil { continue } @@ -80,15 +85,15 @@ HandshakeCycle: if peer == nil { continue } - govpn.Printf(`[handshake-completed remote="%s"]`, *remoteAddr) - knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{*remoteAddr: &peer}) - if firstUpCall { - go govpn.ScriptCall(*upPath, *ifaceName, *remoteAddr) - firstUpCall = false + govpn.Printf(`[handshake-completed remote="%s"]`, c.config.RemoteAddress) + c.knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{c.config.RemoteAddress: &peer}) + if c.firstUpCall { + go govpn.ScriptCall(c.config.UpPath, c.config.InterfaceName, c.config.RemoteAddress) + c.firstUpCall = false } hs.Zero() terminator = make(chan struct{}) - go govpn.PeerTapProcessor(peer, tap, terminator) + go govpn.PeerTapProcessor(peer, c.tap, terminator) break HandshakeCycle } if hs != nil { @@ -103,20 +108,23 @@ HandshakeCycle: TransportCycle: for { select { - case <-termination: + case <-c.termination: break TransportCycle default: } if prev == len(buf) { - govpn.Printf(`[packet-timeouted remote="%s"]`, *remoteAddr) - timeouted <- struct{}{} + govpn.Printf(`[packet-timeouted remote="%s"]`, c.config.RemoteAddress) + c.timeouted <- struct{}{} + break TransportCycle + } + if err = conn.SetReadDeadline(time.Now().Add(c.config.Peer.Timeout)); err != nil { + c.Error <- err break TransportCycle } - conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Second)) n, err = conn.Read(buf[prev:]) if err != nil { - govpn.Printf(`[connection-timeouted remote="%s"]`, *remoteAddr) - timeouted <- struct{}{} + govpn.Printf(`[connection-timeouted remote="%s"]`, c.config.RemoteAddress) + c.timeouted <- struct{}{} break TransportCycle } prev += n @@ -128,14 +136,14 @@ TransportCycle: if i == -1 { continue } - if !peer.PktProcess(buf[:i+govpn.NonceSize], tap, false) { - govpn.Printf(`[packet-unauthenticated remote="%s"]`, *remoteAddr) - timeouted <- struct{}{} + if !peer.PktProcess(buf[:i+govpn.NonceSize], c.tap, false) { + govpn.Printf(`[packet-unauthenticated remote="%s"]`, c.config.RemoteAddress) + c.timeouted <- struct{}{} break TransportCycle } if atomic.LoadUint64(&peer.BytesIn)+atomic.LoadUint64(&peer.BytesOut) > govpn.MaxBytesPerKey { - govpn.Printf(`[rehandshake-required remote="%s"]`, *remoteAddr) - rehandshaking <- struct{}{} + govpn.Printf(`[rehandshake-required remote="%s"]`, c.config.RemoteAddress) + c.rehandshaking <- struct{}{} break TransportCycle } copy(buf, buf[i+govpn.NonceSize:prev]) @@ -146,5 +154,7 @@ TransportCycle: terminator <- struct{}{} } peer.Zero() - conn.Close() + if err = conn.Close(); err != nil { + c.Error <- err + } } diff --git a/src/cypherpunks.ru/govpn/cmd/govpn-client/udp.go b/src/cypherpunks.ru/govpn/client/udp.go similarity index 51% rename from src/cypherpunks.ru/govpn/cmd/govpn-client/udp.go rename to src/cypherpunks.ru/govpn/client/udp.go index 96dbfba..541d631 100644 --- a/src/cypherpunks.ru/govpn/cmd/govpn-client/udp.go +++ b/src/cypherpunks.ru/govpn/client/udp.go @@ -16,10 +16,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -package main +package client import ( - "log" + "fmt" "net" "sync/atomic" "time" @@ -27,36 +27,42 @@ import ( "cypherpunks.ru/govpn" ) -func startUDP(timeouted, rehandshaking, termination chan struct{}) { - remote, err := net.ResolveUDPAddr("udp", *remoteAddr) +func (c *Client) startUDP() { + remote, err := net.ResolveUDPAddr("udp", c.config.RemoteAddress) if err != nil { - log.Fatalln("Can not resolve remote address:", err) + c.Error <- fmt.Errorf("Can not resolve remote address: %s", err) + return } conn, err := net.DialUDP("udp", nil, remote) if err != nil { - log.Fatalln("Can not listen on UDP:", err) + c.Error <- fmt.Errorf("Can not connect remote address: %s", err) + return } - govpn.Printf(`[connected remote="%s"]`, *remoteAddr) + govpn.Printf(`[connected remote="%s"]`, c.config.RemoteAddress) - hs := govpn.HandshakeStart(*remoteAddr, conn, conf) - buf := make([]byte, *mtu*2) + hs := govpn.HandshakeStart(c.config.RemoteAddress, conn, c.config.Peer) + buf := make([]byte, c.config.MTU*2) var n int var timeouts int var peer *govpn.Peer var terminator chan struct{} + timeout := int(c.config.Peer.Timeout.Seconds()) MainCycle: for { select { - case <-termination: + case <-c.termination: break MainCycle default: } - conn.SetReadDeadline(time.Now().Add(time.Second)) + if err = conn.SetReadDeadline(time.Now().Add(time.Second)); err != nil { + c.Error <- err + break MainCycle + } n, err = conn.Read(buf) if timeouts == timeout { - govpn.Printf(`[connection-timeouted remote="%s"]`, *remoteAddr) - timeouted <- struct{}{} + govpn.Printf(`[connection-timeouted remote="%s"]`, c.config.RemoteAddress) + c.timeouted <- struct{}{} break } if err != nil { @@ -64,21 +70,21 @@ MainCycle: continue } if peer != nil { - if peer.PktProcess(buf[:n], tap, true) { + if peer.PktProcess(buf[:n], c.tap, true) { timeouts = 0 } else { - govpn.Printf(`[packet-unauthenticated remote="%s"]`, *remoteAddr) + govpn.Printf(`[packet-unauthenticated remote="%s"]`, c.config.RemoteAddress) timeouts++ } if atomic.LoadUint64(&peer.BytesIn)+atomic.LoadUint64(&peer.BytesOut) > govpn.MaxBytesPerKey { - govpn.Printf(`[rehandshake-required remote="%s"]`, *remoteAddr) - rehandshaking <- struct{}{} + govpn.Printf(`[rehandshake-required remote="%s"]`, c.config.RemoteAddress) + c.rehandshaking <- struct{}{} break MainCycle } continue } - if idsCache.Find(buf[:n]) == nil { - govpn.Printf(`[identity-invalid remote="%s"]`, *remoteAddr) + if c.idsCache.Find(buf[:n]) == nil { + govpn.Printf(`[identity-invalid remote="%s"]`, c.config.RemoteAddress) continue } timeouts = 0 @@ -86,15 +92,15 @@ MainCycle: if peer == nil { continue } - govpn.Printf(`[handshake-completed remote="%s"]`, *remoteAddr) - knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{*remoteAddr: &peer}) - if firstUpCall { - go govpn.ScriptCall(*upPath, *ifaceName, *remoteAddr) - firstUpCall = false + govpn.Printf(`[handshake-completed remote="%s"]`, c.config.RemoteAddress) + c.knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{c.config.RemoteAddress: &peer}) + if c.firstUpCall { + go govpn.ScriptCall(c.config.UpPath, c.config.InterfaceName, c.config.RemoteAddress) + c.firstUpCall = false } hs.Zero() terminator = make(chan struct{}) - go govpn.PeerTapProcessor(peer, tap, terminator) + go govpn.PeerTapProcessor(peer, c.tap, terminator) } if terminator != nil { terminator <- struct{}{} @@ -102,5 +108,7 @@ MainCycle: if hs != nil { hs.Zero() } - conn.Close() + if err = conn.Close(); err != nil { + c.Error <- err + } } diff --git a/src/cypherpunks.ru/govpn/cmd/govpn-client/main.go b/src/cypherpunks.ru/govpn/cmd/govpn-client/main.go index 36ff72a..df426ba 100644 --- a/src/cypherpunks.ru/govpn/cmd/govpn-client/main.go +++ b/src/cypherpunks.ru/govpn/cmd/govpn-client/main.go @@ -23,46 +23,41 @@ import ( "flag" "fmt" "log" - "net" "os" "os/signal" "time" "cypherpunks.ru/govpn" -) - -var ( - remoteAddr = flag.String("remote", "", "Remote server address") - proto = flag.String("proto", "udp", "Protocol to use: udp or tcp") - ifaceName = flag.String("iface", "tap0", "TUN/TAP network interface") - verifierRaw = flag.String("verifier", "", "Verifier") - keyPath = flag.String("key", "", "Path to passphrase 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") - proxyAddr = flag.String("proxy", "", "Use HTTP proxy on host:port") - proxyAuth = flag.String("proxy-auth", "", "user:password Basic proxy auth") - mtu = flag.Int("mtu", govpn.MTUDefault, "MTU of TUN/TAP interface") - timeoutP = flag.Int("timeout", 60, "Timeout seconds") - timeSync = flag.Int("timesync", 0, "Time synchronization requirement") - noreconnect = flag.Bool("noreconnect", false, "Disable reconnection after timeout") - noisy = flag.Bool("noise", false, "Enable noise appending") - encless = flag.Bool("encless", false, "Encryptionless mode") - cpr = flag.Int("cpr", 0, "Enable constant KiB/sec out traffic rate") - egdPath = flag.String("egd", "", "Optional path to EGD socket") - syslog = flag.Bool("syslog", false, "Enable logging to syslog") - version = flag.Bool("version", false, "Print version information") - warranty = flag.Bool("warranty", false, "Print warranty information") - - conf *govpn.PeerConf - tap *govpn.TAP - timeout int - firstUpCall bool = true - knownPeers govpn.KnownPeers - idsCache *govpn.MACCache + "cypherpunks.ru/govpn/client" ) func main() { + var ( + remoteAddr = flag.String("remote", "", "Remote server address") + proto = flag.String("proto", "udp", "Protocol to use: udp or tcp") + ifaceName = flag.String("iface", "tap0", "TUN/TAP network interface") + verifierRaw = flag.String("verifier", "", "Verifier") + keyPath = flag.String("key", "", "Path to passphrase 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") + proxyAddr = flag.String("proxy", "", "Use HTTP proxy on host:port") + proxyAuth = flag.String("proxy-auth", "", "user:password Basic proxy auth") + mtu = flag.Int("mtu", govpn.MTUDefault, "MTU of TUN/TAP interface") + timeoutP = flag.Int("timeout", 60, "Timeout seconds") + timeSync = flag.Int("timesync", 0, "Time synchronization requirement") + noreconnect = flag.Bool("noreconnect", false, "Disable reconnection after timeout") + noisy = flag.Bool("noise", false, "Enable noise appending") + encless = flag.Bool("encless", false, "Encryptionless mode") + cpr = flag.Int("cpr", 0, "Enable constant KiB/sec out traffic rate") + egdPath = flag.String("egd", "", "Optional path to EGD socket") + syslog = flag.Bool("syslog", false, "Enable logging to syslog") + version = flag.Bool("version", false, "Print version information") + warranty = flag.Bool("warranty", false, "Print warranty information") + protocol client.Protocol + err error + ) + flag.Parse() if *warranty { fmt.Println(govpn.Warranty) @@ -72,72 +67,78 @@ func main() { fmt.Println(govpn.VersionGet()) return } - timeout = *timeoutP - var err error log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile) - if *mtu > govpn.MTUMax { - log.Fatalln("Maximum allowable MTU is", govpn.MTUMax) - } if *egdPath != "" { log.Println("Using", *egdPath, "EGD") govpn.EGDInit(*egdPath) } - if *proxyAddr != "" { - *proto = "tcp" - } - if !(*proto == "udp" || *proto == "tcp") { + switch *proto { + case "udp": + protocol = client.ProtocolUDP + case "tcp": + protocol = client.ProtocolTCP + default: log.Fatalln("Unknown protocol specified") } + + if *proxyAddr != "" && protocol == client.ProtocolUDP { + log.Println("Proxy is supported for TCP only, switch") + protocol = client.ProtocolTCP + } + if *verifierRaw == "" { - log.Fatalln("No verifier specified") + log.Fatalln("-verifier is required") } verifier, err := govpn.VerifierFromString(*verifierRaw) if err != nil { - log.Fatalln(err) + log.Fatalln("Invalid -verifier:", err) } key, err := govpn.KeyRead(*keyPath) if err != nil { - log.Fatalln("Unable to read the key", err) + log.Fatalln("Invalid -key:", err) } priv := verifier.PasswordApply(key) if *encless { - if *proto != "tcp" { + if protocol != client.ProtocolTCP { log.Fatalln("Currently encryptionless mode works only with TCP") } - *noisy = true + if !*noisy { + log.Println("-encless is on, force -noisy mode") + *noisy = true + } } - conf = &govpn.PeerConf{ - Id: verifier.Id, - Iface: *ifaceName, - MTU: *mtu, - Timeout: time.Second * time.Duration(timeout), - TimeSync: *timeSync, - Noise: *noisy, - CPR: *cpr, - Encless: *encless, - Verifier: verifier, - DSAPriv: priv, + conf := client.Configuration{ + PrivateKey: priv, + Peer: &govpn.PeerConf{ + Id: verifier.Id, + Iface: *ifaceName, + MTU: *mtu, + Timeout: time.Second * time.Duration(*timeoutP), + TimeSync: *timeSync, + Noise: *noisy, + CPR: *cpr, + Encless: *encless, + Verifier: verifier, + DSAPriv: priv, + }, + Protocol: protocol, + InterfaceName: *ifaceName, + ProxyAddress: *proxyAddr, + ProxyAuthentication: *proxyAuth, + RemoteAddress: *remoteAddr, + UpPath: *upPath, + DownPath: *downPath, + StatsAddress: *stats, + NoReconnect: *noreconnect, + MTU: *mtu, } - idsCache = govpn.NewMACCache() - confs := map[govpn.PeerId]*govpn.PeerConf{*verifier.Id: conf} - idsCache.Update(&confs) - log.Println(govpn.VersionGet()) - - tap, err = govpn.TAPListen(*ifaceName, *mtu) - if err != nil { - log.Fatalln("Can not listen on TUN/TAP interface:", err) + if err = conf.Validate(); err != nil { + log.Fatalln("Invalid settings:", err) } - if *stats != "" { - log.Println("Stats are going to listen on", *stats) - statsPort, err := net.Listen("tcp", *stats) - if err != nil { - log.Fatalln("Can not listen on stats port:", err) - } - go govpn.StatsProcessor(statsPort, &knownPeers) - } + log.Println(govpn.VersionGet()) if *syslog { govpn.SyslogEnable() @@ -145,38 +146,11 @@ func main() { termSignal := make(chan os.Signal, 1) signal.Notify(termSignal, os.Interrupt, os.Kill) - -MainCycle: - for { - timeouted := make(chan struct{}) - rehandshaking := make(chan struct{}) - termination := make(chan struct{}) - switch *proto { - case "udp": - go startUDP(timeouted, rehandshaking, termination) - case "tcp": - if *proxyAddr != "" { - go proxyTCP(timeouted, rehandshaking, termination) - } else { - go startTCP(timeouted, rehandshaking, termination) - } - } - select { - case <-termSignal: - govpn.BothPrintf(`[finish remote="%s"]`, *remoteAddr) - termination <- struct{}{} - break MainCycle - case <-timeouted: - if *noreconnect { - break MainCycle - } - govpn.BothPrintf(`[sleep seconds="%d"]`, timeout) - time.Sleep(time.Second * time.Duration(timeout)) - case <-rehandshaking: - } - close(timeouted) - close(rehandshaking) - close(termination) + c := client.NewClient(conf, verifier, termSignal) + go c.MainCycle() + if err := <-c.Error; err != nil { + log.Fatalln(err) + } else { + log.Println("Closed VPN tunnel") } - govpn.ScriptCall(*downPath, *ifaceName, *remoteAddr) }