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