]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/client/client.go
Print seconds, not microseconds
[govpn.git] / src / cypherpunks.ru / govpn / client / client.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package client
20
21 import (
22         "errors"
23         "fmt"
24         "net"
25         "os"
26         "time"
27
28         "github.com/agl/ed25519"
29
30         "cypherpunks.ru/govpn"
31 )
32
33 type Protocol int
34
35 const (
36         ProtocolUDP Protocol = iota
37         ProtocolTCP
38 )
39
40 type Configuration struct {
41         PrivateKey          *[ed25519.PrivateKeySize]byte
42         Peer                *govpn.PeerConf
43         Protocol            Protocol
44         InterfaceName       string
45         ProxyAddress        string
46         ProxyAuthentication string
47         RemoteAddress       string
48         UpPath              string
49         DownPath            string
50         StatsAddress        string
51         NoReconnect         bool
52         MTU                 int
53 }
54
55 func (c *Configuration) Validate() error {
56         if c.MTU > govpn.MTUMax {
57                 return fmt.Errorf("Invalid MTU %d, maximum allowable is %d", c.MTU, govpn.MTUMax)
58         }
59         if len(c.RemoteAddress) == 0 {
60                 return errors.New("Missing RemoteAddress")
61         }
62         if len(c.InterfaceName) == 0 {
63                 return errors.New("Missing InterfaceName")
64         }
65         return nil
66 }
67
68 func (c *Configuration) isProxy() bool {
69         return len(c.ProxyAddress) > 0
70 }
71
72 type Client struct {
73         idsCache      *govpn.MACCache
74         tap           *govpn.TAP
75         knownPeers    govpn.KnownPeers
76         statsPort     net.Listener
77         timeouted     chan struct{}
78         rehandshaking chan struct{}
79         termination   chan struct{}
80         firstUpCall   bool
81         termSignal    chan os.Signal
82         config        Configuration
83
84         // Error channel receives any kind of routine errors
85         Error chan error
86 }
87
88 func (c *Client) MainCycle() {
89         var err error
90         c.tap, err = govpn.TAPListen(c.config.InterfaceName, c.config.MTU)
91         if err != nil {
92                 c.Error <- fmt.Errorf("Can not listen on TUN/TAP interface: %s", err.Error())
93                 return
94         }
95
96         if len(c.config.StatsAddress) > 0 {
97                 c.statsPort, err = net.Listen("tcp", c.config.StatsAddress)
98                 if err != nil {
99                         c.Error <- fmt.Errorf("Can't listen on stats port: %s", err.Error())
100                         return
101                 }
102                 c.knownPeers = govpn.KnownPeers(make(map[string]**govpn.Peer))
103                 go govpn.StatsProcessor(c.statsPort, &c.knownPeers)
104         }
105
106 MainCycle:
107         for {
108                 c.timeouted = make(chan struct{})
109                 c.rehandshaking = make(chan struct{})
110                 c.termination = make(chan struct{})
111                 switch c.config.Protocol {
112                 case ProtocolUDP:
113                         go c.startUDP()
114                 case ProtocolTCP:
115                         if c.config.isProxy() {
116                                 go c.proxyTCP()
117                         } else {
118                                 go c.startTCP()
119                         }
120                 }
121                 select {
122                 case <-c.termSignal:
123                         govpn.BothPrintf(`[finish remote="%s"]`, c.config.RemoteAddress)
124                         c.termination <- struct{}{}
125                         // empty value signals that everything is fine
126                         c.Error <- nil
127                         break MainCycle
128                 case <-c.timeouted:
129                         if c.config.NoReconnect {
130                                 break MainCycle
131                         }
132                         govpn.BothPrintf(`[sleep seconds="%d"]`, c.config.Peer.Timeout/time.Second)
133                         time.Sleep(c.config.Peer.Timeout)
134                 case <-c.rehandshaking:
135                 }
136                 close(c.timeouted)
137                 close(c.rehandshaking)
138                 close(c.termination)
139         }
140         if _, err = govpn.ScriptCall(
141                 c.config.DownPath,
142                 c.config.InterfaceName,
143                 c.config.RemoteAddress,
144         ); err != nil {
145                 c.Error <- err
146         }
147 }
148
149 func NewClient(conf Configuration, verifier *govpn.Verifier, termSignal chan os.Signal) *Client {
150         client := Client{
151                 idsCache:    govpn.NewMACCache(),
152                 firstUpCall: true,
153                 config:      conf,
154                 termSignal:  termSignal,
155                 Error:       make(chan error, 1),
156         }
157         confs := map[govpn.PeerId]*govpn.PeerConf{*verifier.Id: conf.Peer}
158         client.idsCache.Update(&confs)
159         return &client
160 }