WIP: cleanup. Local peer discovery working.
This commit is contained in:
parent
8407fd5b48
commit
bbf5202d30
@ -1,79 +0,0 @@
|
|||||||
package aestests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/rand"
|
|
||||||
"log"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func must(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAES(t *testing.T) {
|
|
||||||
key := make([]byte, 32)
|
|
||||||
rand.Read(key)
|
|
||||||
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
aesgcm, err := cipher.NewGCM(block)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
log.Print(aesgcm.NonceSize())
|
|
||||||
log.Print(aesgcm.Overhead())
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSeal(b *testing.B) {
|
|
||||||
key := make([]byte, 32)
|
|
||||||
rand.Read(key)
|
|
||||||
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
cryptor, err := cipher.NewGCM(block)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
nonce := make([]byte, 12)
|
|
||||||
rand.Read(nonce)
|
|
||||||
|
|
||||||
data := make([]byte, 1400)
|
|
||||||
rand.Read(data)
|
|
||||||
|
|
||||||
out := make([]byte, 1500)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
out = cryptor.Seal(out[:0], nonce, data, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkOpen(b *testing.B) {
|
|
||||||
key := make([]byte, 32)
|
|
||||||
rand.Read(key)
|
|
||||||
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
cryptor, err := cipher.NewGCM(block)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
nonce := make([]byte, 12)
|
|
||||||
rand.Read(nonce)
|
|
||||||
|
|
||||||
data := make([]byte, 1400)
|
|
||||||
rand.Read(data)
|
|
||||||
|
|
||||||
sealed := make([]byte, 1500)
|
|
||||||
sealed = cryptor.Seal(sealed[:0], nonce, data, nil)
|
|
||||||
|
|
||||||
dec := make([]byte, 1500)
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
dec, err = cryptor.Open(dec[:0], nonce, sealed, nil)
|
|
||||||
}
|
|
||||||
}
|
|
103
hub/api/api.go
103
hub/api/api.go
@ -24,7 +24,6 @@ var migrations embed.FS
|
|||||||
type API struct {
|
type API struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
peerIntents map[string]PeerCreateArgs
|
|
||||||
initIntents map[string]byte // Map from intent key to peer IP
|
initIntents map[string]byte // Map from intent key to peer IP
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +39,6 @@ func New(dbPath string) (*API, error) {
|
|||||||
|
|
||||||
a := &API{
|
a := &API{
|
||||||
db: sqlDB,
|
db: sqlDB,
|
||||||
peerIntents: map[string]PeerCreateArgs{},
|
|
||||||
initIntents: map[string]byte{},
|
initIntents: map[string]byte{},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,34 +151,6 @@ func (a *API) Peer_CreateNew(p *Peer) error {
|
|||||||
return db.Peer_Insert(a.db, p)
|
return db.Peer_Insert(a.db, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
type PeerCreateArgs struct {
|
|
||||||
Name string
|
|
||||||
PublicIP []byte
|
|
||||||
Port uint16
|
|
||||||
Relay bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
// Create the intention to add a peer. The returned code is used to complete
|
|
||||||
// the peer creation. The code is valid for 5 minutes.
|
|
||||||
func (a *API) Peer_CreateIntent(args PeerCreateArgs) string {
|
|
||||||
a.lock.Lock()
|
|
||||||
defer a.lock.Unlock()
|
|
||||||
|
|
||||||
code := idgen.NewToken()
|
|
||||||
a.peerIntents[code] = args
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
time.Sleep(5 * time.Minute)
|
|
||||||
a.lock.Lock()
|
|
||||||
defer a.lock.Unlock()
|
|
||||||
delete(a.peerIntents, code)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the intention to initialize a peer. The returned code is used to
|
// Create the intention to initialize a peer. The returned code is used to
|
||||||
// complete the peer initialization. The code is valid for 5 minutes.
|
// complete the peer initialization. The code is valid for 5 minutes.
|
||||||
func (a *API) Peer_CreateInitIntent(peerIP byte) string {
|
func (a *API) Peer_CreateInitIntent(peerIP byte) string {
|
||||||
@ -252,79 +222,6 @@ func (a *API) Peer_Init(initCode string) (*m.PeerConfig, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
func (a *API) Peer_Create(creationCode string) (*m.PeerConfig, error) {
|
|
||||||
a.lock.Lock()
|
|
||||||
defer a.lock.Unlock()
|
|
||||||
|
|
||||||
args, ok := a.peerIntents[creationCode]
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrNotAuthorized
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(a.peerIntents, creationCode)
|
|
||||||
|
|
||||||
encPubKey, encPrivKey, err := box.GenerateKey(rand.Reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
signPubKey, signPrivKey, err := sign.GenerateKey(rand.Reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get peer IP.
|
|
||||||
peerIP := byte(0)
|
|
||||||
|
|
||||||
for i := byte(1); i < 255; i++ {
|
|
||||||
exists, err := db.Peer_Exists(a.db, i)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
peerIP = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if peerIP == 0 {
|
|
||||||
return nil, ErrNoIPAvailable
|
|
||||||
}
|
|
||||||
|
|
||||||
peer := &Peer{
|
|
||||||
PeerIP: peerIP,
|
|
||||||
Version: idgen.NextID(0),
|
|
||||||
APIKey: idgen.NewToken(),
|
|
||||||
Name: args.Name,
|
|
||||||
PublicIP: args.PublicIP,
|
|
||||||
Port: args.Port,
|
|
||||||
Relay: args.Relay,
|
|
||||||
PubKey: encPubKey[:],
|
|
||||||
PubSignKey: signPubKey[:],
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := db.Peer_Insert(a.db, peer); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
conf := a.Config_Get()
|
|
||||||
|
|
||||||
return &m.PeerConfig{
|
|
||||||
PeerIP: peer.PeerIP,
|
|
||||||
HubAddress: conf.HubAddress,
|
|
||||||
APIKey: peer.APIKey,
|
|
||||||
Network: conf.VPNNetwork,
|
|
||||||
PublicIP: peer.PublicIP,
|
|
||||||
Port: peer.Port,
|
|
||||||
Relay: peer.Relay,
|
|
||||||
PubKey: encPubKey[:],
|
|
||||||
PrivKey: encPrivKey[:],
|
|
||||||
PubSignKey: signPubKey[:],
|
|
||||||
PrivSignKey: signPrivKey[:],
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *API) Peer_Update(p *Peer) error {
|
func (a *API) Peer_Update(p *Peer) error {
|
||||||
a.lock.Lock()
|
a.lock.Lock()
|
||||||
defer a.lock.Unlock()
|
defer a.lock.Unlock()
|
||||||
|
@ -1 +0,0 @@
|
|||||||
package api
|
|
@ -208,7 +208,7 @@ func (a *App) _adminPeerInit(s *api.Session, w http.ResponseWriter, r *http.Requ
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
code := a.api.Peer_CreateInitIntent(peerIP)
|
code := a.api.Peer_CreateInitIntent(peerIP)
|
||||||
log.Printf("Got code: %v / %v", peerIP, cod)
|
log.Printf("Got code: %v / %v", peerIP, code)
|
||||||
|
|
||||||
return a.render("/admin-peer-init.html", w, struct {
|
return a.render("/admin-peer-init.html", w, struct {
|
||||||
Session *api.Session
|
Session *api.Session
|
||||||
@ -217,20 +217,6 @@ func (a *App) _adminPeerInit(s *api.Session, w http.ResponseWriter, r *http.Requ
|
|||||||
}{s, a.api.Config_Get().HubAddress, code})
|
}{s, a.api.Config_Get().HubAddress, code})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
func (a *App) _adminPeerIntentCreated(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
|
||||||
code := r.FormValue("Code")
|
|
||||||
if code == "" {
|
|
||||||
return errors.New("missing Code")
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.render("/admin-peer-intent.html", w, struct {
|
|
||||||
Session *api.Session
|
|
||||||
HubAddress string
|
|
||||||
Code string
|
|
||||||
}{s, a.api.Config_Get().HubAddress, code})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) _adminPeerView(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
func (a *App) _adminPeerView(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
||||||
var peerIP byte
|
var peerIP byte
|
||||||
err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error()
|
err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error()
|
||||||
@ -345,17 +331,6 @@ func (a *App) _peerInit(w http.ResponseWriter, r *http.Request) error {
|
|||||||
return a.sendJSON(w, conf)
|
return a.sendJSON(w, conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
func (a *App) _peerCreate(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
code := r.FormValue("Code")
|
|
||||||
conf, err := a.api.Peer_Create(code)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.sendJSON(w, conf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error {
|
func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error {
|
||||||
_, apiKey, ok := r.BasicAuth()
|
_, apiKey, ok := r.BasicAuth()
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -385,13 +360,14 @@ func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error {
|
|||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
if len(p.PubKey) != 0 {
|
if len(p.PubKey) != 0 {
|
||||||
state.Peers[p.PeerIP] = &m.Peer{
|
state.Peers[p.PeerIP] = &m.Peer{
|
||||||
PeerIP: p.PeerIP,
|
PeerIP: p.PeerIP,
|
||||||
Version: p.Version,
|
Version: p.Version,
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
PublicIP: p.PublicIP,
|
PublicIP: p.PublicIP,
|
||||||
Port: p.Port,
|
Port: p.Port,
|
||||||
Relay: p.Relay,
|
Relay: p.Relay,
|
||||||
PubKey: p.PubKey,
|
PubKey: p.PubKey,
|
||||||
|
PubSignKey: p.PubSignKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,15 +20,12 @@ func (a *App) registerRoutes() {
|
|||||||
a.handleSignedIn("GET /admin/peer/create/", a._adminPeerCreate)
|
a.handleSignedIn("GET /admin/peer/create/", a._adminPeerCreate)
|
||||||
a.handleSignedIn("POST /admin/peer/create/", a._adminPeerCreateSubmit)
|
a.handleSignedIn("POST /admin/peer/create/", a._adminPeerCreateSubmit)
|
||||||
a.handleSignedIn("GET /admin/peer/init/", a._adminPeerInit)
|
a.handleSignedIn("GET /admin/peer/init/", a._adminPeerInit)
|
||||||
// TODO: Remove
|
|
||||||
a.handleSignedIn("GET /admin/peer/intent-created/", a._adminPeerIntentCreated)
|
|
||||||
a.handleSignedIn("GET /admin/peer/view/", a._adminPeerView)
|
a.handleSignedIn("GET /admin/peer/view/", a._adminPeerView)
|
||||||
a.handleSignedIn("GET /admin/peer/edit/", a._adminPeerEdit)
|
a.handleSignedIn("GET /admin/peer/edit/", a._adminPeerEdit)
|
||||||
a.handleSignedIn("POST /admin/peer/edit/", a._adminPeerEditSubmit)
|
a.handleSignedIn("POST /admin/peer/edit/", a._adminPeerEditSubmit)
|
||||||
a.handleSignedIn("GET /admin/peer/delete/", a._adminPeerDelete)
|
a.handleSignedIn("GET /admin/peer/delete/", a._adminPeerDelete)
|
||||||
a.handleSignedIn("POST /admin/peer/delete/", a._adminPeerDeleteSubmit)
|
a.handleSignedIn("POST /admin/peer/delete/", a._adminPeerDeleteSubmit)
|
||||||
|
|
||||||
a.handlePeer("GET /peer/create/", a._peerCreate) // TODO: Remove
|
|
||||||
a.handlePeer("GET /peer/init/", a._peerInit)
|
a.handlePeer("GET /peer/init/", a._peerInit)
|
||||||
a.handlePeer("GET /peer/fetch-state/", a._peerFetchState)
|
a.handlePeer("GET /peer/fetch-state/", a._peerFetchState)
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
package hub
|
|
@ -13,21 +13,17 @@ func addrDiscoveryServer() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
pkt := <-discoveryPackets
|
msg := <-discoveryMessages
|
||||||
|
p := msg.Packet
|
||||||
|
|
||||||
p, ok := pkt.Payload.(addrDiscoveryPacket)
|
route := routingTable[msg.SrcIP].Load()
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
route := routingTable[pkt.SrcIP].Load()
|
|
||||||
if route == nil || !route.RemoteAddr.IsValid() {
|
if route == nil || !route.RemoteAddr.IsValid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendControlPacket(addrDiscoveryPacket{
|
_sendControlPacket(addrDiscoveryPacket{
|
||||||
TraceID: p.TraceID,
|
TraceID: p.TraceID,
|
||||||
ToAddr: pkt.SrcAddr,
|
ToAddr: msg.SrcAddr,
|
||||||
}, *route, buf1, buf2)
|
}, *route, buf1, buf2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,9 +42,9 @@ func addrDiscoveryClient() {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case pkt := <-discoveryPackets:
|
case msg := <-discoveryMessages:
|
||||||
p, ok := pkt.Payload.(addrDiscoveryPacket)
|
p := msg.Packet
|
||||||
if !ok || p.TraceID != addrPacket.TraceID || !p.ToAddr.IsValid() || p.ToAddr == lAddr {
|
if p.TraceID != addrPacket.TraceID || !p.ToAddr.IsValid() || p.ToAddr == lAddr {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build
|
|
||||||
sudo setcap cap_net_admin+iep ./client
|
|
||||||
./client 144.76.78.93
|
|
@ -1,15 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"vppn/node"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) != 2 {
|
|
||||||
log.Fatalf("Usage: %s <addr:port>", os.Args[0])
|
|
||||||
}
|
|
||||||
n := node.NewTmpNodeClient(os.Args[1])
|
|
||||||
n.RunClient()
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build
|
|
||||||
ssh kevin "killall server"
|
|
||||||
scp server kevin:/home/jdl/tmp/
|
|
||||||
ssh root@kevin "sudo setcap cap_net_admin+iep /home/jdl/tmp/server"
|
|
||||||
ssh kevin "/home/jdl/tmp/server"
|
|
@ -1,8 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "vppn/node"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
n := node.NewTmpNodeServer()
|
|
||||||
n.RunServer()
|
|
||||||
}
|
|
@ -1,10 +1,10 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
"vppn/m"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -13,6 +13,12 @@ const (
|
|||||||
if_queue_len = 2048
|
if_queue_len = 2048
|
||||||
controlCipherOverhead = 16
|
controlCipherOverhead = 16
|
||||||
dataCipherOverhead = 16
|
dataCipherOverhead = 16
|
||||||
|
signOverhead = 64
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
multicastIP = netip.AddrFrom4([4]byte{224, 0, 0, 157})
|
||||||
|
multicastAddr = net.UDPAddrFromAddrPort(netip.AddrPortFrom(multicastIP, 4560))
|
||||||
)
|
)
|
||||||
|
|
||||||
type peerRoute struct {
|
type peerRoute struct {
|
||||||
@ -56,18 +62,9 @@ var (
|
|||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Channels for incoming control packets.
|
messages [256]chan any = func() (out [256]chan any) {
|
||||||
controlPackets [256]chan controlPacket = func() (out [256]chan controlPacket) {
|
|
||||||
for i := range out {
|
for i := range out {
|
||||||
out[i] = make(chan controlPacket, 256)
|
out[i] = make(chan any, 256)
|
||||||
}
|
|
||||||
return
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Channels for incoming peer updates from the hub.
|
|
||||||
peerUpdates [256]chan *m.Peer = func() (out [256]chan *m.Peer) {
|
|
||||||
for i := range out {
|
|
||||||
out[i] = make(chan *m.Peer)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
@ -81,8 +78,10 @@ var (
|
|||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Managed by the addrDiscovery* functions.
|
||||||
|
discoveryMessages = make(chan controlMsg[addrDiscoveryPacket], 256)
|
||||||
|
|
||||||
// Managed by the relayManager.
|
// Managed by the relayManager.
|
||||||
discoveryPackets = make(chan controlPacket, 256)
|
localAddr = &atomic.Pointer[netip.AddrPort]{}
|
||||||
localAddr = &atomic.Pointer[netip.AddrPort]{}
|
relayIP = &atomic.Pointer[byte]{}
|
||||||
relayIP = &atomic.Pointer[byte]{}
|
|
||||||
)
|
)
|
||||||
|
@ -86,7 +86,7 @@ func (hp *hubPoller) applyNetworkState(state m.NetworkState) {
|
|||||||
for i, peer := range state.Peers {
|
for i, peer := range state.Peers {
|
||||||
if i != int(localIP) {
|
if i != int(localIP) {
|
||||||
if peer != nil && peer.Version != hp.versions[i] {
|
if peer != nil && peer.Version != hp.versions[i] {
|
||||||
peerUpdates[i] <- state.Peers[i]
|
messages[i] <- peerUpdateMsg{Peer: state.Peers[i]}
|
||||||
hp.versions[i] = peer.Version
|
hp.versions[i] = peer.Version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func localBroadcaster() {
|
|
||||||
var (
|
|
||||||
buf1 = make([]byte, bufferSize)
|
|
||||||
buf2 = make([]byte, bufferSize)
|
|
||||||
)
|
|
||||||
time.Sleep(4 * time.Second)
|
|
||||||
doBroadcast(buf1, buf2)
|
|
||||||
for range time.Tick(32 * time.Second) {
|
|
||||||
doBroadcast(buf1, buf2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func doBroadcast(buf1, buf2 []byte) {
|
|
||||||
ifaces, err := net.Interfaces()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to list interfaces: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, iface := range ifaces {
|
|
||||||
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagRunning == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if iface.Flags&net.FlagPointToPoint != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if iface.Flags&net.FlagBroadcast == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
addrs, err := iface.Addrs()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to get interface addresses: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range addrs {
|
|
||||||
ipNet, ok := addr.(*net.IPNet)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ip4 := ipNet.IP.To4()
|
|
||||||
if ip4 == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, ok := lastAddr(ipNet)
|
|
||||||
if !ok {
|
|
||||||
log.Printf("Failed to find broadcast address: %v", ipNet)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Broadcasting on address: %v", ip)
|
|
||||||
//addr := netip.AddrPortFrom(ip, 456)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// works when the n is a prefix, otherwise...
|
|
||||||
func lastAddr(n *net.IPNet) (netip.Addr, bool) {
|
|
||||||
ip := make(net.IP, len(n.IP.To4()))
|
|
||||||
binary.BigEndian.PutUint32(ip, binary.BigEndian.Uint32(n.IP.To4())|
|
|
||||||
^binary.BigEndian.Uint32(net.IP(n.Mask).To4()))
|
|
||||||
return netip.AddrFromSlice(ip)
|
|
||||||
}
|
|
@ -3,18 +3,11 @@ package node
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/nacl/sign"
|
"golang.org/x/crypto/nacl/sign"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
signOverhead = 64
|
|
||||||
multicastIP = netip.AddrFrom4([4]byte{224, 0, 0, 157})
|
|
||||||
multicastAddr = net.UDPAddrFromAddrPort(netip.AddrPortFrom(multicastIP, 4560))
|
|
||||||
)
|
|
||||||
|
|
||||||
func localDiscovery() {
|
func localDiscovery() {
|
||||||
conn, err := net.ListenMulticastUDP("udp", nil, multicastAddr)
|
conn, err := net.ListenMulticastUDP("udp", nil, multicastAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -32,8 +25,9 @@ func sendLocalDiscovery(conn *net.UDPConn) {
|
|||||||
buf2 = make([]byte, bufferSize)
|
buf2 = make([]byte, bufferSize)
|
||||||
)
|
)
|
||||||
|
|
||||||
for range time.Tick(16 * time.Second) {
|
for range time.Tick(32 * time.Second) {
|
||||||
signed := buildLocalDiscoveryPacket(buf1, buf2)
|
signed := buildLocalDiscoveryPacket(buf1, buf2)
|
||||||
|
log.Printf("Sending discovery packet...")
|
||||||
if _, err := conn.WriteToUDP(signed, multicastAddr); err != nil {
|
if _, err := conn.WriteToUDP(signed, multicastAddr); err != nil {
|
||||||
log.Printf("Failed to write multicast UDP packet: %v", err)
|
log.Printf("Failed to write multicast UDP packet: %v", err)
|
||||||
}
|
}
|
||||||
@ -51,21 +45,24 @@ func recvLocalDiscovery(conn *net.UDPConn) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to read from UDP port (multicast): %v", err)
|
log.Fatalf("Failed to read from UDP port (multicast): %v", err)
|
||||||
}
|
}
|
||||||
|
log.Printf("Got local discovery packet...")
|
||||||
|
|
||||||
raw = raw[:n]
|
raw = raw[:n]
|
||||||
h, ok := openLocalDiscoveryPacket(raw, buf)
|
h, ok := openLocalDiscoveryPacket(raw, buf)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
log.Printf("Failed to open discovery packet?")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt := controlPacket{
|
msg := controlMsg[localDiscoveryPacket]{
|
||||||
SrcIP: h.SourceIP,
|
SrcIP: h.SourceIP,
|
||||||
SrcAddr: remoteAddr,
|
SrcAddr: remoteAddr,
|
||||||
Payload: localDiscoveryPacket{},
|
Packet: localDiscoveryPacket{},
|
||||||
}
|
}
|
||||||
|
log.Printf("Got local discovery packet from %d/%v...", h.SourceIP, remoteAddr)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case controlPackets[h.SourceIP] <- pkt:
|
case messages[h.SourceIP] <- msg:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,6 +89,7 @@ func openLocalDiscoveryPacket(raw, buf []byte) (h header, ok bool) {
|
|||||||
h.Parse(raw[signOverhead:])
|
h.Parse(raw[signOverhead:])
|
||||||
route := routingTable[h.SourceIP].Load()
|
route := routingTable[h.SourceIP].Load()
|
||||||
if route == nil || route.PubSignKey == nil {
|
if route == nil || route.PubSignKey == nil {
|
||||||
|
log.Printf("Missing signing key")
|
||||||
ok = false
|
ok = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
62
node/main.go
62
node/main.go
@ -11,6 +11,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
"vppn/m"
|
"vppn/m"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,13 +27,11 @@ func Main() {
|
|||||||
var (
|
var (
|
||||||
initURL string
|
initURL string
|
||||||
listenIP string
|
listenIP string
|
||||||
port int
|
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.StringVar(&netName, "name", "", "[REQUIRED] The network name.")
|
flag.StringVar(&netName, "name", "", "[REQUIRED] The network name.")
|
||||||
flag.StringVar(&initURL, "init-url", "", "Initializes peer from the hub URL.")
|
flag.StringVar(&initURL, "init-url", "", "Initializes peer from the hub URL.")
|
||||||
flag.StringVar(&listenIP, "listen-ip", "", "IP address to listen on.")
|
flag.StringVar(&listenIP, "listen-ip", "", "IP address to listen on.")
|
||||||
flag.IntVar(&port, "port", 0, "Port to listen on.")
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if netName == "" {
|
if netName == "" {
|
||||||
@ -45,7 +44,7 @@ func Main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
main(listenIP, uint16(port))
|
main(listenIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mainInit(initURL string) {
|
func mainInit(initURL string) {
|
||||||
@ -74,20 +73,18 @@ func mainInit(initURL string) {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
func main(listenIP string, port uint16) {
|
func main(listenIP string) {
|
||||||
config, err := loadPeerConfig(netName)
|
config, err := loadPeerConfig(netName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to load configuration: %v", err)
|
log.Fatalf("Failed to load configuration: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
port = determinePort(config.Port, port)
|
|
||||||
|
|
||||||
iface, err := openInterface(config.Network, config.PeerIP, netName)
|
iface, err := openInterface(config.Network, config.PeerIP, netName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to open interface: %v", err)
|
log.Fatalf("Failed to open interface: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", listenIP, port))
|
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", listenIP, config.Port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to resolve UDP address: %v", err)
|
log.Fatalf("Failed to resolve UDP address: %v", err)
|
||||||
}
|
}
|
||||||
@ -129,6 +126,17 @@ func main(listenIP string, port uint16) {
|
|||||||
go localDiscovery()
|
go localDiscovery()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for range time.Tick(pingInterval) {
|
||||||
|
for i := range messages {
|
||||||
|
select {
|
||||||
|
case messages[i] <- pingTimerMsg{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
go newHubPoller(config).Run()
|
go newHubPoller(config).Run()
|
||||||
go readFromConn(conn)
|
go readFromConn(conn)
|
||||||
readFromIFace(iface)
|
readFromIFace(iface)
|
||||||
@ -136,18 +144,6 @@ func main(listenIP string, port uint16) {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
func determinePort(confPort, portFromCommandLine uint16) uint16 {
|
|
||||||
if portFromCommandLine != 0 {
|
|
||||||
return portFromCommandLine
|
|
||||||
}
|
|
||||||
if confPort != 0 {
|
|
||||||
return confPort
|
|
||||||
}
|
|
||||||
return 456
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func readFromConn(conn *net.UDPConn) {
|
func readFromConn(conn *net.UDPConn) {
|
||||||
|
|
||||||
defer panicHandler()
|
defer panicHandler()
|
||||||
@ -218,31 +214,21 @@ func handleControlPacket(addr netip.AddrPort, h header, data, decBuf []byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt := controlPacket{
|
msg, err := parseControlMsg(h.SourceIP, addr, out)
|
||||||
SrcIP: h.SourceIP,
|
if err != nil {
|
||||||
SrcAddr: addr,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := pkt.ParsePayload(out); err != nil {
|
|
||||||
log.Printf("Failed to parse control packet: %v", err)
|
log.Printf("Failed to parse control packet: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch pkt.Payload.(type) {
|
if dm, ok := msg.(controlMsg[addrDiscoveryPacket]); ok {
|
||||||
|
discoveryMessages <- dm
|
||||||
case addrDiscoveryPacket:
|
return
|
||||||
select {
|
}
|
||||||
case discoveryPackets <- pkt:
|
|
||||||
default:
|
|
||||||
log.Printf("Dropping discovery packet.")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
select {
|
||||||
|
case messages[h.SourceIP] <- msg:
|
||||||
default:
|
default:
|
||||||
select {
|
log.Printf("Dropping control packet.")
|
||||||
case controlPackets[h.SourceIP] <- pkt:
|
|
||||||
default:
|
|
||||||
log.Printf("Dropping control packet.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1 +1,66 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
"vppn/m"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type controlMsg[T any] struct {
|
||||||
|
SrcIP byte
|
||||||
|
SrcAddr netip.AddrPort
|
||||||
|
Packet T
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseControlMsg(srcIP byte, srcAddr netip.AddrPort, buf []byte) (any, error) {
|
||||||
|
switch buf[0] {
|
||||||
|
|
||||||
|
case packetTypeSyn:
|
||||||
|
packet, err := parseSynPacket(buf)
|
||||||
|
return controlMsg[synPacket]{
|
||||||
|
SrcIP: srcIP,
|
||||||
|
SrcAddr: srcAddr,
|
||||||
|
Packet: packet,
|
||||||
|
}, err
|
||||||
|
|
||||||
|
case packetTypeSynAck:
|
||||||
|
packet, err := parseSynAckPacket(buf)
|
||||||
|
return controlMsg[synAckPacket]{
|
||||||
|
SrcIP: srcIP,
|
||||||
|
SrcAddr: srcAddr,
|
||||||
|
Packet: packet,
|
||||||
|
}, err
|
||||||
|
|
||||||
|
case packetTypeProbe:
|
||||||
|
packet, err := parseProbePacket(buf)
|
||||||
|
return controlMsg[probePacket]{
|
||||||
|
SrcIP: srcIP,
|
||||||
|
SrcAddr: srcAddr,
|
||||||
|
Packet: packet,
|
||||||
|
}, err
|
||||||
|
|
||||||
|
case packetTypeAddrDiscovery:
|
||||||
|
packet, err := parseAddrDiscoveryPacket(buf)
|
||||||
|
return controlMsg[addrDiscoveryPacket]{
|
||||||
|
SrcIP: srcIP,
|
||||||
|
SrcAddr: srcAddr,
|
||||||
|
Packet: packet,
|
||||||
|
}, err
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errUnknownPacketType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type peerUpdateMsg struct {
|
||||||
|
Peer *m.Peer
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type pingTimerMsg struct{}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -20,30 +20,6 @@ const (
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
type controlPacket struct {
|
|
||||||
SrcIP byte
|
|
||||||
SrcAddr netip.AddrPort
|
|
||||||
Payload any
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *controlPacket) ParsePayload(buf []byte) (err error) {
|
|
||||||
switch buf[0] {
|
|
||||||
case packetTypeSyn:
|
|
||||||
p.Payload, err = parseSynPacket(buf)
|
|
||||||
case packetTypeSynAck:
|
|
||||||
p.Payload, err = parseSynAckPacket(buf)
|
|
||||||
case packetTypeProbe:
|
|
||||||
p.Payload, err = parseProbePacket(buf)
|
|
||||||
case packetTypeAddrDiscovery:
|
|
||||||
p.Payload, err = parseAddrDiscoveryPacket(buf)
|
|
||||||
default:
|
|
||||||
return errUnknownPacketType
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type synPacket struct {
|
type synPacket struct {
|
||||||
TraceID uint64 // TraceID to match response w/ request.
|
TraceID uint64 // TraceID to match response w/ request.
|
||||||
SharedKey [32]byte // Our shared key.
|
SharedKey [32]byte // Our shared key.
|
||||||
|
@ -29,8 +29,7 @@ type peerSupervisor struct {
|
|||||||
remotePub bool
|
remotePub bool
|
||||||
|
|
||||||
// Incoming events.
|
// Incoming events.
|
||||||
peerUpdates chan *m.Peer
|
messages chan any
|
||||||
controlPackets chan controlPacket
|
|
||||||
|
|
||||||
// Buffers for sending control packets.
|
// Buffers for sending control packets.
|
||||||
buf1 []byte
|
buf1 []byte
|
||||||
@ -39,12 +38,11 @@ type peerSupervisor struct {
|
|||||||
|
|
||||||
func newPeerSupervisor(i int) *peerSupervisor {
|
func newPeerSupervisor(i int) *peerSupervisor {
|
||||||
return &peerSupervisor{
|
return &peerSupervisor{
|
||||||
published: routingTable[i],
|
published: routingTable[i],
|
||||||
remoteIP: byte(i),
|
remoteIP: byte(i),
|
||||||
peerUpdates: peerUpdates[i],
|
messages: messages[i],
|
||||||
controlPackets: controlPackets[i],
|
buf1: make([]byte, bufferSize),
|
||||||
buf1: make([]byte, bufferSize),
|
buf2: make([]byte, bufferSize),
|
||||||
buf2: make([]byte, bufferSize),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +93,12 @@ func (s *peerSupervisor) publish() {
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
func (s *peerSupervisor) noPeer() stateFunc {
|
func (s *peerSupervisor) noPeer() stateFunc {
|
||||||
return s.peerUpdate(<-s.peerUpdates)
|
for {
|
||||||
|
rawMsg := <-s.messages
|
||||||
|
if msg, ok := rawMsg.(peerUpdateMsg); ok {
|
||||||
|
return s.peerUpdate(msg.Peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -149,75 +152,73 @@ func (s *peerSupervisor) server() stateFunc {
|
|||||||
logf("DOWN")
|
logf("DOWN")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
syn synPacket
|
syn synPacket
|
||||||
timeoutTimer = time.NewTimer(timeoutInterval)
|
lastSeen = time.Now()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Timer will be restarted once we have established a connection.
|
|
||||||
timeoutTimer.Stop()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
rawMsg := <-s.messages
|
||||||
case peer := <-s.peerUpdates:
|
switch msg := rawMsg.(type) {
|
||||||
return s.peerUpdate(peer)
|
|
||||||
|
|
||||||
case pkt := <-s.controlPackets:
|
case peerUpdateMsg:
|
||||||
switch p := pkt.Payload.(type) {
|
return s.peerUpdate(msg.Peer)
|
||||||
|
|
||||||
case synPacket:
|
case controlMsg[synPacket]:
|
||||||
timeoutTimer.Reset(timeoutInterval)
|
p := msg.Packet
|
||||||
|
lastSeen = time.Now()
|
||||||
|
|
||||||
// Before we can respond to this packet, we need to make sure the
|
// Before we can respond to this packet, we need to make sure the
|
||||||
// route is setup properly.
|
// route is setup properly.
|
||||||
//
|
//
|
||||||
// The client will update the syn's TraceID whenever there's a change.
|
// The client will update the syn's TraceID whenever there's a change.
|
||||||
// The server will follow the client's request.
|
// The server will follow the client's request.
|
||||||
if p.TraceID != syn.TraceID || !s.staged.Up {
|
if p.TraceID != syn.TraceID || !s.staged.Up {
|
||||||
if p.Direct {
|
if p.Direct {
|
||||||
logf("UP - Direct")
|
logf("UP - Direct")
|
||||||
} else {
|
|
||||||
logf("UP - Relayed")
|
|
||||||
}
|
|
||||||
|
|
||||||
syn = p
|
|
||||||
s.staged.Up = true
|
|
||||||
s.staged.Direct = syn.Direct
|
|
||||||
s.staged.DataCipher = newDataCipherFromKey(syn.SharedKey)
|
|
||||||
s.staged.RemoteAddr = pkt.SrcAddr
|
|
||||||
|
|
||||||
s.publish()
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should always respond.
|
|
||||||
ack := synAckPacket{
|
|
||||||
TraceID: syn.TraceID,
|
|
||||||
FromAddr: getLocalAddr(),
|
|
||||||
}
|
|
||||||
s.sendControlPacket(ack)
|
|
||||||
|
|
||||||
if s.staged.Direct {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !syn.FromAddr.IsValid() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
probe := probePacket{TraceID: newTraceID()}
|
|
||||||
s.sendControlPacketTo(probe, syn.FromAddr)
|
|
||||||
|
|
||||||
case probePacket:
|
|
||||||
if pkt.SrcAddr.IsValid() {
|
|
||||||
s.sendControlPacketTo(probePacket{TraceID: p.TraceID}, pkt.SrcAddr)
|
|
||||||
} else {
|
} else {
|
||||||
logf("Invalid probe address")
|
logf("UP - Relayed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syn = p
|
||||||
|
s.staged.Up = true
|
||||||
|
s.staged.Direct = syn.Direct
|
||||||
|
s.staged.DataCipher = newDataCipherFromKey(syn.SharedKey)
|
||||||
|
s.staged.RemoteAddr = msg.SrcAddr
|
||||||
|
|
||||||
|
s.publish()
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-timeoutTimer.C:
|
// We should always respond.
|
||||||
logf("Connection timeout")
|
ack := synAckPacket{
|
||||||
s.staged.Up = false
|
TraceID: syn.TraceID,
|
||||||
s.publish()
|
FromAddr: getLocalAddr(),
|
||||||
|
}
|
||||||
|
s.sendControlPacket(ack)
|
||||||
|
|
||||||
|
if s.staged.Direct {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !syn.FromAddr.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
probe := probePacket{TraceID: newTraceID()}
|
||||||
|
s.sendControlPacketTo(probe, syn.FromAddr)
|
||||||
|
|
||||||
|
case controlMsg[probePacket]:
|
||||||
|
if !msg.SrcAddr.IsValid() {
|
||||||
|
logf("Invalid probe address")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.sendControlPacketTo(probePacket{TraceID: msg.Packet.TraceID}, msg.SrcAddr)
|
||||||
|
|
||||||
|
case pingTimerMsg:
|
||||||
|
if time.Since(lastSeen) > timeoutInterval {
|
||||||
|
logf("Connection timeout")
|
||||||
|
s.staged.Up = false
|
||||||
|
s.publish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,91 +238,106 @@ func (s *peerSupervisor) client() stateFunc {
|
|||||||
FromAddr: getLocalAddr(),
|
FromAddr: getLocalAddr(),
|
||||||
}
|
}
|
||||||
|
|
||||||
ack synAckPacket
|
lastSeen = time.Now()
|
||||||
|
ack synAckPacket
|
||||||
|
|
||||||
probe probePacket
|
probe probePacket
|
||||||
probeAddr netip.AddrPort
|
probeAddr netip.AddrPort
|
||||||
|
|
||||||
remoteAddr netip.AddrPort
|
localProbe probePacket
|
||||||
|
localProbeAddr netip.AddrPort
|
||||||
|
|
||||||
timeoutTimer = time.NewTimer(timeoutInterval)
|
lastLocalAddr netip.AddrPort
|
||||||
pingTimer = time.NewTimer(pingInterval)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
defer timeoutTimer.Stop()
|
|
||||||
defer pingTimer.Stop()
|
|
||||||
|
|
||||||
s.sendControlPacket(syn)
|
s.sendControlPacket(syn)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
rawMsg := <-s.messages
|
||||||
|
switch msg := rawMsg.(type) {
|
||||||
|
|
||||||
case peer := <-s.peerUpdates:
|
case peerUpdateMsg:
|
||||||
return s.peerUpdate(peer)
|
return s.peerUpdate(msg.Peer)
|
||||||
|
|
||||||
case pkt := <-s.controlPackets:
|
case controlMsg[synAckPacket]:
|
||||||
switch p := pkt.Payload.(type) {
|
p := msg.Packet
|
||||||
|
|
||||||
case synAckPacket:
|
if p.TraceID != syn.TraceID {
|
||||||
if p.TraceID != syn.TraceID {
|
continue // Hmm...
|
||||||
continue // Hmm...
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ack = p
|
lastSeen = time.Now()
|
||||||
timeoutTimer.Reset(timeoutInterval)
|
ack = msg.Packet
|
||||||
|
|
||||||
if !s.staged.Up {
|
if !s.staged.Up {
|
||||||
if s.staged.Direct {
|
|
||||||
logf("UP - Direct")
|
|
||||||
} else {
|
|
||||||
logf("UP - Relayed")
|
|
||||||
}
|
|
||||||
|
|
||||||
s.staged.Up = true
|
|
||||||
s.publish()
|
|
||||||
}
|
|
||||||
|
|
||||||
case probePacket:
|
|
||||||
if s.staged.Direct {
|
if s.staged.Direct {
|
||||||
continue
|
logf("UP - Direct")
|
||||||
|
} else {
|
||||||
|
logf("UP - Relayed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.TraceID != probe.TraceID {
|
s.staged.Up = true
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upgrade connection.
|
|
||||||
|
|
||||||
logf("UP - Direct")
|
|
||||||
s.staged.Direct = true
|
|
||||||
s.staged.RemoteAddr = probeAddr
|
|
||||||
s.publish()
|
s.publish()
|
||||||
|
|
||||||
syn.TraceID = newTraceID()
|
|
||||||
syn.Direct = true
|
|
||||||
syn.FromAddr = getLocalAddr()
|
|
||||||
s.sendControlPacket(syn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-pingTimer.C:
|
case controlMsg[probePacket]:
|
||||||
// Send syn.
|
|
||||||
|
|
||||||
syn.FromAddr = getLocalAddr()
|
|
||||||
if syn.FromAddr != remoteAddr {
|
|
||||||
syn.TraceID = newTraceID()
|
|
||||||
remoteAddr = syn.FromAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
s.sendControlPacket(syn)
|
|
||||||
|
|
||||||
pingTimer.Reset(pingInterval)
|
|
||||||
|
|
||||||
if s.staged.Direct {
|
if s.staged.Direct {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check if we have local address.
|
p := msg.Packet
|
||||||
// TODO: Send local probe
|
|
||||||
|
if p.TraceID != localProbe.TraceID && p.TraceID != probe.TraceID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrade connection.
|
||||||
|
|
||||||
|
s.staged.Direct = true
|
||||||
|
if p.TraceID == localProbe.TraceID {
|
||||||
|
logf("UP - Local")
|
||||||
|
s.staged.RemoteAddr = localProbeAddr
|
||||||
|
} else {
|
||||||
|
logf("UP - Direct")
|
||||||
|
s.staged.RemoteAddr = probeAddr
|
||||||
|
}
|
||||||
|
s.publish()
|
||||||
|
|
||||||
|
syn.TraceID = newTraceID()
|
||||||
|
syn.Direct = true
|
||||||
|
syn.FromAddr = getLocalAddr()
|
||||||
|
s.sendControlPacket(syn)
|
||||||
|
|
||||||
|
case controlMsg[localDiscoveryPacket]:
|
||||||
|
if s.staged.Direct {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send probe.
|
||||||
|
//
|
||||||
|
// The source port will be the multicast port, so we'll have to
|
||||||
|
// construct the correct address using the peer's listed port.
|
||||||
|
localProbe = probePacket{TraceID: newTraceID()}
|
||||||
|
localProbeAddr = netip.AddrPortFrom(msg.SrcAddr.Addr(), s.peer.Port)
|
||||||
|
s.sendControlPacketTo(localProbe, localProbeAddr)
|
||||||
|
|
||||||
|
case pingTimerMsg:
|
||||||
|
if time.Since(lastSeen) > timeoutInterval {
|
||||||
|
logf("Connection timeout")
|
||||||
|
return s.peerUpdate(s.peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
syn.FromAddr = getLocalAddr()
|
||||||
|
if syn.FromAddr != lastLocalAddr {
|
||||||
|
syn.TraceID = newTraceID()
|
||||||
|
lastLocalAddr = syn.FromAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
s.sendControlPacket(syn)
|
||||||
|
|
||||||
|
if s.staged.Direct {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if !ack.FromAddr.IsValid() {
|
if !ack.FromAddr.IsValid() {
|
||||||
continue
|
continue
|
||||||
@ -331,10 +347,6 @@ func (s *peerSupervisor) client() stateFunc {
|
|||||||
probeAddr = ack.FromAddr
|
probeAddr = ack.FromAddr
|
||||||
|
|
||||||
s.sendControlPacketTo(probe, ack.FromAddr)
|
s.sendControlPacketTo(probe, ack.FromAddr)
|
||||||
|
|
||||||
case <-timeoutTimer.C:
|
|
||||||
logf("Connection timeout")
|
|
||||||
return s.peerUpdate(s.peer)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
package node
|
|
@ -1 +0,0 @@
|
|||||||
## Stage1: Point-to-point Tunnel w/ no Encryption
|
|
@ -1,32 +0,0 @@
|
|||||||
package stage1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"runtime/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RunClient(serverAddrStr string) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
fmt.Printf("%v", r)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
iface, err := openInterface(network, clientIP, netName)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", myAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
serverAddr, err := netip.ParseAddrPort(fmt.Sprintf("%s:%d", serverAddrStr, port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
go readFromIFace(iface, conn, serverIP, serverAddr)
|
|
||||||
readFromConn(iface, conn)
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build
|
|
||||||
|
|
||||||
scp client kevin:/home/jdl/tmp
|
|
||||||
ssh root@home "setcap cap_net_admin+iep /home/jdl/tmp/client"
|
|
||||||
ssh home "/home/jdl/tmp/client 192.168.1.21"
|
|
@ -1,14 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"vppn/stage1"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) != 2 {
|
|
||||||
log.Fatalf("Usage: %s <addr:port>", os.Args[0])
|
|
||||||
}
|
|
||||||
stage1.RunClient(os.Args[1])
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build
|
|
||||||
sudo setcap cap_net_admin+iep server
|
|
@ -1,14 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"vppn/stage1"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) != 2 {
|
|
||||||
log.Fatalf("Usage: %s <addr>", os.Args[0])
|
|
||||||
}
|
|
||||||
stage1.RunServer(os.Args[1])
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
package stage1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
if_mtu = 1200
|
|
||||||
if_queue_len = 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
func openInterface(network []byte, localIP byte, name string) (io.ReadWriteCloser, error) {
|
|
||||||
if len(network) != 4 {
|
|
||||||
return nil, fmt.Errorf("expected network to be 4 bytes, got %d", len(network))
|
|
||||||
}
|
|
||||||
ip := net.IPv4(network[0], network[1], network[2], localIP)
|
|
||||||
|
|
||||||
//////////////////////////
|
|
||||||
// Create TUN Interface //
|
|
||||||
//////////////////////////
|
|
||||||
|
|
||||||
tunFD, err := syscall.Open("/dev/net/tun", syscall.O_RDWR|unix.O_CLOEXEC, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to open TUN device: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New interface request.
|
|
||||||
req, err := unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create new TUN interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flags:
|
|
||||||
//
|
|
||||||
// IFF_NO_PI => don't add packet info data to packets sent to the interface.
|
|
||||||
// IFF_TUN => create a TUN device handling IP packets.
|
|
||||||
req.SetUint16(unix.IFF_NO_PI | unix.IFF_TUN)
|
|
||||||
|
|
||||||
err = unix.IoctlIfreq(tunFD, unix.TUNSETIFF, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set TUN device settings: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name may not be exactly the same?
|
|
||||||
name = req.Name()
|
|
||||||
|
|
||||||
/////////////
|
|
||||||
// Set MTU //
|
|
||||||
/////////////
|
|
||||||
|
|
||||||
// We need a socket file descriptor to set other options for some reason.
|
|
||||||
sockFD, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to open socket: %w", err)
|
|
||||||
}
|
|
||||||
defer unix.Close(sockFD)
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create MTU interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.SetUint32(if_mtu)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFMTU, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface MTU: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// Set Queue Length //
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create IP interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.SetUint16(if_queue_len)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFTXQLEN, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface queue length: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////
|
|
||||||
// Set IP and Mask //
|
|
||||||
/////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create IP interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.SetInet4Addr(ip.To4()); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface request IP: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFADDR, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface IP: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SET MASK - must happen after setting address.
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create mask interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.SetInet4Addr(net.IPv4(255, 255, 255, 0).To4()); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface request mask: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unix.IoctlIfreq(sockFD, unix.SIOCSIFNETMASK, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface mask: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////
|
|
||||||
// Bring Interface Up //
|
|
||||||
////////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create up interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current flags.
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCGIFFLAGS, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get interface flags: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := req.Uint16() | unix.IFF_UP | unix.IFF_RUNNING
|
|
||||||
|
|
||||||
// Set UP flag / broadcast flags.
|
|
||||||
req.SetUint16(flags)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFFLAGS, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface up: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.NewFile(uintptr(tunFD), "tun"), nil
|
|
||||||
}
|
|
109
stage1/server.go
109
stage1/server.go
@ -1,109 +0,0 @@
|
|||||||
package stage1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"runtime/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
network = []byte{10, 1, 1, 0}
|
|
||||||
serverIP = byte(1)
|
|
||||||
clientIP = byte(2)
|
|
||||||
port = uint16(5151)
|
|
||||||
netName = "testnet"
|
|
||||||
bufferSize = if_mtu * 2
|
|
||||||
)
|
|
||||||
|
|
||||||
func must(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunServer(clientAddrStr string) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
fmt.Printf("%v", r)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
iface, err := openInterface(network, serverIP, netName)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", myAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
clientAddr, err := netip.ParseAddrPort(fmt.Sprintf("%s:%d", clientAddrStr, port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
go readFromIFace(iface, conn, clientIP, clientAddr)
|
|
||||||
readFromConn(iface, conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFromIFace(iface io.ReadWriteCloser, conn *net.UDPConn, remoteIP byte, remoteAddr netip.AddrPort) {
|
|
||||||
var (
|
|
||||||
n int
|
|
||||||
packet = make([]byte, bufferSize)
|
|
||||||
version byte
|
|
||||||
ip byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
n, err = iface.Read(packet[:bufferSize])
|
|
||||||
must(err)
|
|
||||||
packet = packet[:n]
|
|
||||||
|
|
||||||
if len(packet) < 20 {
|
|
||||||
log.Printf("Dropping small packet: %d", n)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
packet = packet[:n]
|
|
||||||
version = packet[0] >> 4
|
|
||||||
|
|
||||||
switch version {
|
|
||||||
case 4:
|
|
||||||
ip = packet[19]
|
|
||||||
case 6:
|
|
||||||
ip = packet[39]
|
|
||||||
default:
|
|
||||||
log.Printf("Dropping packet with IP version: %d", version)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if ip != remoteIP {
|
|
||||||
log.Printf("Dropping packet for incorrect IP: %d", ip)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.WriteToUDPAddrPort(packet, remoteAddr)
|
|
||||||
must(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFromConn(iface io.ReadWriteCloser, conn *net.UDPConn) {
|
|
||||||
var (
|
|
||||||
n int
|
|
||||||
packet = make([]byte, bufferSize)
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
// We assume that we're only receiving packets from one source.
|
|
||||||
n, err = conn.Read(packet[:bufferSize])
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
packet = packet[:n]
|
|
||||||
_, err = iface.Write(packet)
|
|
||||||
must(err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package stage1
|
|
@ -1,4 +0,0 @@
|
|||||||
## Stage2:
|
|
||||||
|
|
||||||
* Point-to-point Tunnel w/ no Encryption
|
|
||||||
* Server gets client's addr from first packet
|
|
@ -1,35 +0,0 @@
|
|||||||
package stage2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"runtime/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RunClient(serverAddrStr string) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
fmt.Printf("%v", r)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
iface, err := openInterface(network, clientIP, netName)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", myAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
serverAddr, err := netip.ParseAddrPort(fmt.Sprintf("%s:%d", serverAddrStr, port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
_, err = conn.WriteToUDPAddrPort([]byte{1, 2, 3, 4, 5, 6, 7, 8}, serverAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
go readFromIFace(iface, conn, serverIP, serverAddr)
|
|
||||||
readFromConn(iface, conn)
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build
|
|
||||||
sudo setcap cap_net_admin+iep ./client
|
|
||||||
./client 144.76.78.93
|
|
@ -1,14 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"vppn/stage2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) != 2 {
|
|
||||||
log.Fatalf("Usage: %s <addr:port>", os.Args[0])
|
|
||||||
}
|
|
||||||
stage2.RunClient(os.Args[1])
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build
|
|
||||||
scp server kevin:/home/jdl/tmp/
|
|
||||||
ssh root@kevin "sudo setcap cap_net_admin+iep /home/jdl/tmp/server"
|
|
||||||
ssh kevin "/home/jdl/tmp/server"
|
|
@ -1,7 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "vppn/stage2"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
stage2.RunServer()
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
package stage2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
if_mtu = 1200
|
|
||||||
if_queue_len = 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
func openInterface(network []byte, localIP byte, name string) (io.ReadWriteCloser, error) {
|
|
||||||
if len(network) != 4 {
|
|
||||||
return nil, fmt.Errorf("expected network to be 4 bytes, got %d", len(network))
|
|
||||||
}
|
|
||||||
ip := net.IPv4(network[0], network[1], network[2], localIP)
|
|
||||||
|
|
||||||
//////////////////////////
|
|
||||||
// Create TUN Interface //
|
|
||||||
//////////////////////////
|
|
||||||
|
|
||||||
tunFD, err := syscall.Open("/dev/net/tun", syscall.O_RDWR|unix.O_CLOEXEC, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to open TUN device: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New interface request.
|
|
||||||
req, err := unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create new TUN interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flags:
|
|
||||||
//
|
|
||||||
// IFF_NO_PI => don't add packet info data to packets sent to the interface.
|
|
||||||
// IFF_TUN => create a TUN device handling IP packets.
|
|
||||||
req.SetUint16(unix.IFF_NO_PI | unix.IFF_TUN)
|
|
||||||
|
|
||||||
err = unix.IoctlIfreq(tunFD, unix.TUNSETIFF, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set TUN device settings: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name may not be exactly the same?
|
|
||||||
name = req.Name()
|
|
||||||
|
|
||||||
/////////////
|
|
||||||
// Set MTU //
|
|
||||||
/////////////
|
|
||||||
|
|
||||||
// We need a socket file descriptor to set other options for some reason.
|
|
||||||
sockFD, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to open socket: %w", err)
|
|
||||||
}
|
|
||||||
defer unix.Close(sockFD)
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create MTU interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.SetUint32(if_mtu)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFMTU, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface MTU: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// Set Queue Length //
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create IP interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.SetUint16(if_queue_len)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFTXQLEN, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface queue length: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////
|
|
||||||
// Set IP and Mask //
|
|
||||||
/////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create IP interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.SetInet4Addr(ip.To4()); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface request IP: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFADDR, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface IP: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SET MASK - must happen after setting address.
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create mask interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.SetInet4Addr(net.IPv4(255, 255, 255, 0).To4()); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface request mask: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unix.IoctlIfreq(sockFD, unix.SIOCSIFNETMASK, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface mask: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////
|
|
||||||
// Bring Interface Up //
|
|
||||||
////////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create up interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current flags.
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCGIFFLAGS, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get interface flags: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := req.Uint16() | unix.IFF_UP | unix.IFF_RUNNING
|
|
||||||
|
|
||||||
// Set UP flag / broadcast flags.
|
|
||||||
req.SetUint16(flags)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFFLAGS, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface up: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.NewFile(uintptr(tunFD), "tun"), nil
|
|
||||||
}
|
|
112
stage2/server.go
112
stage2/server.go
@ -1,112 +0,0 @@
|
|||||||
package stage2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"runtime/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
network = []byte{10, 1, 1, 0}
|
|
||||||
serverIP = byte(1)
|
|
||||||
clientIP = byte(2)
|
|
||||||
port = uint16(5151)
|
|
||||||
netName = "testnet"
|
|
||||||
bufferSize = if_mtu * 2
|
|
||||||
)
|
|
||||||
|
|
||||||
func must(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunServer() {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
fmt.Printf("%v", r)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
iface, err := openInterface(network, serverIP, netName)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", myAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
// Get remoteAddr from a packet.
|
|
||||||
buf := make([]byte, 8)
|
|
||||||
_, remoteAddr, err := conn.ReadFromUDPAddrPort(buf)
|
|
||||||
log.Printf("Got remote addr: %v", remoteAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
go readFromIFace(iface, conn, clientIP, remoteAddr)
|
|
||||||
readFromConn(iface, conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFromIFace(iface io.ReadWriteCloser, conn *net.UDPConn, remoteIP byte, remoteAddr netip.AddrPort) {
|
|
||||||
var (
|
|
||||||
n int
|
|
||||||
packet = make([]byte, bufferSize)
|
|
||||||
version byte
|
|
||||||
ip byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
n, err = iface.Read(packet[:bufferSize])
|
|
||||||
must(err)
|
|
||||||
packet = packet[:n]
|
|
||||||
|
|
||||||
if len(packet) < 20 {
|
|
||||||
log.Printf("Dropping small packet: %d", n)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
packet = packet[:n]
|
|
||||||
version = packet[0] >> 4
|
|
||||||
|
|
||||||
switch version {
|
|
||||||
case 4:
|
|
||||||
ip = packet[19]
|
|
||||||
case 6:
|
|
||||||
ip = packet[39]
|
|
||||||
default:
|
|
||||||
log.Printf("Dropping packet with IP version: %d", version)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if ip != remoteIP {
|
|
||||||
log.Printf("Dropping packet for incorrect IP: %d", ip)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.WriteToUDPAddrPort(packet, remoteAddr)
|
|
||||||
must(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFromConn(iface io.ReadWriteCloser, conn *net.UDPConn) {
|
|
||||||
var (
|
|
||||||
n int
|
|
||||||
packet = make([]byte, bufferSize)
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
// We assume that we're only receiving packets from one source.
|
|
||||||
n, err = conn.Read(packet[:bufferSize])
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
packet = packet[:n]
|
|
||||||
_, err = iface.Write(packet)
|
|
||||||
must(err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package stage2
|
|
@ -1,16 +0,0 @@
|
|||||||
## Stage3:
|
|
||||||
|
|
||||||
* Point-to-point Tunnel w/ no Encryption
|
|
||||||
* Server gets client's addr from first packet
|
|
||||||
* Add packet counter to detect skipped and late packets
|
|
||||||
|
|
||||||
### Learnings
|
|
||||||
|
|
||||||
* Directional packet loss is an issue.
|
|
||||||
* Sending to hetzner: ~380 Mbits/sec
|
|
||||||
* From hetzner: ~800 Mbits/sec
|
|
||||||
* Runs of dropped packets are generally small < 30
|
|
||||||
* Saw a few cases of 100-200
|
|
||||||
* Runs of correctly-sequenced packets are generally >> drops
|
|
||||||
* Late packets aren't so common
|
|
||||||
* Dropping late packets causes large slow-down.
|
|
@ -1,35 +0,0 @@
|
|||||||
package stage3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"runtime/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RunClient(serverAddrStr string) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
fmt.Printf("%v", r)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
iface, err := openInterface(network, clientIP, netName)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", myAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
serverAddr, err := netip.ParseAddrPort(fmt.Sprintf("%s:%d", serverAddrStr, port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
_, err = conn.WriteToUDPAddrPort([]byte{1, 2, 3, 4, 5, 6, 7, 8}, serverAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
go readFromIFace(iface, conn, clientIP, serverIP, serverAddr)
|
|
||||||
readFromConn(iface, conn, serverIP)
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build
|
|
||||||
sudo setcap cap_net_admin+iep ./client
|
|
||||||
./client 144.76.78.93
|
|
@ -1,14 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"vppn/stage3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) != 2 {
|
|
||||||
log.Fatalf("Usage: %s <addr:port>", os.Args[0])
|
|
||||||
}
|
|
||||||
stage3.RunClient(os.Args[1])
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go build
|
|
||||||
ssh kevin "killall server"
|
|
||||||
scp server kevin:/home/jdl/tmp/
|
|
||||||
ssh root@kevin "sudo setcap cap_net_admin+iep /home/jdl/tmp/server"
|
|
||||||
ssh kevin "/home/jdl/tmp/server"
|
|
@ -1,7 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "vppn/stage3"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
stage3.RunServer()
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
package stage3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
if_mtu = 1200
|
|
||||||
if_queue_len = 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
func openInterface(network []byte, localIP byte, name string) (io.ReadWriteCloser, error) {
|
|
||||||
if len(network) != 4 {
|
|
||||||
return nil, fmt.Errorf("expected network to be 4 bytes, got %d", len(network))
|
|
||||||
}
|
|
||||||
ip := net.IPv4(network[0], network[1], network[2], localIP)
|
|
||||||
|
|
||||||
//////////////////////////
|
|
||||||
// Create TUN Interface //
|
|
||||||
//////////////////////////
|
|
||||||
|
|
||||||
tunFD, err := syscall.Open("/dev/net/tun", syscall.O_RDWR|unix.O_CLOEXEC, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to open TUN device: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New interface request.
|
|
||||||
req, err := unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create new TUN interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flags:
|
|
||||||
//
|
|
||||||
// IFF_NO_PI => don't add packet info data to packets sent to the interface.
|
|
||||||
// IFF_TUN => create a TUN device handling IP packets.
|
|
||||||
req.SetUint16(unix.IFF_NO_PI | unix.IFF_TUN)
|
|
||||||
|
|
||||||
err = unix.IoctlIfreq(tunFD, unix.TUNSETIFF, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set TUN device settings: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name may not be exactly the same?
|
|
||||||
name = req.Name()
|
|
||||||
|
|
||||||
/////////////
|
|
||||||
// Set MTU //
|
|
||||||
/////////////
|
|
||||||
|
|
||||||
// We need a socket file descriptor to set other options for some reason.
|
|
||||||
sockFD, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to open socket: %w", err)
|
|
||||||
}
|
|
||||||
defer unix.Close(sockFD)
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create MTU interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.SetUint32(if_mtu)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFMTU, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface MTU: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// Set Queue Length //
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create IP interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.SetUint16(if_queue_len)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFTXQLEN, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface queue length: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////
|
|
||||||
// Set IP and Mask //
|
|
||||||
/////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create IP interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.SetInet4Addr(ip.To4()); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface request IP: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFADDR, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface IP: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SET MASK - must happen after setting address.
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create mask interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.SetInet4Addr(net.IPv4(255, 255, 255, 0).To4()); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface request mask: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unix.IoctlIfreq(sockFD, unix.SIOCSIFNETMASK, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface mask: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////
|
|
||||||
// Bring Interface Up //
|
|
||||||
////////////////////////
|
|
||||||
|
|
||||||
req, err = unix.NewIfreq(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create up interface request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current flags.
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCGIFFLAGS, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get interface flags: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := req.Uint16() | unix.IFF_UP | unix.IFF_RUNNING
|
|
||||||
|
|
||||||
// Set UP flag / broadcast flags.
|
|
||||||
req.SetUint16(flags)
|
|
||||||
if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFFLAGS, req); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set interface up: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.NewFile(uintptr(tunFD), "tun"), nil
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package stage3
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
const headerSize = 9
|
|
||||||
|
|
||||||
type packetHeader struct {
|
|
||||||
SrcIP byte
|
|
||||||
Counter uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h packetHeader) Marshal(buf []byte) int {
|
|
||||||
buf = buf[:9]
|
|
||||||
buf[0] = h.SrcIP
|
|
||||||
*(*uint64)(unsafe.Pointer(&buf[1])) = h.Counter
|
|
||||||
return headerSize
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *packetHeader) Parse(buf []byte) int {
|
|
||||||
h.SrcIP = buf[0]
|
|
||||||
h.Counter = *(*uint64)(unsafe.Pointer(&buf[1]))
|
|
||||||
return headerSize
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package stage3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPacketHeader(t *testing.T) {
|
|
||||||
b := make([]byte, 1024)
|
|
||||||
|
|
||||||
h := packetHeader{
|
|
||||||
SrcIP: 8,
|
|
||||||
Counter: 2354,
|
|
||||||
}
|
|
||||||
n := h.Marshal(b)
|
|
||||||
h2 := packetHeader{}
|
|
||||||
h2.Parse(b[:n])
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(h, h2) {
|
|
||||||
t.Fatal(h, h2)
|
|
||||||
}
|
|
||||||
}
|
|
147
stage3/server.go
147
stage3/server.go
@ -1,147 +0,0 @@
|
|||||||
package stage3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"runtime/debug"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
network = []byte{10, 1, 1, 0}
|
|
||||||
serverIP = byte(1)
|
|
||||||
clientIP = byte(2)
|
|
||||||
port = uint16(5151)
|
|
||||||
netName = "testnet"
|
|
||||||
bufferSize = if_mtu * 2
|
|
||||||
)
|
|
||||||
|
|
||||||
func must(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunServer() {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
fmt.Printf("%v", r)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
iface, err := openInterface(network, serverIP, netName)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", myAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
// Get remoteAddr from a packet.
|
|
||||||
buf := make([]byte, 8)
|
|
||||||
_, remoteAddr, err := conn.ReadFromUDPAddrPort(buf)
|
|
||||||
log.Printf("Got remote addr: %v", remoteAddr)
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
go readFromIFace(iface, conn, serverIP, clientIP, remoteAddr)
|
|
||||||
readFromConn(iface, conn, clientIP)
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFromIFace(iface io.ReadWriteCloser, conn *net.UDPConn, localIP, remoteIP byte, remoteAddr netip.AddrPort) {
|
|
||||||
var (
|
|
||||||
n int
|
|
||||||
packet = make([]byte, bufferSize)
|
|
||||||
version byte
|
|
||||||
ip byte
|
|
||||||
err error
|
|
||||||
counter uint64
|
|
||||||
buf = make([]byte, bufferSize)
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
n, err = iface.Read(packet[:bufferSize])
|
|
||||||
must(err)
|
|
||||||
packet = packet[:n]
|
|
||||||
|
|
||||||
if len(packet) < 20 {
|
|
||||||
log.Printf("Dropping small packet: %d", n)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
packet = packet[:n]
|
|
||||||
version = packet[0] >> 4
|
|
||||||
|
|
||||||
switch version {
|
|
||||||
case 4:
|
|
||||||
ip = packet[19]
|
|
||||||
case 6:
|
|
||||||
ip = packet[39]
|
|
||||||
default:
|
|
||||||
log.Printf("Dropping packet with IP version: %d", version)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if ip != remoteIP {
|
|
||||||
log.Printf("Dropping packet for incorrect IP: %d", ip)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
h := packetHeader{SrcIP: localIP, Counter: counter}
|
|
||||||
counter++
|
|
||||||
buf = buf[:headerSize+len(packet)]
|
|
||||||
h.Marshal(buf)
|
|
||||||
copy(buf[headerSize:], packet)
|
|
||||||
|
|
||||||
_, err = conn.WriteToUDPAddrPort(buf, remoteAddr)
|
|
||||||
must(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFromConn(iface io.ReadWriteCloser, conn *net.UDPConn, remoteIP byte) {
|
|
||||||
var (
|
|
||||||
n int
|
|
||||||
packet = make([]byte, bufferSize)
|
|
||||||
err error
|
|
||||||
counter uint64
|
|
||||||
run uint64
|
|
||||||
h packetHeader
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
// We assume that we're only receiving packets from one source.
|
|
||||||
n, err = conn.Read(packet[:bufferSize])
|
|
||||||
must(err)
|
|
||||||
|
|
||||||
packet = packet[:n]
|
|
||||||
if len(packet) < headerSize {
|
|
||||||
fmt.Print("_")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
h.Parse(packet)
|
|
||||||
if h.SrcIP != remoteIP {
|
|
||||||
fmt.Print("?")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.Counter == counter+1 {
|
|
||||||
run++
|
|
||||||
counter = h.Counter
|
|
||||||
} else if h.Counter > counter+1 {
|
|
||||||
fmt.Printf("x(%d/%d)", h.Counter-counter+1, run)
|
|
||||||
run = 0
|
|
||||||
counter = h.Counter
|
|
||||||
} else if h.Counter <= counter {
|
|
||||||
//log.Printf("Skipped late packet: -%d", counter-h.Counter)
|
|
||||||
//continue
|
|
||||||
fmt.Print("<")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = iface.Write(packet[headerSize:])
|
|
||||||
must(err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package stage3
|
|
Loading…
x
Reference in New Issue
Block a user