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