]> Cypherpunks.ru repositories - govpn.git/blob - govpn.go
Ability to decrease verbosity
[govpn.git] / govpn.go
1 /*
2 govpn -- high-performance secure virtual private network daemon
3 Copyright (C) 2014 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 package main
19
20 import (
21         "encoding/binary"
22         "encoding/hex"
23         "flag"
24         "fmt"
25         "log"
26         "net"
27         "time"
28
29         "code.google.com/p/go.crypto/poly1305"
30         "code.google.com/p/go.crypto/salsa20"
31         "github.com/chon219/water"
32 )
33
34 const (
35         NonceSize    = 8
36         AliveTimeout = time.Second * 90
37         // S20BS is Salsa20's internal blocksize in bytes
38         S20BS = 64
39 )
40
41 type Peer struct {
42         addr      *net.UDPAddr
43         lastPing  time.Time
44         key       *[32]byte // encryption key
45         nonceOur  uint64    // nonce for our messages
46         nonceRecv uint64    // latest received nonce from remote peer
47 }
48
49 func (p *Peer) IsAlive() bool {
50         if (p == nil) || (p.lastPing.Add(AliveTimeout).Before(time.Now())) {
51                 return false
52         }
53         return true
54 }
55
56 func (p *Peer) SetAlive() {
57         p.lastPing = time.Now()
58 }
59
60 type UDPPkt struct {
61         addr *net.UDPAddr
62         data []byte
63 }
64
65 var (
66         remoteAddr = flag.String("remote", "", "Remote server address")
67         bindAddr   = flag.String("bind", "", "Bind to address")
68         ifaceName  = flag.String("iface", "tap0", "TAP network interface")
69         keyHex     = flag.String("key", "", "Authentication key")
70         mtu        = flag.Int("mtu", 1500, "MTU")
71         verbose    = flag.Bool("v", false, "Increase verbosity")
72 )
73
74 func main() {
75         flag.Parse()
76         log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
77
78         // Key decoding
79         if len(*keyHex) != 64 {
80                 panic("Key is required argument (64 hex characters)")
81         }
82         keyDecoded, err := hex.DecodeString(*keyHex)
83         if err != nil {
84                 panic(err)
85         }
86         key := new([32]byte)
87         copy(key[:], keyDecoded)
88
89         // Interface listening
90         maxIfacePktSize := *mtu - poly1305.TagSize - NonceSize
91         log.Println("Max MTU", maxIfacePktSize, "on interface", *ifaceName)
92         iface, err := water.NewTAP(*ifaceName)
93         if err != nil {
94                 panic(err)
95         }
96         ethSink := make(chan []byte)
97         go func() {
98                 for {
99                         buf := make([]byte, maxIfacePktSize)
100                         n, err := iface.Read(buf)
101                         if err != nil {
102                                 panic(err)
103                         }
104                         ethSink <- buf[:n]
105                 }
106         }()
107
108         // Network address parsing
109         if (len(*bindAddr) > 1 && len(*remoteAddr) > 1) || (len(*bindAddr) == 0 && len(*remoteAddr) == 0) {
110                 panic("Either -bind or -remote must be specified only")
111         }
112
113         var conn *net.UDPConn
114         var remote *net.UDPAddr
115
116         serverMode := false
117         bindTo := "0.0.0.0:0"
118
119         if len(*bindAddr) > 1 {
120                 bindTo = *bindAddr
121                 serverMode = true
122         }
123
124         bind, err := net.ResolveUDPAddr("udp", bindTo)
125         if err != nil {
126                 panic(err)
127         }
128         conn, err = net.ListenUDP("udp", bind)
129         if err != nil {
130                 panic(err)
131         }
132
133         if len(*remoteAddr) > 1 {
134                 remote, err = net.ResolveUDPAddr("udp", *remoteAddr)
135                 if err != nil {
136                         panic(err)
137                 }
138         }
139
140         udpSink := make(chan UDPPkt)
141         go func(conn *net.UDPConn, sink chan<- UDPPkt) {
142                 for {
143                         data := make([]byte, *mtu)
144                         n, addr, err := conn.ReadFromUDP(data)
145                         if err != nil {
146                                 fmt.Print("B")
147                         }
148                         sink <- UDPPkt{addr, data[:n]}
149                 }
150         }(conn, udpSink)
151
152         // Process packets
153         var udpPkt UDPPkt
154         var ethPkt []byte
155         var addr string
156         var peer Peer
157         var p *Peer
158         var buf []byte
159
160         states := make(map[string]*Handshake)
161         nonce := make([]byte, NonceSize)
162         keyAuth := new([32]byte)
163         tag := new([poly1305.TagSize]byte)
164
165         if !serverMode {
166                 log.Println("starting handshake with", *remoteAddr)
167                 states[remote.String()] = HandshakeStart(conn, remote, key)
168         }
169
170         for {
171                 buf = make([]byte, *mtu+S20BS)
172                 select {
173                 case udpPkt = <-udpSink:
174                         if isValidHandshakePkt(udpPkt.data) {
175                                 addr = udpPkt.addr.String()
176                                 state, exists := states[addr]
177                                 if serverMode {
178                                         if !exists {
179                                                 state = &Handshake{addr: udpPkt.addr}
180                                                 states[addr] = state
181                                         }
182                                         p = state.Server(conn, key, udpPkt.data)
183                                 } else {
184                                         if !exists {
185                                                 fmt.Print("[HS?]")
186                                                 continue
187                                         }
188                                         p = state.Client(conn, key, udpPkt.data)
189                                 }
190                                 if p != nil {
191                                         fmt.Print("[HS-OK]")
192                                         peer = *p
193                                         delete(states, addr)
194                                 }
195                                 continue
196                         }
197                         if !peer.IsAlive() {
198                                 continue
199                         }
200                         nonceRecv, _ := binary.Uvarint(udpPkt.data[:8])
201                         if peer.nonceRecv >= nonceRecv {
202                                 fmt.Print("R")
203                                 continue
204                         }
205                         copy(tag[:], udpPkt.data[len(udpPkt.data)-poly1305.TagSize:])
206                         copy(buf[S20BS:], udpPkt.data[NonceSize:len(udpPkt.data)-poly1305.TagSize])
207                         salsa20.XORKeyStream(
208                                 buf[:S20BS+len(udpPkt.data)-poly1305.TagSize],
209                                 buf[:S20BS+len(udpPkt.data)-poly1305.TagSize],
210                                 udpPkt.data[:NonceSize],
211                                 peer.key,
212                         )
213                         copy(keyAuth[:], buf[:32])
214                         if !poly1305.Verify(tag, udpPkt.data[:len(udpPkt.data)-poly1305.TagSize], keyAuth) {
215                                 fmt.Print("T")
216                                 continue
217                         }
218                         peer.nonceRecv = nonceRecv
219                         peer.SetAlive()
220                         if _, err := iface.Write(buf[S20BS : S20BS+len(udpPkt.data)-NonceSize-poly1305.TagSize]); err != nil {
221                                 log.Println("Error writing to iface")
222                         }
223                         if *verbose {
224                                 fmt.Print("r")
225                         }
226                 case ethPkt = <-ethSink:
227                         if len(ethPkt) > maxIfacePktSize {
228                                 panic("Too large packet on interface")
229                         }
230                         if !peer.IsAlive() {
231                                 continue
232                         }
233                         peer.nonceOur = peer.nonceOur + 2
234                         binary.PutUvarint(nonce, peer.nonceOur)
235                         copy(buf[S20BS:], ethPkt)
236                         salsa20.XORKeyStream(buf, buf, nonce, peer.key)
237                         copy(buf[S20BS-NonceSize:S20BS], nonce)
238                         copy(keyAuth[:], buf[:32])
239                         dataToSend := buf[S20BS-NonceSize : S20BS+len(ethPkt)]
240                         poly1305.Sum(tag, dataToSend, keyAuth)
241                         _, err := conn.WriteTo(append(dataToSend, tag[:]...), peer.addr)
242                         if err != nil {
243                                 log.Println("Error sending UDP", err)
244                         }
245                         if *verbose {
246                                 fmt.Print("w")
247                         }
248                 }
249         }
250 }