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