]> Cypherpunks.ru repositories - govpn.git/blob - govpn.go
Heartbeating the channel twice during timeout
[govpn.git] / govpn.go
1 /*
2 govpn -- high-performance secure virtual private network daemon
3 Copyright (C) 2014 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 package main
19
20 import (
21         "encoding/binary"
22         "encoding/hex"
23         "flag"
24         "fmt"
25         "io"
26         "io/ioutil"
27         "log"
28         "net"
29         "time"
30
31         "code.google.com/p/go.crypto/poly1305"
32         "code.google.com/p/go.crypto/salsa20"
33 )
34
35 var (
36         remoteAddr = flag.String("remote", "", "Remote server address")
37         bindAddr   = flag.String("bind", "", "Bind to address")
38         ifaceName  = flag.String("iface", "tap0", "TAP network interface")
39         keyPath    = flag.String("key", "", "Path to authentication key file")
40         mtu        = flag.Int("mtu", 1500, "MTU")
41         timeoutP   = flag.Int("timeout", 60, "Timeout seconds")
42         verboseP   = flag.Bool("v", false, "Increase verbosity")
43 )
44
45 const (
46         NonceSize = 8
47         KeySize   = 32
48         // S20BS is Salsa20's internal blocksize in bytes
49         S20BS         = 64
50         HeartBeatSize = 12
51         HeartBeatMark = "\x00\x00\x00HEARTBEAT"
52 )
53
54 type TAP interface {
55         io.Reader
56         io.Writer
57 }
58
59 type Peer struct {
60         addr      *net.UDPAddr
61         key       *[KeySize]byte // encryption key
62         nonceOur  uint64         // nonce for our messages
63         nonceRecv uint64         // latest received nonce from remote peer
64 }
65
66 type UDPPkt struct {
67         addr *net.UDPAddr
68         size int
69 }
70
71 func main() {
72         flag.Parse()
73         timeout := *timeoutP
74         verbose := *verboseP
75         log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
76
77         // Key decoding
78         keyData, err := ioutil.ReadFile(*keyPath)
79         if err != nil {
80                 panic("Unable to read keyfile: " + err.Error())
81         }
82         if len(keyData) < 64 {
83                 panic("Key must be 64 hex characters long")
84         }
85         keyDecoded, err := hex.DecodeString(string(keyData[0:64]))
86         if err != nil {
87                 panic("Unable to decode the key: " + err.Error())
88         }
89         key := new([KeySize]byte)
90         copy(key[:], keyDecoded)
91         keyDecoded = nil
92         keyData = nil
93
94         // Interface listening
95         maxIfacePktSize := *mtu - poly1305.TagSize - NonceSize
96         log.Println("Max MTU", maxIfacePktSize, "on interface", *ifaceName)
97         iface := NewTAP(*ifaceName)
98         ethBuf := make([]byte, maxIfacePktSize)
99         ethSink := make(chan int)
100         ethSinkReady := make(chan bool)
101         go func() {
102                 for {
103                         <-ethSinkReady
104                         n, err := iface.Read(ethBuf)
105                         if err != nil {
106                                 panic(err)
107                         }
108                         ethSink <- n
109                 }
110         }()
111         ethSinkReady <- true
112
113         // Network address parsing
114         if (len(*bindAddr) > 1 && len(*remoteAddr) > 1) ||
115                 (len(*bindAddr) == 0 && len(*remoteAddr) == 0) {
116                 panic("Either -bind or -remote must be specified only")
117         }
118         var conn *net.UDPConn
119         var remote *net.UDPAddr
120         serverMode := false
121         bindTo := "0.0.0.0:0"
122
123         if len(*bindAddr) > 1 {
124                 bindTo = *bindAddr
125                 serverMode = true
126         }
127
128         bind, err := net.ResolveUDPAddr("udp", bindTo)
129         if err != nil {
130                 panic(err)
131         }
132         conn, err = net.ListenUDP("udp", bind)
133         if err != nil {
134                 panic(err)
135         }
136
137         if len(*remoteAddr) > 1 {
138                 remote, err = net.ResolveUDPAddr("udp", *remoteAddr)
139                 if err != nil {
140                         panic(err)
141                 }
142         }
143
144         udpBuf := make([]byte, *mtu)
145         udpSink := make(chan *UDPPkt)
146         udpSinkReady := make(chan bool)
147         go func(conn *net.UDPConn) {
148                 for {
149                         <-udpSinkReady
150                         conn.SetReadDeadline(time.Now().Add(time.Second))
151                         n, addr, err := conn.ReadFromUDP(udpBuf)
152                         if err != nil {
153                                 if verbose {
154                                         fmt.Print("B")
155                                 }
156                                 udpSink <- nil
157                         } else {
158                                 udpSink <- &UDPPkt{addr, n}
159                         }
160                 }
161         }(conn)
162         udpSinkReady <- true
163
164         // Process packets
165         var udpPkt *UDPPkt
166         var udpPktData []byte
167         var ethPktSize int
168         var frame []byte
169         var addr string
170         var peer *Peer
171         var p *Peer
172
173         timeouts := 0
174         states := make(map[string]*Handshake)
175         nonce := make([]byte, NonceSize)
176         keyAuth := new([KeySize]byte)
177         tag := new([poly1305.TagSize]byte)
178         buf := make([]byte, *mtu+S20BS)
179         emptyKey := make([]byte, KeySize)
180         ethPkt := make([]byte, maxIfacePktSize)
181         udpPktDataBuf := make([]byte, *mtu)
182
183         if !serverMode {
184                 states[remote.String()] = HandshakeStart(conn, remote, key)
185         }
186
187         heartbeat := time.Tick(time.Second * time.Duration(timeout/3))
188         heartbeatMark := []byte(HeartBeatMark)
189
190         finished := false
191         for {
192                 if finished {
193                         break
194                 }
195                 select {
196                 case <-heartbeat:
197                         go func() { ethSink <- -1 }()
198                 case udpPkt = <-udpSink:
199                         timeouts++
200                         if !serverMode && timeouts >= timeout {
201                                 finished = true
202                         }
203                         if udpPkt == nil {
204                                 udpSinkReady <- true
205                                 continue
206                         }
207                         copy(udpPktDataBuf, udpBuf[:udpPkt.size])
208                         udpSinkReady <- true
209                         udpPktData = udpPktDataBuf[:udpPkt.size]
210                         if isValidHandshakePkt(udpPktData) {
211                                 addr = udpPkt.addr.String()
212                                 state, exists := states[addr]
213                                 if serverMode {
214                                         if !exists {
215                                                 state = &Handshake{addr: udpPkt.addr}
216                                                 states[addr] = state
217                                         }
218                                         p = state.Server(conn, key, udpPktData)
219                                 } else {
220                                         if !exists {
221                                                 fmt.Print("[HS?]")
222                                                 continue
223                                         }
224                                         p = state.Client(conn, key, udpPktData)
225                                 }
226                                 if p != nil {
227                                         fmt.Print("[HS-OK]")
228                                         peer = p
229                                         delete(states, addr)
230                                 }
231                                 continue
232                         }
233                         if peer == nil {
234                                 continue
235                         }
236                         nonceRecv, _ := binary.Uvarint(udpPktData[:8])
237                         if peer.nonceRecv >= nonceRecv {
238                                 fmt.Print("R")
239                                 continue
240                         }
241                         copy(buf[:KeySize], emptyKey)
242                         copy(tag[:], udpPktData[udpPkt.size-poly1305.TagSize:])
243                         copy(buf[S20BS:], udpPktData[NonceSize:udpPkt.size-poly1305.TagSize])
244                         salsa20.XORKeyStream(
245                                 buf[:S20BS+udpPkt.size-poly1305.TagSize],
246                                 buf[:S20BS+udpPkt.size-poly1305.TagSize],
247                                 udpPktData[:NonceSize],
248                                 peer.key,
249                         )
250                         copy(keyAuth[:], buf[:KeySize])
251                         if !poly1305.Verify(tag, udpPktData[:udpPkt.size-poly1305.TagSize], keyAuth) {
252                                 fmt.Print("T")
253                                 continue
254                         }
255                         peer.nonceRecv = nonceRecv
256                         timeouts = 0
257                         frame = buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]
258                         if string(frame[0:HeartBeatSize]) == HeartBeatMark {
259                                 continue
260                         }
261                         if _, err := iface.Write(frame); err != nil {
262                                 log.Println("Error writing to iface: ", err)
263                         }
264                         if verbose {
265                                 fmt.Print("r")
266                         }
267                 case ethPktSize = <-ethSink:
268                         if ethPktSize > maxIfacePktSize {
269                                 panic("Too large packet on interface")
270                         }
271                         if peer == nil {
272                                 ethSinkReady <- true
273                                 continue
274                         }
275                         if ethPktSize > -1 {
276                                 copy(ethPkt, ethBuf[:ethPktSize])
277                                 ethSinkReady <- true
278                         } else {
279                                 copy(ethPkt, heartbeatMark)
280                                 ethPktSize = HeartBeatSize
281                         }
282                         peer.nonceOur = peer.nonceOur + 2
283                         binary.PutUvarint(nonce, peer.nonceOur)
284                         copy(buf[:KeySize], emptyKey)
285                         copy(buf[S20BS:], ethPkt[:ethPktSize])
286                         salsa20.XORKeyStream(buf, buf, nonce, peer.key)
287                         copy(buf[S20BS-NonceSize:S20BS], nonce)
288                         copy(keyAuth[:], buf[:KeySize])
289                         dataToSend := buf[S20BS-NonceSize : S20BS+ethPktSize]
290                         poly1305.Sum(tag, dataToSend, keyAuth)
291                         if _, err := conn.WriteTo(append(dataToSend, tag[:]...), peer.addr); err != nil {
292                                 log.Println("Error sending UDP", err)
293                         }
294                         if verbose {
295                                 fmt.Print("w")
296                         }
297                 }
298         }
299 }