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"
36 AliveTimeout = time.Second * 90
37 // S20BS is Salsa20's internal blocksize in bytes
44 key *[32]byte // encryption key
45 nonceOur uint64 // nonce for our messages
46 nonceRecv uint64 // latest received nonce from remote peer
49 func (p *Peer) IsAlive() bool {
50 if (p == nil) || (p.lastPing.Add(AliveTimeout).Before(time.Now())) {
56 func (p *Peer) SetAlive() {
57 p.lastPing = time.Now()
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")
76 log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
79 if len(*keyHex) != 64 {
80 panic("Key is required argument (64 hex characters)")
82 keyDecoded, err := hex.DecodeString(*keyHex)
87 copy(key[:], keyDecoded)
89 // Interface listening
90 maxIfacePktSize := *mtu - poly1305.TagSize - NonceSize
91 log.Println("Max MTU", maxIfacePktSize, "on interface", *ifaceName)
92 iface, err := water.NewTAP(*ifaceName)
96 ethSink := make(chan []byte)
99 buf := make([]byte, maxIfacePktSize)
100 n, err := iface.Read(buf)
108 // Network address parsing
109 if (len(*bindAddr) > 1 && len(*remoteAddr) > 1) ||
110 (len(*bindAddr) == 0 && len(*remoteAddr) == 0) {
111 panic("Either -bind or -remote must be specified only")
113 var conn *net.UDPConn
114 var remote *net.UDPAddr
116 bindTo := "0.0.0.0:0"
118 if len(*bindAddr) > 1 {
123 bind, err := net.ResolveUDPAddr("udp", bindTo)
127 conn, err = net.ListenUDP("udp", bind)
132 if len(*remoteAddr) > 1 {
133 remote, err = net.ResolveUDPAddr("udp", *remoteAddr)
139 udpSink := make(chan UDPPkt)
140 go func(conn *net.UDPConn) {
142 data := make([]byte, *mtu)
143 n, addr, err := conn.ReadFromUDP(data)
147 udpSink <- UDPPkt{addr, data[:n]}
159 states := make(map[string]*Handshake)
160 nonce := make([]byte, NonceSize)
161 keyAuth := new([32]byte)
162 tag := new([poly1305.TagSize]byte)
165 log.Println("starting handshake with", *remoteAddr)
166 states[remote.String()] = HandshakeStart(conn, remote, key)
170 buf = make([]byte, *mtu+S20BS)
172 case udpPkt = <-udpSink:
173 if isValidHandshakePkt(udpPkt.data) {
174 addr = udpPkt.addr.String()
175 state, exists := states[addr]
178 state = &Handshake{addr: udpPkt.addr}
181 p = state.Server(conn, key, udpPkt.data)
187 p = state.Client(conn, key, udpPkt.data)
199 nonceRecv, _ := binary.Uvarint(udpPkt.data[:8])
200 if peer.nonceRecv >= nonceRecv {
204 copy(tag[:], udpPkt.data[len(udpPkt.data)-poly1305.TagSize:])
205 copy(buf[S20BS:], udpPkt.data[NonceSize:len(udpPkt.data)-poly1305.TagSize])
206 salsa20.XORKeyStream(
207 buf[:S20BS+len(udpPkt.data)-poly1305.TagSize],
208 buf[:S20BS+len(udpPkt.data)-poly1305.TagSize],
209 udpPkt.data[:NonceSize],
212 copy(keyAuth[:], buf[:32])
213 if !poly1305.Verify(tag, udpPkt.data[:len(udpPkt.data)-poly1305.TagSize], keyAuth) {
217 peer.nonceRecv = nonceRecv
219 if _, err := iface.Write(buf[S20BS : S20BS+len(udpPkt.data)-NonceSize-poly1305.TagSize]); err != nil {
220 log.Println("Error writing to iface")
225 case ethPkt = <-ethSink:
226 if len(ethPkt) > maxIfacePktSize {
227 panic("Too large packet on interface")
232 peer.nonceOur = peer.nonceOur + 2
233 binary.PutUvarint(nonce, peer.nonceOur)
234 copy(buf[S20BS:], ethPkt)
235 salsa20.XORKeyStream(buf, buf, nonce, peer.key)
236 copy(buf[S20BS-NonceSize:S20BS], nonce)
237 copy(keyAuth[:], buf[:32])
238 dataToSend := buf[S20BS-NonceSize : S20BS+len(ethPkt)]
239 poly1305.Sum(tag, dataToSend, keyAuth)
240 if _, err := conn.WriteToUDP(append(dataToSend, tag[:]...), peer.addr); err != nil {
241 log.Println("Error sending UDP", err)