if err != nil {
log.Fatalln("Can not resolve address:", err)
}
- conn, err := net.ListenUDP("udp", bind)
+ conn, err := net.DialUDP("udp", bind, remote)
if err != nil {
log.Fatalln("Can not listen on UDP:", err)
}
log.Fatalln("Can not resolve remote address:", err)
}
+ sink := make(chan []byte)
+ ready := make(chan struct{})
+ go func() {
+ buf := make([]byte, govpn.MTU)
+ var n int
+ var err error
+ for {
+ <-ready
+ conn.SetReadDeadline(time.Now().Add(time.Second))
+ n, err = conn.Read(buf)
+ if err != nil {
+ // This is needed for ticking the timeouts counter outside
+ sink <- nil
+ continue
+ }
+ sink <- buf[:n]
+ }
+ }()
+ ready <- struct{}{}
+
tap, ethSink, ethReady, _, err := govpn.TAPListen(
*ifaceName,
time.Second*time.Duration(timeout),
if err != nil {
log.Fatalln("Can not listen on TAP interface:", err)
}
- udpSink, udpReady := govpn.ConnListenUDP(conn)
timeouts := 0
firstUpCall := true
var peer *govpn.Peer
var ethPkt []byte
- var udpPkt govpn.UDPPkt
+ var pkt []byte
knownPeers := govpn.KnownPeers(map[string]**govpn.Peer{remote.String(): &peer})
log.Println(govpn.VersionGet())
signal.Notify(termSignal, os.Interrupt, os.Kill)
log.Println("Starting handshake")
- handshake := govpn.HandshakeStart(conf, conn, remote)
+ handshake := govpn.HandshakeStart(remote.String(), conn, conf)
MainCycle:
for {
if peer != nil && (peer.BytesIn+peer.BytesOut) > govpn.MaxBytesPerKey {
peer.Zero()
peer = nil
- handshake = govpn.HandshakeStart(conf, conn, remote)
+ handshake = govpn.HandshakeStart(remote.String(), conn, conf)
log.Println("Rehandshaking")
}
select {
}
continue
}
- peer.EthProcess(ethPkt, conn, ethReady)
- case udpPkt = <-udpSink:
+ peer.EthProcess(ethPkt, ethReady)
+ case pkt = <-sink:
timeouts++
if timeouts >= timeout {
break MainCycle
}
- if udpPkt.Addr == nil {
- udpReady <- struct{}{}
+ if pkt == nil {
+ ready <- struct{}{}
continue
}
if peer == nil {
- if udpPkt.Addr.String() != remote.String() {
- udpReady <- struct{}{}
- log.Println("Unknown handshake message")
- continue
- }
- if govpn.IDsCache.Find(udpPkt.Data) == nil {
+ if govpn.IDsCache.Find(pkt) == nil {
log.Println("Invalid identity in handshake packet")
- udpReady <- struct{}{}
+ ready <- struct{}{}
continue
}
- if p := handshake.Client(conn, udpPkt.Data); p != nil {
+ if p := handshake.Client(pkt); p != nil {
log.Println("Handshake completed")
if firstUpCall {
go govpn.ScriptCall(*upPath, *ifaceName)
handshake.Zero()
handshake = nil
}
- udpReady <- struct{}{}
+ ready <- struct{}{}
continue
}
if peer == nil {
- udpReady <- struct{}{}
+ ready <- struct{}{}
continue
}
- if peer.UDPProcess(udpPkt.Data, tap, udpReady) {
+ if peer.PktProcess(pkt, tap, ready) {
timeouts = 0
}
}
import (
"bytes"
"flag"
+ "io"
"log"
"net"
"os"
egdPath = flag.String("egd", "", "Optional path to EGD socket")
)
+type Pkt struct {
+ addr string
+ conn io.Writer
+ data []byte
+}
+
+type UDPSender struct {
+ conn *net.UDPConn
+ addr *net.UDPAddr
+}
+
+func (c UDPSender) Write(data []byte) (int, error) {
+ return c.conn.WriteToUDP(data, c.addr)
+}
+
type PeerReadyEvent struct {
peer *govpn.Peer
iface string
if err != nil {
log.Fatalln("Can not resolve bind address:", err)
}
- conn, err := net.ListenUDP("udp", bind)
+ lconn, err := net.ListenUDP("udp", bind)
if err != nil {
log.Fatalln("Can listen on UDP:", err)
}
- udpSink, udpReady := govpn.ConnListenUDP(conn)
+
+ sink := make(chan Pkt)
+ ready := make(chan struct{})
+ go func() {
+ buf := make([]byte, govpn.MTU)
+ var n int
+ var raddr *net.UDPAddr
+ var err error
+ for {
+ <-ready
+ lconn.SetReadDeadline(time.Now().Add(time.Second))
+ n, raddr, err = lconn.ReadFromUDP(buf)
+ if err != nil {
+ // This is needed for ticking the timeouts counter outside
+ sink <- Pkt{}
+ continue
+ }
+ sink <- Pkt{raddr.String(), UDPSender{lconn, raddr}, buf[:n]}
+ }
+ }()
+ ready <- struct{}{}
termSignal := make(chan os.Signal, 1)
signal.Notify(termSignal, os.Interrupt, os.Kill)
hsHeartbeat := time.Tick(timeout)
go func() { <-hsHeartbeat }()
- var addr string
var state *govpn.Handshake
var peerState *PeerState
var peer *govpn.Peer
peerReadySink := make(chan PeerReadyEvent)
knownPeers := govpn.KnownPeers(make(map[string]**govpn.Peer))
var peerReady PeerReadyEvent
- var udpPkt govpn.UDPPkt
+ var pkt Pkt
var ethEvent EthEvent
var peerId *govpn.PeerId
var peerConf *govpn.PeerConf
state.peer.Zero()
break
}
- addr = peerReady.peer.Addr.String()
state := NewPeerState(peerReady.peer, peerReady.iface)
if state == nil {
continue
}
- peers[addr] = state
- knownPeers[addr] = &peerReady.peer
- states[addr].Zero()
- delete(states, addr)
+ peers[peerReady.peer.Addr] = state
+ knownPeers[peerReady.peer.Addr] = &peerReady.peer
+ states[peerReady.peer.Addr].Zero()
+ delete(states, peerReady.peer.Addr)
log.Println("Registered interface", peerReady.iface, "with peer", peer)
go func(state *PeerState) {
for data := range state.sink {
}
}(state)
case ethEvent = <-ethSink:
- if s, exists := peers[ethEvent.peer.Addr.String()]; !exists || s.peer != ethEvent.peer {
+ if s, exists := peers[ethEvent.peer.Addr]; !exists || s.peer != ethEvent.peer {
continue
}
- ethEvent.peer.EthProcess(ethEvent.data, conn, ethEvent.ready)
- case udpPkt = <-udpSink:
- if udpPkt.Addr == nil {
- udpReady <- struct{}{}
+ ethEvent.peer.EthProcess(ethEvent.data, ethEvent.ready)
+ case pkt = <-sink:
+ if pkt.data == nil {
+ ready <- struct{}{}
continue
}
- addr = udpPkt.Addr.String()
handshakeProcessForce = false
HandshakeProcess:
- if _, exists = peers[addr]; handshakeProcessForce || !exists {
- peerId = govpn.IDsCache.Find(udpPkt.Data)
+ if _, exists = peers[pkt.addr]; handshakeProcessForce || !exists {
+ peerId = govpn.IDsCache.Find(pkt.data)
if peerId == nil {
- log.Println("Unknown identity from", addr)
- udpReady <- struct{}{}
+ log.Println("Unknown identity from", pkt.addr)
+ ready <- struct{}{}
continue
}
peerConf = peerId.Conf()
if peerConf == nil {
log.Println("Can not get peer configuration", peerId.String())
- udpReady <- struct{}{}
+ ready <- struct{}{}
continue
}
- state, exists = states[addr]
+ state, exists = states[pkt.addr]
if !exists {
- state = govpn.HandshakeNew(udpPkt.Addr, peerConf)
- states[addr] = state
+ state = govpn.HandshakeNew(pkt.addr, pkt.conn, peerConf)
+ states[pkt.addr] = state
}
- peer = state.Server(conn, udpPkt.Data)
+ peer = state.Server(pkt.data)
if peer != nil {
log.Println("Peer handshake finished", peer)
- if _, exists = peers[addr]; exists {
+ if _, exists = peers[pkt.addr]; exists {
go func() {
- peerReadySink <- PeerReadyEvent{peer, peers[addr].tap.Name}
+ peerReadySink <- PeerReadyEvent{
+ peer, peers[pkt.addr].tap.Name,
+ }
}()
} else {
go func() {
}
}
if !handshakeProcessForce {
- udpReady <- struct{}{}
+ ready <- struct{}{}
}
continue
}
- peerState, exists = peers[addr]
+ peerState, exists = peers[pkt.addr]
if !exists {
- udpReady <- struct{}{}
+ ready <- struct{}{}
continue
}
// If it fails during processing, then try to work with it
// as with handshake packet
- if !peerState.peer.UDPProcess(udpPkt.Data, peerState.tap, udpReady) {
+ if !peerState.peer.PktProcess(pkt.data, peerState.tap, ready) {
handshakeProcessForce = true
goto HandshakeProcess
}
"crypto/rand"
"crypto/subtle"
"encoding/binary"
+ "io"
"log"
- "net"
"time"
"github.com/agl/ed25519"
)
type Handshake struct {
- addr *net.UDPAddr
+ addr string
+ conn io.Writer
LastPing time.Time
Conf *PeerConf
dsaPubH *[ed25519.PublicKeySize]byte
}
// Create new handshake state.
-func HandshakeNew(addr *net.UDPAddr, conf *PeerConf) *Handshake {
+func HandshakeNew(addr string, conn io.Writer, conf *PeerConf) *Handshake {
state := Handshake{
addr: addr,
+ conn: conn,
LastPing: time.Now(),
Conf: conf,
}
}
// Start handshake's procedure from the client. It is the entry point
-// for starting the handshake procedure. You have to specify outgoing
-// conn address, remote's addr address, our own peer configuration.
-// First handshake packet will be sent immediately.
-func HandshakeStart(conf *PeerConf, conn *net.UDPConn, addr *net.UDPAddr) *Handshake {
- state := HandshakeNew(addr, conf)
+// for starting the handshake procedure. // First handshake packet
+// will be sent immediately.
+func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake {
+ state := HandshakeNew(addr, conn, conf)
var dhPubRepr *[32]byte
state.dhPriv, dhPubRepr = dhKeypairGen()
salsa20.XORKeyStream(enc, dhPubRepr[:], state.rNonce[:], state.dsaPubH)
data := append(state.rNonce[:], enc...)
data = append(data, idTag(state.Conf.Id, state.rNonce[:])...)
- conn.WriteToUDP(data, addr)
+ state.conn.Write(data)
return state
}
// Process handshake message on the server side.
// This function is intended to be called on server's side.
-// Our outgoing conn connection and received data are required.
// If this is the final handshake message, then new Peer object
// will be created and used as a transport. If no mutually
// authenticated Peer is ready, then return nil.
-func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
+func (h *Handshake) Server(data []byte) *Peer {
// R + ENC(H(DSAPub), R, El(CDHPub)) + IDtag
if len(data) == 48 && h.rNonce == nil {
// Generate DH keypair
salsa20.XORKeyStream(encRs, append(h.rServer[:], h.sServer[:]...), h.rNonce[:], h.key)
// Send that to client
- conn.WriteToUDP(append(encPub, append(encRs, idTag(h.Conf.Id, encPub)...)...), h.addr)
+ h.conn.Write(append(encPub, append(encRs, idTag(h.Conf.Id, encPub)...)...))
h.LastPing = time.Now()
} else
// ENC(K, R+1, RS + RC + SC + Sign(DSAPriv, K)) + IDtag
// Send final answer to client
enc := make([]byte, RSize)
salsa20.XORKeyStream(enc, dec[RSize:RSize+RSize], h.rNonceNext(2), h.key)
- conn.WriteToUDP(append(enc, idTag(h.Conf.Id, enc)...), h.addr)
+ h.conn.Write(append(enc, idTag(h.Conf.Id, enc)...))
// Switch peer
peer := newPeer(
h.addr,
+ h.conn,
h.Conf,
0,
keyFromSecrets(h.sServer[:], dec[RSize+RSize:RSize+RSize+SSize]))
// Process handshake message on the client side.
// This function is intended to be called on client's side.
-// Our outgoing conn connection, authentication
-// key and received data are required.
// If this is the final handshake message, then new Peer object
// will be created and used as a transport. If no mutually
// authenticated Peer is ready, then return nil.
-func (h *Handshake) Client(conn *net.UDPConn, data []byte) *Peer {
+func (h *Handshake) Client(data []byte) *Peer {
switch len(data) {
case 80: // ENC(H(DSAPub), R+1, El(SDHPub)) + ENC(K, R, RS + SS) + IDtag
if h.key != nil {
append(h.sClient[:], sign[:]...)...)...), h.rNonceNext(1), h.key)
// Send that to server
- conn.WriteToUDP(append(enc, idTag(h.Conf.Id, enc)...), h.addr)
+ h.conn.Write(append(enc, idTag(h.Conf.Id, enc)...))
h.LastPing = time.Now()
case 16: // ENC(K, R+2, RC) + IDtag
if h.key == nil {
}
// Switch peer
- peer := newPeer(h.addr, h.Conf, 1, keyFromSecrets(h.sServer[:], h.sClient[:]))
+ peer := newPeer(h.addr, h.conn, h.Conf, 1, keyFromSecrets(h.sServer[:], h.sClient[:]))
h.LastPing = time.Now()
return peer
default:
+++ /dev/null
-/*
-GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package govpn
-
-import (
- "net"
- "time"
-)
-
-type UDPPkt struct {
- Addr *net.UDPAddr
- Data []byte
-}
-
-// Create UDP listening goroutine.
-// This function takes already listening UDP socket and a buffer where
-// all UDP packet data will be saved, channel where information about
-// remote address and number of written bytes are stored, and a channel
-// used to tell that buffer is ready to be overwritten.
-func ConnListenUDP(conn *net.UDPConn) (chan UDPPkt, chan struct{}) {
- buf := make([]byte, MTU)
- sink := make(chan UDPPkt)
- sinkReady := make(chan struct{})
- go func(conn *net.UDPConn) {
- var n int
- var addr *net.UDPAddr
- var err error
- for {
- <-sinkReady
- conn.SetReadDeadline(time.Now().Add(time.Second))
- n, addr, err = conn.ReadFromUDP(buf)
- if err != nil {
- // This is needed for ticking the timeouts counter outside
- sink <- UDPPkt{nil, nil}
- continue
- }
- sink <- UDPPkt{addr, buf[:n]}
- }
- }(conn)
- sinkReady <- struct{}{}
- return sink, sinkReady
-}
import (
"encoding/binary"
"io"
- "net"
"time"
"golang.org/x/crypto/poly1305"
)
type Peer struct {
- Addr *net.UDPAddr
+ Addr string
Id *PeerId
+ Conn io.Writer
// Traffic behaviour
NoiseEnable bool
}
func (p *Peer) String() string {
- return p.Id.String() + ":" + p.Addr.String()
+ return p.Id.String() + ":" + p.Addr
}
// Zero peer's memory state.
return time.Second / time.Duration(rate*(1<<10)/MTU)
}
-func newPeer(addr *net.UDPAddr, conf *PeerConf, nonce int, key *[SSize]byte) *Peer {
+func newPeer(addr string, conn io.Writer, conf *PeerConf, nonce int, key *[SSize]byte) *Peer {
now := time.Now()
timeout := conf.Timeout
cprCycle := cprCycleCalculate(conf.CPR)
}
peer := Peer{
Addr: addr,
+ Conn: conn,
Timeout: timeout,
Established: now,
LastPing: now,
}
// Process incoming UDP packet.
-// udpPkt is received data, related to the peer tap interface and
// ConnListen'es synchronization channel used to tell him that he is
// free to receive new packets. Authenticated and decrypted packets
// will be written to the interface immediately (except heartbeat ones).
-func (p *Peer) UDPProcess(udpPkt []byte, tap io.Writer, ready chan struct{}) bool {
- p.size = len(udpPkt)
+func (p *Peer) PktProcess(data []byte, tap io.Writer, ready chan struct{}) bool {
+ p.size = len(data)
copy(p.buf, Emptiness)
- copy(p.tag[:], udpPkt[p.size-poly1305.TagSize:])
- copy(p.buf[S20BS:], udpPkt[NonceSize:p.size-poly1305.TagSize])
+ copy(p.tag[:], data[p.size-poly1305.TagSize:])
+ copy(p.buf[S20BS:], data[NonceSize:p.size-poly1305.TagSize])
salsa20.XORKeyStream(
p.buf[:S20BS+p.size-poly1305.TagSize],
p.buf[:S20BS+p.size-poly1305.TagSize],
- udpPkt[:NonceSize],
+ data[:NonceSize],
p.Key,
)
copy(p.keyAuth[:], p.buf[:SSize])
- if !poly1305.Verify(p.tag, udpPkt[:p.size-poly1305.TagSize], p.keyAuth) {
+ if !poly1305.Verify(p.tag, data[:p.size-poly1305.TagSize], p.keyAuth) {
ready <- struct{}{}
p.FramesUnauth++
return false
// Check from the oldest bucket, as in most cases this will result
// in constant time check.
// If Bucket0 is filled, then it becomes Bucket1.
- p.NonceCipher.Decrypt(p.buf, udpPkt[:NonceSize])
+ p.NonceCipher.Decrypt(p.buf, data[:NonceSize])
ready <- struct{}{}
p.nonceRecv, _ = binary.Uvarint(p.buf[:NonceSize])
if _, p.nonceFound = p.nonceBucket1[p.NonceRecv]; p.nonceFound {
return true
}
-type WriteToUDPer interface {
- WriteToUDP([]byte, *net.UDPAddr) (int, error)
-}
-
// Process incoming Ethernet packet.
-// ethPkt is received data, conn is our outgoing connection.
// ready channel is TAPListen's synchronization channel used to tell him
// that he is free to receive new packets. Encrypted and authenticated
// packets will be sent to remote Peer side immediately.
-func (p *Peer) EthProcess(ethPkt []byte, conn WriteToUDPer, ready chan struct{}) {
+func (p *Peer) EthProcess(data []byte, ready chan struct{}) {
p.now = time.Now()
- p.size = len(ethPkt)
+ p.size = len(data)
// If this heartbeat is necessary
if p.size == 0 && !p.LastSent.Add(p.Timeout).Before(p.now) {
return
}
copy(p.buf, Emptiness)
if p.size > 0 {
- copy(p.buf[S20BS+PktSizeSize:], ethPkt)
+ copy(p.buf[S20BS+PktSizeSize:], data)
ready <- struct{}{}
binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(p.size))
p.BytesPayloadOut += int64(p.size)
}
}
p.LastSent = p.now
- conn.WriteToUDP(append(p.frame, p.tag[:]...), p.Addr)
+ p.Conn.Write(append(p.frame, p.tag[:]...))
}
package govpn
import (
- "net"
"testing"
"time"
)
peer *Peer
plaintext []byte
ready chan struct{}
- dummy = &Dummy{}
ciphertext []byte
- addr *net.UDPAddr
peerId *PeerId
conf *PeerConf
)
+type Dummy struct{
+ dst *[]byte
+}
+
+func (d Dummy) Write(b []byte) (int, error) {
+ if d.dst != nil {
+ *d.dst = b
+ }
+ return len(b), nil
+}
+
func init() {
MTU = 1500
- addr, _ = net.ResolveUDPAddr("udp", "[::1]:1")
peerId, _ = IDDecode("ffffffffffffffffffffffffffffffff")
conf = &PeerConf{
Id: peerId,
NoiseEnable: false,
CPR: 0,
}
- peer = newPeer(addr, conf, 128, new([SSize]byte))
+ peer = newPeer("foo", Dummy{&ciphertext}, conf, 128, new([SSize]byte))
plaintext = make([]byte, 789)
ready = make(chan struct{})
go func() {
}()
}
-type Dummy struct{}
-
-func (d *Dummy) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) {
- ciphertext = b
- return len(b), nil
-}
-
-func (d *Dummy) Write(p []byte) (n int, err error) {
- return len(p), nil
-}
-
func BenchmarkEnc(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
peer.NonceOur = 128
- peer.EthProcess(plaintext, dummy, ready)
+ peer.EthProcess(plaintext, ready)
}
}
func BenchmarkDec(b *testing.B) {
- peer.EthProcess(plaintext, dummy, ready)
- peer = newPeer(addr, conf, 128, new([SSize]byte))
+ peer.EthProcess(plaintext, ready)
+ peer = newPeer("foo", Dummy{nil}, conf, 128, new([SSize]byte))
b.ResetTimer()
for i := 0; i < b.N; i++ {
peer.nonceBucket0 = make(map[uint64]struct{}, 1)
peer.nonceBucket1 = make(map[uint64]struct{}, 1)
- if !peer.UDPProcess(ciphertext, dummy, ready) {
+ if !peer.PktProcess(ciphertext, Dummy{nil}, ready) {
b.Fail()
}
}