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