"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", "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.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)
return
}
- timeout = *timeoutP
- var err error
+ if *version {
+ fmt.Println(govpn.VersionGet())
+ return
+ }
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)
}
+ switch *proto {
+ case "udp":
+ protocol = client.ProtocolUDP
+ case "tcp":
+ protocol = client.ProtocolTCP
+ default:
+ log.Fatalln("Unknown protocol specified")
+ }
+
+ if *proxyAddr != "" && protocol == client.ProtocolUDP {
+ log.Fatalln("HTTP proxy is supported only in TCP mode")
+ }
+
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
}
- 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 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()
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{})
- 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:
- govpn.BothPrintf(`[finish remote="%s"]`, *remoteAddr)
- termination <- struct{}{}
- break MainCycle
- case <-timeouted:
- break MainCycle
- 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)
}