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/>.
29 "code.google.com/p/go.crypto/poly1305"
30 "code.google.com/p/go.crypto/salsa20"
31 "github.com/chon219/water"
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
53 key *[KeySize]byte // encryption key
54 nonceOur uint64 // nonce for our messages
55 nonceRecv uint64 // latest received nonce from remote peer
65 log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
68 if len(*keyHex) != 64 {
69 panic("Key is required argument (64 hex characters)")
71 keyDecoded, err := hex.DecodeString(*keyHex)
75 key := new([KeySize]byte)
76 copy(key[:], keyDecoded)
78 // Interface listening
79 maxIfacePktSize := *mtu - poly1305.TagSize - NonceSize
80 log.Println("Max MTU", maxIfacePktSize, "on interface", *ifaceName)
81 iface, err := water.NewTAP(*ifaceName)
85 ethBuf := make([]byte, maxIfacePktSize)
86 ethSink := make(chan int)
87 ethSinkReady := make(chan bool)
91 n, err := iface.Read(ethBuf)
100 // Network address parsing
101 if (len(*bindAddr) > 1 && len(*remoteAddr) > 1) ||
102 (len(*bindAddr) == 0 && len(*remoteAddr) == 0) {
103 panic("Either -bind or -remote must be specified only")
105 var conn *net.UDPConn
106 var remote *net.UDPAddr
108 bindTo := "0.0.0.0:0"
110 if len(*bindAddr) > 1 {
115 bind, err := net.ResolveUDPAddr("udp", bindTo)
119 conn, err = net.ListenUDP("udp", bind)
124 if len(*remoteAddr) > 1 {
125 remote, err = net.ResolveUDPAddr("udp", *remoteAddr)
131 udpBuf := make([]byte, *mtu)
132 udpSink := make(chan *UDPPkt)
133 udpSinkReady := make(chan bool)
134 go func(conn *net.UDPConn) {
137 conn.SetReadDeadline(time.Now().Add(time.Second))
138 n, addr, err := conn.ReadFromUDP(udpBuf)
145 udpSink <- &UDPPkt{addr, n}
153 var udpPktData []byte
160 states := make(map[string]*Handshake)
161 nonce := make([]byte, NonceSize)
162 keyAuth := new([KeySize]byte)
163 tag := new([poly1305.TagSize]byte)
164 buf := make([]byte, *mtu+S20BS)
165 emptyKey := make([]byte, KeySize)
166 ethPkt := make([]byte, maxIfacePktSize)
167 udpPktDataBuf := make([]byte, *mtu)
170 states[remote.String()] = HandshakeStart(conn, remote, key)
179 case udpPkt = <-udpSink:
181 if !serverMode && timeouts >= *timeout {
188 copy(udpPktDataBuf, udpBuf[:udpPkt.size])
190 udpPktData = udpPktDataBuf[:udpPkt.size]
191 if isValidHandshakePkt(udpPktData) {
192 addr = udpPkt.addr.String()
193 state, exists := states[addr]
196 state = &Handshake{addr: udpPkt.addr}
199 p = state.Server(conn, key, udpPktData)
205 p = state.Client(conn, key, udpPktData)
217 nonceRecv, _ := binary.Uvarint(udpPktData[:8])
218 if peer.nonceRecv >= nonceRecv {
222 copy(buf[:KeySize], emptyKey)
223 copy(tag[:], udpPktData[udpPkt.size-poly1305.TagSize:])
224 copy(buf[S20BS:], udpPktData[NonceSize:udpPkt.size-poly1305.TagSize])
225 salsa20.XORKeyStream(
226 buf[:S20BS+udpPkt.size-poly1305.TagSize],
227 buf[:S20BS+udpPkt.size-poly1305.TagSize],
228 udpPktData[:NonceSize],
231 copy(keyAuth[:], buf[:KeySize])
232 if !poly1305.Verify(tag, udpPktData[:udpPkt.size-poly1305.TagSize], keyAuth) {
236 peer.nonceRecv = nonceRecv
238 if _, err := iface.Write(buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]); err != nil {
239 log.Println("Error writing to iface")
244 case ethPktSize = <-ethSink:
245 if ethPktSize > maxIfacePktSize {
246 panic("Too large packet on interface")
252 copy(ethPkt, ethBuf[:ethPktSize])
254 peer.nonceOur = peer.nonceOur + 2
255 binary.PutUvarint(nonce, peer.nonceOur)
256 copy(buf[:KeySize], emptyKey)
257 copy(buf[S20BS:], ethPkt[:ethPktSize])
258 salsa20.XORKeyStream(buf, buf, nonce, peer.key)
259 copy(buf[S20BS-NonceSize:S20BS], nonce)
260 copy(keyAuth[:], buf[:KeySize])
261 dataToSend := buf[S20BS-NonceSize : S20BS+ethPktSize]
262 poly1305.Sum(tag, dataToSend, keyAuth)
263 if _, err := conn.WriteTo(append(dataToSend, tag[:]...), peer.addr); err != nil {
264 log.Println("Error sending UDP", err)