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