2 govpn -- high-performance secure virtual private network daemon
3 Copyright (C) 2014 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/>.
30 "code.google.com/p/go.crypto/poly1305"
31 "code.google.com/p/go.crypto/salsa20"
35 remoteAddr = flag.String("remote", "", "Remote server address")
36 bindAddr = flag.String("bind", "", "Bind to address")
37 ifaceName = flag.String("iface", "tap0", "TAP network interface")
38 keyHex = flag.String("key", "", "Authentication key")
39 mtu = flag.Int("mtu", 1500, "MTU")
40 timeout = flag.Int("timeout", 60, "Timeout seconds")
41 verbose = flag.Bool("v", false, "Increase verbosity")
47 // S20BS is Salsa20's internal blocksize in bytes
58 key *[KeySize]byte // encryption key
59 nonceOur uint64 // nonce for our messages
60 nonceRecv uint64 // latest received nonce from remote peer
70 log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
73 if len(*keyHex) != 64 {
74 panic("Key is required argument (64 hex characters)")
76 keyDecoded, err := hex.DecodeString(*keyHex)
80 key := new([KeySize]byte)
81 copy(key[:], keyDecoded)
83 // Interface listening
84 maxIfacePktSize := *mtu - poly1305.TagSize - NonceSize
85 log.Println("Max MTU", maxIfacePktSize, "on interface", *ifaceName)
86 iface := NewTAP(*ifaceName)
87 ethBuf := make([]byte, maxIfacePktSize)
88 ethSink := make(chan int)
89 ethSinkReady := make(chan bool)
93 n, err := iface.Read(ethBuf)
102 // Network address parsing
103 if (len(*bindAddr) > 1 && len(*remoteAddr) > 1) ||
104 (len(*bindAddr) == 0 && len(*remoteAddr) == 0) {
105 panic("Either -bind or -remote must be specified only")
107 var conn *net.UDPConn
108 var remote *net.UDPAddr
110 bindTo := "0.0.0.0:0"
112 if len(*bindAddr) > 1 {
117 bind, err := net.ResolveUDPAddr("udp", bindTo)
121 conn, err = net.ListenUDP("udp", bind)
126 if len(*remoteAddr) > 1 {
127 remote, err = net.ResolveUDPAddr("udp", *remoteAddr)
133 udpBuf := make([]byte, *mtu)
134 udpSink := make(chan *UDPPkt)
135 udpSinkReady := make(chan bool)
136 go func(conn *net.UDPConn) {
139 conn.SetReadDeadline(time.Now().Add(time.Second))
140 n, addr, err := conn.ReadFromUDP(udpBuf)
147 udpSink <- &UDPPkt{addr, n}
155 var udpPktData []byte
162 states := make(map[string]*Handshake)
163 nonce := make([]byte, NonceSize)
164 keyAuth := new([KeySize]byte)
165 tag := new([poly1305.TagSize]byte)
166 buf := make([]byte, *mtu+S20BS)
167 emptyKey := make([]byte, KeySize)
168 ethPkt := make([]byte, maxIfacePktSize)
169 udpPktDataBuf := make([]byte, *mtu)
172 states[remote.String()] = HandshakeStart(conn, remote, key)
181 case udpPkt = <-udpSink:
183 if !serverMode && timeouts >= *timeout {
190 copy(udpPktDataBuf, udpBuf[:udpPkt.size])
192 udpPktData = udpPktDataBuf[:udpPkt.size]
193 if isValidHandshakePkt(udpPktData) {
194 addr = udpPkt.addr.String()
195 state, exists := states[addr]
198 state = &Handshake{addr: udpPkt.addr}
201 p = state.Server(conn, key, udpPktData)
207 p = state.Client(conn, key, udpPktData)
219 nonceRecv, _ := binary.Uvarint(udpPktData[:8])
220 if peer.nonceRecv >= nonceRecv {
224 copy(buf[:KeySize], emptyKey)
225 copy(tag[:], udpPktData[udpPkt.size-poly1305.TagSize:])
226 copy(buf[S20BS:], udpPktData[NonceSize:udpPkt.size-poly1305.TagSize])
227 salsa20.XORKeyStream(
228 buf[:S20BS+udpPkt.size-poly1305.TagSize],
229 buf[:S20BS+udpPkt.size-poly1305.TagSize],
230 udpPktData[:NonceSize],
233 copy(keyAuth[:], buf[:KeySize])
234 if !poly1305.Verify(tag, udpPktData[:udpPkt.size-poly1305.TagSize], keyAuth) {
238 peer.nonceRecv = nonceRecv
240 if _, err := iface.Write(buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]); err != nil {
241 log.Println("Error writing to iface: ", err)
246 case ethPktSize = <-ethSink:
247 if ethPktSize > maxIfacePktSize {
248 panic("Too large packet on interface")
254 copy(ethPkt, ethBuf[:ethPktSize])
256 peer.nonceOur = peer.nonceOur + 2
257 binary.PutUvarint(nonce, peer.nonceOur)
258 copy(buf[:KeySize], emptyKey)
259 copy(buf[S20BS:], ethPkt[:ethPktSize])
260 salsa20.XORKeyStream(buf, buf, nonce, peer.key)
261 copy(buf[S20BS-NonceSize:S20BS], nonce)
262 copy(keyAuth[:], buf[:KeySize])
263 dataToSend := buf[S20BS-NonceSize : S20BS+ethPktSize]
264 poly1305.Sum(tag, dataToSend, keyAuth)
265 if _, err := conn.WriteTo(append(dataToSend, tag[:]...), peer.addr); err != nil {
266 log.Println("Error sending UDP", err)