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