2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
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.
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.
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/>.
28 "golang.org/x/crypto/poly1305"
29 "golang.org/x/crypto/salsa20"
30 "golang.org/x/crypto/xtea"
36 // S20BS is Salsa20's internal blocksize in bytes
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
52 Key *[KeySize]byte `json:"-"`
53 NonceOur uint64 `json:"-"`
54 NonceRecv uint64 `json:"-"`
55 NonceCipher *xtea.Cipher `json:"-"`
59 tag *[poly1305.TagSize]byte
60 keyAuth *[KeySize]byte
77 func (p *Peer) String() string {
78 return p.Id.String() + ":" + p.Addr.String()
81 // Zero peer's memory state
82 func (p *Peer) Zero() {
85 sliceZero(p.keyAuth[:])
92 Emptiness = make([]byte, 1<<14)
93 taps = make(map[string]*TAP)
94 heartbeatPeriod *time.Duration
97 func heartbeatPeriodGet() time.Duration {
98 if heartbeatPeriod == nil {
99 period := time.Second * time.Duration(Timeout/4)
100 heartbeatPeriod = &period
102 return *heartbeatPeriod
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
111 func TAPListen(ifaceName string) (*TAP, chan []byte, chan struct{}, chan struct{}, error) {
114 tap, exists := taps[ifaceName]
116 tap, err = NewTAP(ifaceName)
118 return nil, nil, nil, nil, err
120 taps[ifaceName] = tap
122 sink := make(chan []byte)
123 sinkReady := make(chan struct{})
124 sinkTerminate := make(chan struct{})
125 sinkSkip := make(chan struct{})
128 heartbeat := time.Tick(heartbeatPeriodGet())
133 case <-sinkTerminate:
136 go func() { sink <- make([]byte, 0) }()
140 tap.ready <- struct{}{}
146 go func() { sink <- make([]byte, 0) }()
147 goto HeartbeatCatched
148 case <-sinkTerminate:
150 case pkt = <-tap.sink:
159 if exists && tap.synced {
160 sinkSkip <- struct{}{}
162 sinkReady <- struct{}{}
164 return tap, sink, sinkReady, sinkTerminate, nil
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) {
178 var addr *net.UDPAddr
182 conn.SetReadDeadline(time.Now().Add(time.Second))
183 n, addr, err = conn.ReadFromUDP(buf)
185 // This is needed for ticking the timeouts counter outside
186 sink <- UDPPkt{nil, 0}
189 sink <- UDPPkt{addr, n}
192 sinkReady <- struct{}{}
193 return sink, buf, sinkReady
196 func newNonceCipher(key *[KeySize]byte) *xtea.Cipher {
197 nonceKey := make([]byte, 16)
198 salsa20.XORKeyStream(
200 make([]byte, KeySize),
201 make([]byte, xtea.BlockSize),
204 ciph, err := xtea.NewCipher(nonceKey)
211 func newPeer(addr *net.UDPAddr, id PeerId, nonce int, key *[KeySize]byte) *Peer {
214 LastPing: time.Now(),
216 NonceOur: uint64(Noncediff + nonce),
217 NonceRecv: uint64(Noncediff + 0),
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),
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 {
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],
244 copy(p.keyAuth[:], p.buf[:KeySize])
245 if !poly1305.Verify(p.tag, udpPkt[:size-poly1305.TagSize], p.keyAuth) {
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 {
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])
266 p.frame = p.buf[S20BS+PktSizeSize : S20BS+PktSizeSize+p.pktSize]
267 p.BytesPayloadIn += int64(p.pktSize)
273 type WriteToer interface {
274 WriteTo([]byte, net.Addr) (int, error)
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{}) {
285 // If this heartbeat is necessary
286 if size == 0 && !p.LastSent.Add(heartbeatPeriodGet()).Before(now) {
289 copy(p.buf, Emptiness)
291 copy(p.buf[S20BS+PktSizeSize:], ethPkt)
293 binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(size))
294 p.BytesPayloadOut += int64(size)
300 copy(p.nonce, Emptiness)
301 binary.PutUvarint(p.nonce, p.NonceOur)
302 p.NonceCipher.Encrypt(p.nonce, p.nonce)
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])
308 p.frame = p.buf[S20BS-NonceSize : S20BS+MTU-NonceSize-poly1305.TagSize]
310 p.frame = p.buf[S20BS-NonceSize : S20BS+PktSizeSize+size]
312 poly1305.Sum(p.tag, p.frame, p.keyAuth)
314 p.BytesOut += int64(len(p.frame) + poly1305.TagSize)
317 if _, err := conn.WriteTo(append(p.frame, p.tag[:]...), p.Addr); err != nil {
318 log.Println("Error sending UDP", err)