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