]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/client/client.go
a4c49079157da40428bc5d534f7989afd0dad1e5
[govpn.git] / src / cypherpunks.ru / govpn / client / client.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2017 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 // Protocol is a GoVPN supported protocol: either UDP, TCP or both
34 type Protocol int
35
36 const (
37         // ProtocolUDP is UDP transport protocol
38         ProtocolUDP Protocol = iota
39         // ProtocolTCP is TCP transport protocol
40         ProtocolTCP
41 )
42
43 // Configuration holds GoVPN client configuration
44 type Configuration struct {
45         PrivateKey          *[ed25519.PrivateKeySize]byte
46         Peer                *govpn.PeerConf
47         Protocol            Protocol
48         InterfaceName       string
49         ProxyAddress        string
50         ProxyAuthentication string
51         RemoteAddress       string
52         UpPath              string
53         DownPath            string
54         StatsAddress        string
55         NoReconnect         bool
56         MTU                 int
57 }
58
59 // Validate returns an error if a configuration is invalid
60 func (c *Configuration) Validate() error {
61         if c.MTU > govpn.MTUMax {
62                 return fmt.Errorf("Invalid MTU %d, maximum allowable is %d", c.MTU, govpn.MTUMax)
63         }
64         if len(c.RemoteAddress) == 0 {
65                 return errors.New("Missing RemoteAddress")
66         }
67         if len(c.InterfaceName) == 0 {
68                 return errors.New("Missing InterfaceName")
69         }
70         return nil
71 }
72
73 func (c *Configuration) isProxy() bool {
74         return len(c.ProxyAddress) > 0
75 }
76
77 // Client is a GoVPN client
78 type Client struct {
79         idsCache      *govpn.MACCache
80         tap           *govpn.TAP
81         knownPeers    govpn.KnownPeers
82         statsPort     net.Listener
83         timeouted     chan struct{}
84         rehandshaking chan struct{}
85         termination   chan struct{}
86         firstUpCall   bool
87         termSignal    chan os.Signal
88         config        Configuration
89
90         // Error channel receives any kind of routine errors
91         Error chan error
92 }
93
94 // MainCycle main loop of a connecting/connected client
95 func (c *Client) MainCycle() {
96         var err error
97         c.tap, err = govpn.TAPListen(c.config.InterfaceName, c.config.MTU)
98         if err != nil {
99                 c.Error <- fmt.Errorf("Can not listen on TUN/TAP interface: %s", err.Error())
100                 return
101         }
102
103         if len(c.config.StatsAddress) > 0 {
104                 c.statsPort, err = net.Listen("tcp", c.config.StatsAddress)
105                 if err != nil {
106                         c.Error <- fmt.Errorf("Can't listen on stats port: %s", err.Error())
107                         return
108                 }
109                 c.knownPeers = govpn.KnownPeers(make(map[string]**govpn.Peer))
110                 go govpn.StatsProcessor(c.statsPort, &c.knownPeers)
111         }
112
113 MainCycle:
114         for {
115                 c.timeouted = make(chan struct{})
116                 c.rehandshaking = make(chan struct{})
117                 c.termination = make(chan struct{})
118                 switch c.config.Protocol {
119                 case ProtocolUDP:
120                         go c.startUDP()
121                 case ProtocolTCP:
122                         if c.config.isProxy() {
123                                 go c.proxyTCP()
124                         } else {
125                                 go c.startTCP()
126                         }
127                 }
128                 select {
129                 case <-c.termSignal:
130                         govpn.BothPrintf(`[finish remote="%s"]`, c.config.RemoteAddress)
131                         c.termination <- struct{}{}
132                         // empty value signals that everything is fine
133                         c.Error <- nil
134                         break MainCycle
135                 case <-c.timeouted:
136                         if c.config.NoReconnect {
137                                 break MainCycle
138                         }
139                         govpn.BothPrintf(`[sleep seconds="%d"]`, c.config.Peer.Timeout/time.Second)
140                         time.Sleep(c.config.Peer.Timeout)
141                 case <-c.rehandshaking:
142                 }
143                 close(c.timeouted)
144                 close(c.rehandshaking)
145                 close(c.termination)
146         }
147         if _, err = govpn.ScriptCall(
148                 c.config.DownPath,
149                 c.config.InterfaceName,
150                 c.config.RemoteAddress,
151         ); err != nil {
152                 c.Error <- err
153         }
154 }
155
156 // NewClient returns a configured GoVPN client, to trigger connection
157 // MainCycle must be executed.
158 func NewClient(conf Configuration, verifier *govpn.Verifier, termSignal chan os.Signal) *Client {
159         client := Client{
160                 idsCache:    govpn.NewMACCache(),
161                 firstUpCall: true,
162                 config:      conf,
163                 termSignal:  termSignal,
164                 Error:       make(chan error, 1),
165         }
166         confs := map[govpn.PeerID]*govpn.PeerConf{*verifier.ID: conf.Peer}
167         client.idsCache.Update(&confs)
168         return &client
169 }