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