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