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