]> Cypherpunks.ru repositories - govpn.git/blob - transport.go
eb02494ce9d7f2f36572e392082fd9938a80c651
[govpn.git] / transport.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2015 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 package govpn
20
21 import (
22         "encoding/binary"
23         "io"
24         "log"
25         "net"
26         "time"
27
28         "golang.org/x/crypto/poly1305"
29         "golang.org/x/crypto/salsa20"
30         "golang.org/x/crypto/xtea"
31 )
32
33 const (
34         NonceSize = 8
35         KeySize   = 32
36         // S20BS is Salsa20's internal blocksize in bytes
37         S20BS = 64
38         // Maximal amount of bytes transfered with single key (4 GiB)
39         MaxBytesPerKey int64 = 1 << 32
40         // Size of packet's size mark in bytes
41         PktSizeSize = 2
42         // Heartbeat rate, relative to Timeout
43         TimeoutHeartbeat = 4
44 )
45
46 type UDPPkt struct {
47         Addr *net.UDPAddr
48         Size int
49 }
50
51 type Peer struct {
52         Addr            *net.UDPAddr
53         Id              PeerId
54         Key             *[KeySize]byte `json:"-"`
55         NonceOur        uint64         `json:"-"`
56         NonceRecv       uint64         `json:"-"`
57         NonceCipher     *xtea.Cipher   `json:"-"`
58         LastPing        time.Time
59         LastSent        time.Time
60         buf             []byte
61         tag             *[poly1305.TagSize]byte
62         keyAuth         *[KeySize]byte
63         nonceRecv       uint64
64         frame           []byte
65         nonce           []byte
66         pktSize         uint64
67         BytesIn         int64
68         BytesOut        int64
69         BytesPayloadIn  int64
70         BytesPayloadOut int64
71         FramesIn        int
72         FramesOut       int
73         FramesUnauth    int
74         FramesDup       int
75         HeartbeatRecv   int
76         HeartbeatSent   int
77 }
78
79 func (p *Peer) String() string {
80         return p.Id.String() + ":" + p.Addr.String()
81 }
82
83 // Zero peer's memory state
84 func (p *Peer) Zero() {
85         sliceZero(p.Key[:])
86         sliceZero(p.tag[:])
87         sliceZero(p.keyAuth[:])
88         sliceZero(p.buf)
89         sliceZero(p.frame)
90         sliceZero(p.nonce)
91 }
92
93 var (
94         Emptiness       = make([]byte, 1<<14)
95         taps            = make(map[string]*TAP)
96         heartbeatPeriod time.Duration
97 )
98
99 func heartbeatPeriodGet() time.Duration {
100         if heartbeatPeriod == time.Duration(0) {
101                 heartbeatPeriod = Timeout / TimeoutHeartbeat
102         }
103         return heartbeatPeriod
104 }
105
106 // Create TAP listening goroutine.
107 // This function takes required TAP interface name, opens it and allocates
108 // a buffer where all frame data will be written, channel where information
109 // about number of read bytes is sent to, synchronization channel (external
110 // processes tell that read buffer can be used again) and possible channel
111 // opening error.
112 func TAPListen(ifaceName string) (*TAP, chan []byte, chan struct{}, chan struct{}, error) {
113         var tap *TAP
114         var err error
115         tap, exists := taps[ifaceName]
116         if !exists {
117                 tap, err = NewTAP(ifaceName)
118                 if err != nil {
119                         return nil, nil, nil, nil, err
120                 }
121                 taps[ifaceName] = tap
122         }
123         sink := make(chan []byte)
124         sinkReady := make(chan struct{})
125         sinkTerminate := make(chan struct{})
126         sinkSkip := make(chan struct{})
127
128         go func() {
129                 heartbeat := time.Tick(heartbeatPeriodGet())
130                 var pkt []byte
131         ListenCycle:
132                 for {
133                         select {
134                         case <-sinkTerminate:
135                                 break ListenCycle
136                         case <-heartbeat:
137                                 go func() { sink <- make([]byte, 0) }()
138                                 continue
139                         case <-sinkSkip:
140                         case <-sinkReady:
141                                 tap.ready <- struct{}{}
142                                 tap.synced = true
143                         }
144                 HeartbeatCatched:
145                         select {
146                         case <-heartbeat:
147                                 go func() { sink <- make([]byte, 0) }()
148                                 goto HeartbeatCatched
149                         case <-sinkTerminate:
150                                 break ListenCycle
151                         case pkt = <-tap.sink:
152                                 tap.synced = false
153                                 sink <- pkt
154                         }
155                 }
156                 close(sink)
157                 close(sinkReady)
158                 close(sinkTerminate)
159         }()
160         if exists && tap.synced {
161                 sinkSkip <- struct{}{}
162         } else {
163                 sinkReady <- struct{}{}
164         }
165         return tap, sink, sinkReady, sinkTerminate, nil
166 }
167
168 // Create UDP listening goroutine.
169 // This function takes already listening UDP socket and a buffer where
170 // all UDP packet data will be saved, channel where information about
171 // remote address and number of written bytes are stored, and a channel
172 // used to tell that buffer is ready to be overwritten.
173 func ConnListen(conn *net.UDPConn) (chan UDPPkt, []byte, chan struct{}) {
174         buf := make([]byte, MTU)
175         sink := make(chan UDPPkt)
176         sinkReady := make(chan struct{})
177         go func(conn *net.UDPConn) {
178                 var n int
179                 var addr *net.UDPAddr
180                 var err error
181                 for {
182                         <-sinkReady
183                         conn.SetReadDeadline(time.Now().Add(time.Second))
184                         n, addr, err = conn.ReadFromUDP(buf)
185                         if err != nil {
186                                 // This is needed for ticking the timeouts counter outside
187                                 sink <- UDPPkt{nil, 0}
188                                 continue
189                         }
190                         sink <- UDPPkt{addr, n}
191                 }
192         }(conn)
193         sinkReady <- struct{}{}
194         return sink, buf, sinkReady
195 }
196
197 func newNonceCipher(key *[KeySize]byte) *xtea.Cipher {
198         nonceKey := make([]byte, 16)
199         salsa20.XORKeyStream(
200                 nonceKey,
201                 make([]byte, KeySize),
202                 make([]byte, xtea.BlockSize),
203                 key,
204         )
205         ciph, err := xtea.NewCipher(nonceKey)
206         if err != nil {
207                 panic(err)
208         }
209         return ciph
210 }
211
212 func newPeer(addr *net.UDPAddr, id PeerId, nonce int, key *[KeySize]byte) *Peer {
213         peer := Peer{
214                 Addr:        addr,
215                 LastPing:    time.Now(),
216                 Id:          id,
217                 NonceOur:    uint64(Noncediff + nonce),
218                 NonceRecv:   uint64(Noncediff + 0),
219                 Key:         key,
220                 NonceCipher: newNonceCipher(key),
221                 buf:         make([]byte, MTU+S20BS),
222                 tag:         new([poly1305.TagSize]byte),
223                 keyAuth:     new([KeySize]byte),
224                 nonce:       make([]byte, NonceSize),
225         }
226         return &peer
227 }
228
229 // Process incoming UDP packet.
230 // udpPkt is received data, related to the peer tap interface and
231 // ConnListen'es synchronization channel used to tell him that he is
232 // free to receive new packets. Authenticated and decrypted packets
233 // will be written to the interface immediately (except heartbeat ones).
234 func (p *Peer) UDPProcess(udpPkt []byte, tap io.Writer, ready chan struct{}) bool {
235         size := len(udpPkt)
236         copy(p.buf, Emptiness)
237         copy(p.tag[:], udpPkt[size-poly1305.TagSize:])
238         copy(p.buf[S20BS:], udpPkt[NonceSize:size-poly1305.TagSize])
239         salsa20.XORKeyStream(
240                 p.buf[:S20BS+size-poly1305.TagSize],
241                 p.buf[:S20BS+size-poly1305.TagSize],
242                 udpPkt[:NonceSize],
243                 p.Key,
244         )
245         copy(p.keyAuth[:], p.buf[:KeySize])
246         if !poly1305.Verify(p.tag, udpPkt[:size-poly1305.TagSize], p.keyAuth) {
247                 ready <- struct{}{}
248                 p.FramesUnauth++
249                 return false
250         }
251         p.NonceCipher.Decrypt(p.buf, udpPkt[:NonceSize])
252         p.nonceRecv, _ = binary.Uvarint(p.buf[:NonceSize])
253         if int(p.NonceRecv)-Noncediff >= 0 && int(p.nonceRecv) < int(p.NonceRecv)-Noncediff {
254                 ready <- struct{}{}
255                 p.FramesDup++
256                 return false
257         }
258         ready <- struct{}{}
259         p.BytesIn += int64(size)
260         p.LastPing = time.Now()
261         p.NonceRecv = p.nonceRecv
262         p.pktSize, _ = binary.Uvarint(p.buf[S20BS : S20BS+PktSizeSize])
263         if p.pktSize == 0 {
264                 p.HeartbeatRecv++
265                 return true
266         }
267         p.frame = p.buf[S20BS+PktSizeSize : S20BS+PktSizeSize+p.pktSize]
268         p.BytesPayloadIn += int64(p.pktSize)
269         p.FramesIn++
270         tap.Write(p.frame)
271         return true
272 }
273
274 type WriteToer interface {
275         WriteTo([]byte, net.Addr) (int, error)
276 }
277
278 // Process incoming Ethernet packet.
279 // ethPkt is received data, conn is our outgoing connection.
280 // ready channel is TAPListen's synchronization channel used to tell him
281 // that he is free to receive new packets. Encrypted and authenticated
282 // packets will be sent to remote Peer side immediately.
283 func (p *Peer) EthProcess(ethPkt []byte, conn WriteToer, ready chan struct{}) {
284         now := time.Now()
285         size := len(ethPkt)
286         // If this heartbeat is necessary
287         if size == 0 && !p.LastSent.Add(heartbeatPeriodGet()).Before(now) {
288                 return
289         }
290         copy(p.buf, Emptiness)
291         if size > 0 {
292                 copy(p.buf[S20BS+PktSizeSize:], ethPkt)
293                 ready <- struct{}{}
294                 binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(size))
295                 p.BytesPayloadOut += int64(size)
296         } else {
297                 p.HeartbeatSent++
298         }
299
300         p.NonceOur += 2
301         copy(p.nonce, Emptiness)
302         binary.PutUvarint(p.nonce, p.NonceOur)
303         p.NonceCipher.Encrypt(p.nonce, p.nonce)
304
305         salsa20.XORKeyStream(p.buf, p.buf, p.nonce, p.Key)
306         copy(p.buf[S20BS-NonceSize:S20BS], p.nonce)
307         copy(p.keyAuth[:], p.buf[:KeySize])
308         if NoiseEnable {
309                 p.frame = p.buf[S20BS-NonceSize : S20BS+MTU-NonceSize-poly1305.TagSize]
310         } else {
311                 p.frame = p.buf[S20BS-NonceSize : S20BS+PktSizeSize+size]
312         }
313         poly1305.Sum(p.tag, p.frame, p.keyAuth)
314
315         p.BytesOut += int64(len(p.frame) + poly1305.TagSize)
316         p.FramesOut++
317         p.LastSent = now
318         if _, err := conn.WriteTo(append(p.frame, p.tag[:]...), p.Addr); err != nil {
319                 log.Println("Error sending UDP", err)
320         }
321 }