]> Cypherpunks.ru repositories - govpn.git/blobdiff - src/cypherpunks.ru/govpn/cmd/govpn-client/main.go
Upgrade Client
[govpn.git] / src / cypherpunks.ru / govpn / cmd / govpn-client / main.go
index c2ddb3e1b9a1d5e1773f8855cd42e4a3bd3903f1..f6530dfe8505b70aaf86e8979472d52d0d26417b 100644 (file)
@@ -22,151 +22,132 @@ package main
 import (
        "flag"
        "fmt"
-       "log"
-       "net"
-       "os"
-       "os/signal"
        "time"
 
-       "cypherpunks.ru/govpn"
-)
+       "github.com/Sirupsen/logrus"
 
-var (
-       remoteAddr  = flag.String("remote", "", "Remote server address")
-       proto       = flag.String("proto", "udp", "Protocol to use: udp or tcp")
-       ifaceName   = flag.String("iface", "tap0", "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 TAP interface")
-       timeoutP    = flag.Int("timeout", 60, "Timeout seconds")
-       timeSync    = flag.Int("timesync", 0, "Time synchronization requirement")
-       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")
-       warranty    = flag.Bool("warranty", false, "Print warranty information")
-
-       conf        *govpn.PeerConf
-       tap         *govpn.TAP
-       timeout     int
-       firstUpCall bool = true
-       knownPeers  govpn.KnownPeers
-       idsCache    *govpn.CipherCache
+       "cypherpunks.ru/govpn"
+       "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")
+               logLevel    = flag.String("log_level", "warning", "Log level")
+               protocol    govpn.Protocol
+               err         error
+               fields      = logrus.Fields{"func": "main"}
+       )
+
        flag.Parse()
        if *warranty {
                fmt.Println(govpn.Warranty)
                return
        }
-       timeout = *timeoutP
-       var err error
-       log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
+       if *version {
+               fmt.Println(govpn.VersionGet())
+               return
+       }
 
-       if *mtu > govpn.MTUMax {
-               log.Fatalln("Maximum allowable MTU is", govpn.MTUMax)
+       logger, err := govpn.NewLogger(*logLevel, *syslog)
+       if err != nil {
+               logrus.WithFields(fields).WithError(err).Fatal("Couldn't initialize logging")
        }
+
        if *egdPath != "" {
-               log.Println("Using", *egdPath, "EGD")
+               logger.WithField("egd_path", *egdPath).WithFields(fields).Debug("Init EGD")
                govpn.EGDInit(*egdPath)
        }
 
+       if protocol, err = govpn.NewProtocolFromString(*proto); err != nil {
+               logger.WithError(err).WithFields(fields).WithField("proto", *proto).Fatal("Invalid protocol")
+       }
+
+       if *proxyAddr != "" && protocol == govpn.ProtocolUDP {
+               logrus.WithFields(fields).WithFields(logrus.Fields{
+                       "proxy": *proxyAddr,
+                       "proto": *proto,
+               }).Fatal("HTTP proxy is supported only in TCP mode")
+       }
+
        if *verifierRaw == "" {
-               log.Fatalln("No verifier specified")
+               logger.Fatalln("-verifier is required")
        }
        verifier, err := govpn.VerifierFromString(*verifierRaw)
        if err != nil {
-               log.Fatalln(err)
+               logger.WithError(err).Fatal("Invalid -verifier")
        }
        key, err := govpn.KeyRead(*keyPath)
        if err != nil {
-               log.Fatalln("Unable to read the key", err)
+               logger.WithError(err).Fatal("Invalid -key")
+       }
+       priv, err := verifier.PasswordApply(key)
+       if err != nil {
+               logger.WithError(err).Fatal("Can't PasswordApply")
        }
-       priv := verifier.PasswordApply(key)
        if *encless {
-               if *proto != "tcp" {
-                       log.Fatalln("Currently encryptionless mode works only with TCP")
+               if protocol != govpn.ProtocolTCP {
+                       logger.Fatal("Currently encryptionless mode works only with TCP")
                }
                *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,
-       }
-       idsCache = govpn.NewCipherCache()
-       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 TAP interface:", err)
+       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,
+                       Up:       govpn.RunScriptAction(upPath),
+                       Down:     govpn.RunScriptAction(downPath),
+               },
+               Protocol:            protocol,
+               ProxyAddress:        *proxyAddr,
+               ProxyAuthentication: *proxyAuth,
+               RemoteAddress:       *remoteAddr,
+               NoReconnect:         *noreconnect,
        }
-
-       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)
+       if err = conf.Validate(); err != nil {
+               logger.WithError(err).Fatal("Invalid settings")
        }
 
-       if *syslog {
-               govpn.SyslogEnable()
+       c, err := client.NewClient(conf, logger, govpn.CatchSignalShutdown())
+       if err != nil {
+               logger.WithError(err).Fatal("Can't initialize client")
        }
 
-       termSignal := make(chan os.Signal, 1)
-       signal.Notify(termSignal, os.Interrupt, os.Kill)
+       if *stats != "" {
+               go govpn.StatsProcessor(*stats, c.KnownPeers())
+       }
 
-MainCycle:
-       for {
-               timeouted := make(chan struct{})
-               rehandshaking := make(chan struct{})
-               termination := make(chan struct{})
-               if *proxyAddr != "" {
-                       *proto = "tcp"
-               }
-               switch *proto {
-               case "udp":
-                       go startUDP(timeouted, rehandshaking, termination)
-               case "tcp":
-                       if *proxyAddr != "" {
-                               go proxyTCP(timeouted, rehandshaking, termination)
-                       } else {
-                               go startTCP(timeouted, rehandshaking, termination)
-                       }
-               default:
-                       log.Fatalln("Unknown protocol specified")
-               }
-               select {
-               case <-termSignal:
-                       log.Println("Finishing")
-                       govpn.Println("Finishing")
-                       termination <- struct{}{}
-                       break MainCycle
-               case <-timeouted:
-                       break MainCycle
-               case <-rehandshaking:
-               }
-               close(timeouted)
-               close(rehandshaking)
-               close(termination)
+       go c.MainCycle()
+       if err = <-c.Error; err != nil {
+               logger.WithError(err).Fatal("Fatal error")
        }
-       govpn.ScriptCall(*downPath, *ifaceName, *remoteAddr)
 }