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 "code.google.com/p/gopacket"
32 "code.google.com/p/gopacket/pcap"
36 // NonceIncrServer is nonce increment value for server message
38 // NonceIncrClient is nonce increment value for client message
41 AliveTimeout = time.Second * 90
42 // S20BS is Salsa20's internal blocksize in bytes
49 key *[32]byte // encryption key
50 nonceOur uint64 // nonce for our messages
51 nonceRecv uint64 // latest received nonce from remote peer
54 func (p *Peer) IsAlive() bool {
55 if (p == nil) || (p.lastPing.Add(AliveTimeout).Before(time.Now())) {
61 func (p *Peer) SetAlive() {
62 p.lastPing = time.Now()
71 remoteAddr = flag.String("remote", "", "Remote server address")
72 bindAddr = flag.String("bind", "", "Bind to address")
73 ifaceName = flag.String("iface", "eth0", "Network interface")
74 keyHex = flag.String("key", "", "Authentication key")
75 mtu = flag.Int("mtu", 1500, "MTU")
80 log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
83 if len(*keyHex) != 64 {
84 panic("Key is required argument (64 hex characters)")
86 keyDecoded, err := hex.DecodeString(*keyHex)
91 copy(key[:], keyDecoded)
93 // Interface listening
94 iface, err := pcap.OpenLive(*ifaceName, int32(*mtu), true, 0)
98 ethSink := gopacket.NewPacketSource(iface, iface.LinkType()).Packets()
99 maxIfacePktSize := *mtu - poly1305.TagSize - NonceSize
100 log.Println("Max MTU", maxIfacePktSize, "on interface", *ifaceName)
102 // Network address parsing
103 if (len(*bindAddr) > 1 && len(*remoteAddr) > 1) || (len(*bindAddr) == 0 && len(*remoteAddr) == 0) {
104 panic("Either -bind or -remote must be specified only")
107 var conn *net.UDPConn
108 var remote *net.UDPAddr
111 nonceIncr := uint64(NonceIncrClient)
112 bindTo := "0.0.0.0:0"
114 if len(*bindAddr) > 1 {
117 nonceIncr = uint64(NonceIncrServer)
120 bind, err := net.ResolveUDPAddr("udp", bindTo)
124 conn, err = net.ListenUDP("udp", bind)
129 if len(*remoteAddr) > 1 {
130 remote, err = net.ResolveUDPAddr("udp", *remoteAddr)
136 udpSink := make(chan UDPPkt)
137 go func(conn *net.UDPConn, sink chan<- UDPPkt) {
138 data := make([]byte, *mtu)
140 n, addr, err := conn.ReadFromUDP(data)
144 sink <- UDPPkt{addr, data[:n]}
150 var ethPkt gopacket.Packet
156 states := make(map[string]*Handshake)
157 nonce := make([]byte, NonceSize)
158 keyAuth := new([32]byte)
159 tag := new([poly1305.TagSize]byte)
162 log.Println("starting handshake with", *remoteAddr)
163 states[remote.String()] = HandshakeStart(conn, remote, key)
167 buf = make([]byte, *mtu+S20BS)
169 case udpPkt = <-udpSink:
170 if isValidHandshakePkt(udpPkt.data) {
171 addr = udpPkt.addr.String()
172 state, exists := states[addr]
175 state = &Handshake{addr: udpPkt.addr}
178 p = state.Server(conn, key, udpPkt.data)
184 p = state.Client(conn, key, udpPkt.data)
196 nonceRecv, _ := binary.Uvarint(udpPkt.data[:8])
197 if peer.nonceRecv >= nonceRecv {
200 copy(tag[:], udpPkt.data[len(udpPkt.data)-poly1305.TagSize:])
201 copy(buf[S20BS:], udpPkt.data[NonceSize:len(udpPkt.data)-poly1305.TagSize])
202 salsa20.XORKeyStream(
203 buf[:S20BS+len(udpPkt.data)-poly1305.TagSize],
204 buf[:S20BS+len(udpPkt.data)-poly1305.TagSize],
205 udpPkt.data[:NonceSize],
208 copy(keyAuth[:], buf[:32])
209 if !poly1305.Verify(tag, udpPkt.data[:len(udpPkt.data)-poly1305.TagSize], keyAuth) {
213 peer.nonceRecv = nonceRecv
215 if err := iface.WritePacketData(buf[S20BS : S20BS+len(udpPkt.data)-NonceSize-poly1305.TagSize]); err != nil {
216 log.Println("Error writing to iface")
219 case ethPkt = <-ethSink:
220 if len(ethPkt.Data()) > maxIfacePktSize {
221 panic("Too large packet on interface")
226 peer.nonceOur = peer.nonceOur + nonceIncr
227 pktData := ethPkt.Data()
228 binary.PutUvarint(nonce, peer.nonceOur)
229 copy(buf[S20BS:], pktData)
230 salsa20.XORKeyStream(buf, buf, nonce, peer.key)
231 copy(buf[S20BS-NonceSize:S20BS], nonce)
232 copy(keyAuth[:], buf[:32])
233 poly1305.Sum(tag, buf[S20BS-NonceSize:S20BS+len(pktData)], keyAuth)
234 _, err := conn.WriteTo(append(buf[S20BS-NonceSize:S20BS+len(pktData)], tag[:]...), peer.addr)
236 log.Println("Error sending UDP", err)