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