and sent to remote server, that writes them to his interface, and vice
versa. Client and server use pre-shared authentication key (PSK).
Because of stateless UDP nature, after some timeout of inactivity peers
-forget about each other and have to retry handshake process again. As a
-rule, there are enough time-to-time traffic in ordinary Ethernet
-networks to heartbeat connection.
+forget about each other and have to retry handshake process again,
+therefore background heartbeat process will be ran.
Handshake is used to mutually authenticate peers, exchange common secret
per-session encryption key and checks UDP transport availability.
NonceSize = 8
KeySize = 32
// S20BS is Salsa20's internal blocksize in bytes
- S20BS = 64
+ S20BS = 64
+ HeartBeatSize = 12
+ HeartBeatMark = "\x00\x00\x00HEARTBEAT"
)
type TAP interface {
var udpPkt *UDPPkt
var udpPktData []byte
var ethPktSize int
+ var frame []byte
var addr string
var peer *Peer
var p *Peer
states[remote.String()] = HandshakeStart(conn, remote, key)
}
+ heartbeat := time.Tick(time.Second * time.Duration(timeout/3))
+ heartbeatMark := []byte(HeartBeatMark)
+
finished := false
for {
if finished {
break
}
select {
+ case <-heartbeat:
+ go func() { ethSink <- -1 }()
case udpPkt = <-udpSink:
timeouts++
if !serverMode && timeouts >= timeout {
}
peer.nonceRecv = nonceRecv
timeouts = 0
- if _, err := iface.Write(buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]); err != nil {
+ frame = buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]
+ if string(frame[0:HeartBeatSize]) == HeartBeatMark {
+ continue
+ }
+ if _, err := iface.Write(frame); err != nil {
log.Println("Error writing to iface: ", err)
}
if verbose {
ethSinkReady <- true
continue
}
- copy(ethPkt, ethBuf[:ethPktSize])
- ethSinkReady <- true
+ if ethPktSize > -1 {
+ copy(ethPkt, ethBuf[:ethPktSize])
+ ethSinkReady <- true
+ } else {
+ copy(ethPkt, heartbeatMark)
+ ethPktSize = HeartBeatSize
+ }
peer.nonceOur = peer.nonceOur + 2
binary.PutUvarint(nonce, peer.nonceOur)
copy(buf[:KeySize], emptyKey)