]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/client/client.go
3621d780c7678aa81360205f39d1111eb2f145a4
[govpn.git] / src / cypherpunks.ru / govpn / client / client.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2019 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, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package client
19
20 import (
21         "errors"
22         "fmt"
23         "net"
24         "os"
25         "sync"
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    sync.Map
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                 go govpn.StatsProcessor(c.statsPort, &c.knownPeers)
103         }
104
105 MainCycle:
106         for {
107                 c.timeouted = make(chan struct{})
108                 c.rehandshaking = make(chan struct{})
109                 c.termination = make(chan struct{})
110                 switch c.config.Protocol {
111                 case ProtocolUDP:
112                         go c.startUDP()
113                 case ProtocolTCP:
114                         if c.config.isProxy() {
115                                 go c.proxyTCP()
116                         } else {
117                                 go c.startTCP()
118                         }
119                 }
120                 select {
121                 case <-c.termSignal:
122                         govpn.BothPrintf(`[finish remote="%s"]`, c.config.RemoteAddress)
123                         c.termination <- struct{}{}
124                         // empty value signals that everything is fine
125                         c.Error <- nil
126                         break MainCycle
127                 case <-c.timeouted:
128                         if c.config.NoReconnect {
129                                 break MainCycle
130                         }
131                         govpn.BothPrintf(`[sleep seconds="%d"]`, c.config.Peer.Timeout/time.Second)
132                         time.Sleep(c.config.Peer.Timeout)
133                 case <-c.rehandshaking:
134                 }
135                 close(c.timeouted)
136                 close(c.rehandshaking)
137                 close(c.termination)
138         }
139         if _, err = govpn.ScriptCall(
140                 c.config.DownPath,
141                 c.config.InterfaceName,
142                 c.config.RemoteAddress,
143         ); err != nil {
144                 c.Error <- err
145         }
146 }
147
148 func NewClient(conf Configuration, verifier *govpn.Verifier, termSignal chan os.Signal) *Client {
149         client := Client{
150                 idsCache:    govpn.NewMACCache(),
151                 firstUpCall: true,
152                 config:      conf,
153                 termSignal:  termSignal,
154                 Error:       make(chan error, 1),
155         }
156         confs := map[govpn.PeerID]*govpn.PeerConf{*verifier.ID: conf.Peer}
157         client.idsCache.Update(&confs)
158         return &client
159 }