- 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
--- /dev/null
+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
+}
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-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))
&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)
}
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package main
+package client
import (
"bytes"
- "log"
+ "fmt"
"net"
"sync/atomic"
"time"
"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
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
}
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 {
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
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])
terminator <- struct{}{}
}
peer.Zero()
- conn.Close()
+ if err = conn.Close(); err != nil {
+ c.Error <- err
+ }
}
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package main
+package client
import (
- "log"
+ "fmt"
"net"
"sync/atomic"
"time"
"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 {
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
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{}{}
if hs != nil {
hs.Zero()
}
- conn.Close()
+ if err = conn.Close(); err != nil {
+ c.Error <- err
+ }
}
"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)
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()
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)
}