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 {
|
||||
db *sql.DB
|
||||
lock sync.Mutex
|
||||
peerIntents map[string]PeerCreateArgs
|
||||
initIntents map[string]byte // Map from intent key to peer IP
|
||||
}
|
||||
|
||||
@ -40,7 +39,6 @@ func New(dbPath string) (*API, error) {
|
||||
|
||||
a := &API{
|
||||
db: sqlDB,
|
||||
peerIntents: map[string]PeerCreateArgs{},
|
||||
initIntents: map[string]byte{},
|
||||
}
|
||||
|
||||
@ -153,34 +151,6 @@ func (a *API) Peer_CreateNew(p *Peer) error {
|
||||
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
|
||||
// complete the peer initialization. The code is valid for 5 minutes.
|
||||
func (a *API) Peer_CreateInitIntent(peerIP byte) string {
|
||||
@ -252,79 +222,6 @@ func (a *API) Peer_Init(initCode string) (*m.PeerConfig, error) {
|
||||
}, 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 {
|
||||
a.lock.Lock()
|
||||
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
|
||||
}
|
||||
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 {
|
||||
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})
|
||||
}
|
||||
|
||||
// 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 {
|
||||
var peerIP byte
|
||||
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)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
_, apiKey, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
@ -392,6 +367,7 @@ func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error {
|
||||
Port: p.Port,
|
||||
Relay: p.Relay,
|
||||
PubKey: p.PubKey,
|
||||
PubSignKey: p.PubSignKey,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,15 +20,12 @@ func (a *App) registerRoutes() {
|
||||
a.handleSignedIn("GET /admin/peer/create/", a._adminPeerCreate)
|
||||
a.handleSignedIn("POST /admin/peer/create/", a._adminPeerCreateSubmit)
|
||||
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/edit/", a._adminPeerEdit)
|
||||
a.handleSignedIn("POST /admin/peer/edit/", a._adminPeerEditSubmit)
|
||||
a.handleSignedIn("GET /admin/peer/delete/", a._adminPeerDelete)
|
||||
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/fetch-state/", a._peerFetchState)
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
package hub
|
@ -13,21 +13,17 @@ func addrDiscoveryServer() {
|
||||
)
|
||||
|
||||
for {
|
||||
pkt := <-discoveryPackets
|
||||
msg := <-discoveryMessages
|
||||
p := msg.Packet
|
||||
|
||||
p, ok := pkt.Payload.(addrDiscoveryPacket)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
route := routingTable[pkt.SrcIP].Load()
|
||||
route := routingTable[msg.SrcIP].Load()
|
||||
if route == nil || !route.RemoteAddr.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
_sendControlPacket(addrDiscoveryPacket{
|
||||
TraceID: p.TraceID,
|
||||
ToAddr: pkt.SrcAddr,
|
||||
ToAddr: msg.SrcAddr,
|
||||
}, *route, buf1, buf2)
|
||||
}
|
||||
}
|
||||
@ -46,9 +42,9 @@ func addrDiscoveryClient() {
|
||||
|
||||
for {
|
||||
select {
|
||||
case pkt := <-discoveryPackets:
|
||||
p, ok := pkt.Payload.(addrDiscoveryPacket)
|
||||
if !ok || p.TraceID != addrPacket.TraceID || !p.ToAddr.IsValid() || p.ToAddr == lAddr {
|
||||
case msg := <-discoveryMessages:
|
||||
p := msg.Packet
|
||||
if p.TraceID != addrPacket.TraceID || !p.ToAddr.IsValid() || p.ToAddr == lAddr {
|
||||
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
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"vppn/m"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -13,6 +13,12 @@ const (
|
||||
if_queue_len = 2048
|
||||
controlCipherOverhead = 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 {
|
||||
@ -56,18 +62,9 @@ var (
|
||||
return
|
||||
}()
|
||||
|
||||
// Channels for incoming control packets.
|
||||
controlPackets [256]chan controlPacket = func() (out [256]chan controlPacket) {
|
||||
messages [256]chan any = func() (out [256]chan any) {
|
||||
for i := range out {
|
||||
out[i] = make(chan controlPacket, 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)
|
||||
out[i] = make(chan any, 256)
|
||||
}
|
||||
return
|
||||
}()
|
||||
@ -81,8 +78,10 @@ var (
|
||||
return
|
||||
}()
|
||||
|
||||
// Managed by the addrDiscovery* functions.
|
||||
discoveryMessages = make(chan controlMsg[addrDiscoveryPacket], 256)
|
||||
|
||||
// Managed by the relayManager.
|
||||
discoveryPackets = make(chan controlPacket, 256)
|
||||
localAddr = &atomic.Pointer[netip.AddrPort]{}
|
||||
relayIP = &atomic.Pointer[byte]{}
|
||||
)
|
||||
|
@ -86,7 +86,7 @@ func (hp *hubPoller) applyNetworkState(state m.NetworkState) {
|
||||
for i, peer := range state.Peers {
|
||||
if i != int(localIP) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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 (
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"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() {
|
||||
conn, err := net.ListenMulticastUDP("udp", nil, multicastAddr)
|
||||
if err != nil {
|
||||
@ -32,8 +25,9 @@ func sendLocalDiscovery(conn *net.UDPConn) {
|
||||
buf2 = make([]byte, bufferSize)
|
||||
)
|
||||
|
||||
for range time.Tick(16 * time.Second) {
|
||||
for range time.Tick(32 * time.Second) {
|
||||
signed := buildLocalDiscoveryPacket(buf1, buf2)
|
||||
log.Printf("Sending discovery packet...")
|
||||
if _, err := conn.WriteToUDP(signed, multicastAddr); err != nil {
|
||||
log.Printf("Failed to write multicast UDP packet: %v", err)
|
||||
}
|
||||
@ -51,21 +45,24 @@ func recvLocalDiscovery(conn *net.UDPConn) {
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read from UDP port (multicast): %v", err)
|
||||
}
|
||||
log.Printf("Got local discovery packet...")
|
||||
|
||||
raw = raw[:n]
|
||||
h, ok := openLocalDiscoveryPacket(raw, buf)
|
||||
if !ok {
|
||||
log.Printf("Failed to open discovery packet?")
|
||||
continue
|
||||
}
|
||||
|
||||
pkt := controlPacket{
|
||||
msg := controlMsg[localDiscoveryPacket]{
|
||||
SrcIP: h.SourceIP,
|
||||
SrcAddr: remoteAddr,
|
||||
Payload: localDiscoveryPacket{},
|
||||
Packet: localDiscoveryPacket{},
|
||||
}
|
||||
log.Printf("Got local discovery packet from %d/%v...", h.SourceIP, remoteAddr)
|
||||
|
||||
select {
|
||||
case controlPackets[h.SourceIP] <- pkt:
|
||||
case messages[h.SourceIP] <- msg:
|
||||
default:
|
||||
}
|
||||
}
|
||||
@ -92,6 +89,7 @@ func openLocalDiscoveryPacket(raw, buf []byte) (h header, ok bool) {
|
||||
h.Parse(raw[signOverhead:])
|
||||
route := routingTable[h.SourceIP].Load()
|
||||
if route == nil || route.PubSignKey == nil {
|
||||
log.Printf("Missing signing key")
|
||||
ok = false
|
||||
return
|
||||
}
|
||||
|
56
node/main.go
56
node/main.go
@ -11,6 +11,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
"vppn/m"
|
||||
)
|
||||
|
||||
@ -26,13 +27,11 @@ func Main() {
|
||||
var (
|
||||
initURL string
|
||||
listenIP string
|
||||
port int
|
||||
)
|
||||
|
||||
flag.StringVar(&netName, "name", "", "[REQUIRED] The network name.")
|
||||
flag.StringVar(&initURL, "init-url", "", "Initializes peer from the hub URL.")
|
||||
flag.StringVar(&listenIP, "listen-ip", "", "IP address to listen on.")
|
||||
flag.IntVar(&port, "port", 0, "Port to listen on.")
|
||||
flag.Parse()
|
||||
|
||||
if netName == "" {
|
||||
@ -45,7 +44,7 @@ func Main() {
|
||||
return
|
||||
}
|
||||
|
||||
main(listenIP, uint16(port))
|
||||
main(listenIP)
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load configuration: %v", err)
|
||||
}
|
||||
|
||||
port = determinePort(config.Port, port)
|
||||
|
||||
iface, err := openInterface(config.Network, config.PeerIP, netName)
|
||||
if err != nil {
|
||||
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 {
|
||||
log.Fatalf("Failed to resolve UDP address: %v", err)
|
||||
}
|
||||
@ -129,6 +126,17 @@ func main(listenIP string, port uint16) {
|
||||
go localDiscovery()
|
||||
}
|
||||
|
||||
go func() {
|
||||
for range time.Tick(pingInterval) {
|
||||
for i := range messages {
|
||||
select {
|
||||
case messages[i] <- pingTimerMsg{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go newHubPoller(config).Run()
|
||||
go readFromConn(conn)
|
||||
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) {
|
||||
|
||||
defer panicHandler()
|
||||
@ -218,32 +214,22 @@ func handleControlPacket(addr netip.AddrPort, h header, data, decBuf []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
pkt := controlPacket{
|
||||
SrcIP: h.SourceIP,
|
||||
SrcAddr: addr,
|
||||
}
|
||||
|
||||
if err := pkt.ParsePayload(out); err != nil {
|
||||
msg, err := parseControlMsg(h.SourceIP, addr, out)
|
||||
if err != nil {
|
||||
log.Printf("Failed to parse control packet: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch pkt.Payload.(type) {
|
||||
|
||||
case addrDiscoveryPacket:
|
||||
select {
|
||||
case discoveryPackets <- pkt:
|
||||
default:
|
||||
log.Printf("Dropping discovery packet.")
|
||||
if dm, ok := msg.(controlMsg[addrDiscoveryPacket]); ok {
|
||||
discoveryMessages <- dm
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
select {
|
||||
case controlPackets[h.SourceIP] <- pkt:
|
||||
case messages[h.SourceIP] <- msg:
|
||||
default:
|
||||
log.Printf("Dropping control packet.")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1 +1,66 @@
|
||||
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 {
|
||||
TraceID uint64 // TraceID to match response w/ request.
|
||||
SharedKey [32]byte // Our shared key.
|
||||
|
@ -29,8 +29,7 @@ type peerSupervisor struct {
|
||||
remotePub bool
|
||||
|
||||
// Incoming events.
|
||||
peerUpdates chan *m.Peer
|
||||
controlPackets chan controlPacket
|
||||
messages chan any
|
||||
|
||||
// Buffers for sending control packets.
|
||||
buf1 []byte
|
||||
@ -41,8 +40,7 @@ func newPeerSupervisor(i int) *peerSupervisor {
|
||||
return &peerSupervisor{
|
||||
published: routingTable[i],
|
||||
remoteIP: byte(i),
|
||||
peerUpdates: peerUpdates[i],
|
||||
controlPackets: controlPackets[i],
|
||||
messages: messages[i],
|
||||
buf1: make([]byte, bufferSize),
|
||||
buf2: make([]byte, bufferSize),
|
||||
}
|
||||
@ -95,7 +93,12 @@ func (s *peerSupervisor) publish() {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -150,22 +153,19 @@ func (s *peerSupervisor) server() stateFunc {
|
||||
|
||||
var (
|
||||
syn synPacket
|
||||
timeoutTimer = time.NewTimer(timeoutInterval)
|
||||
lastSeen = time.Now()
|
||||
)
|
||||
|
||||
// Timer will be restarted once we have established a connection.
|
||||
timeoutTimer.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case peer := <-s.peerUpdates:
|
||||
return s.peerUpdate(peer)
|
||||
rawMsg := <-s.messages
|
||||
switch msg := rawMsg.(type) {
|
||||
|
||||
case pkt := <-s.controlPackets:
|
||||
switch p := pkt.Payload.(type) {
|
||||
case peerUpdateMsg:
|
||||
return s.peerUpdate(msg.Peer)
|
||||
|
||||
case synPacket:
|
||||
timeoutTimer.Reset(timeoutInterval)
|
||||
case controlMsg[synPacket]:
|
||||
p := msg.Packet
|
||||
lastSeen = time.Now()
|
||||
|
||||
// Before we can respond to this packet, we need to make sure the
|
||||
// route is setup properly.
|
||||
@ -183,7 +183,7 @@ func (s *peerSupervisor) server() stateFunc {
|
||||
s.staged.Up = true
|
||||
s.staged.Direct = syn.Direct
|
||||
s.staged.DataCipher = newDataCipherFromKey(syn.SharedKey)
|
||||
s.staged.RemoteAddr = pkt.SrcAddr
|
||||
s.staged.RemoteAddr = msg.SrcAddr
|
||||
|
||||
s.publish()
|
||||
}
|
||||
@ -206,20 +206,21 @@ func (s *peerSupervisor) server() stateFunc {
|
||||
probe := probePacket{TraceID: newTraceID()}
|
||||
s.sendControlPacketTo(probe, syn.FromAddr)
|
||||
|
||||
case probePacket:
|
||||
if pkt.SrcAddr.IsValid() {
|
||||
s.sendControlPacketTo(probePacket{TraceID: p.TraceID}, pkt.SrcAddr)
|
||||
} else {
|
||||
case controlMsg[probePacket]:
|
||||
if !msg.SrcAddr.IsValid() {
|
||||
logf("Invalid probe address")
|
||||
continue
|
||||
}
|
||||
}
|
||||
s.sendControlPacketTo(probePacket{TraceID: msg.Packet.TraceID}, msg.SrcAddr)
|
||||
|
||||
case <-timeoutTimer.C:
|
||||
case pingTimerMsg:
|
||||
if time.Since(lastSeen) > timeoutInterval {
|
||||
logf("Connection timeout")
|
||||
s.staged.Up = false
|
||||
s.publish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -237,38 +238,36 @@ func (s *peerSupervisor) client() stateFunc {
|
||||
FromAddr: getLocalAddr(),
|
||||
}
|
||||
|
||||
lastSeen = time.Now()
|
||||
ack synAckPacket
|
||||
|
||||
probe probePacket
|
||||
probeAddr netip.AddrPort
|
||||
|
||||
remoteAddr netip.AddrPort
|
||||
localProbe probePacket
|
||||
localProbeAddr netip.AddrPort
|
||||
|
||||
timeoutTimer = time.NewTimer(timeoutInterval)
|
||||
pingTimer = time.NewTimer(pingInterval)
|
||||
lastLocalAddr netip.AddrPort
|
||||
)
|
||||
|
||||
defer timeoutTimer.Stop()
|
||||
defer pingTimer.Stop()
|
||||
|
||||
s.sendControlPacket(syn)
|
||||
|
||||
for {
|
||||
select {
|
||||
rawMsg := <-s.messages
|
||||
switch msg := rawMsg.(type) {
|
||||
|
||||
case peer := <-s.peerUpdates:
|
||||
return s.peerUpdate(peer)
|
||||
case peerUpdateMsg:
|
||||
return s.peerUpdate(msg.Peer)
|
||||
|
||||
case pkt := <-s.controlPackets:
|
||||
switch p := pkt.Payload.(type) {
|
||||
case controlMsg[synAckPacket]:
|
||||
p := msg.Packet
|
||||
|
||||
case synAckPacket:
|
||||
if p.TraceID != syn.TraceID {
|
||||
continue // Hmm...
|
||||
}
|
||||
|
||||
ack = p
|
||||
timeoutTimer.Reset(timeoutInterval)
|
||||
lastSeen = time.Now()
|
||||
ack = msg.Packet
|
||||
|
||||
if !s.staged.Up {
|
||||
if s.staged.Direct {
|
||||
@ -281,47 +280,64 @@ func (s *peerSupervisor) client() stateFunc {
|
||||
s.publish()
|
||||
}
|
||||
|
||||
case probePacket:
|
||||
case controlMsg[probePacket]:
|
||||
if s.staged.Direct {
|
||||
continue
|
||||
}
|
||||
|
||||
if p.TraceID != probe.TraceID {
|
||||
p := msg.Packet
|
||||
|
||||
if p.TraceID != localProbe.TraceID && p.TraceID != probe.TraceID {
|
||||
continue
|
||||
}
|
||||
|
||||
// Upgrade connection.
|
||||
|
||||
logf("UP - Direct")
|
||||
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 <-pingTimer.C:
|
||||
// Send syn.
|
||||
|
||||
syn.FromAddr = getLocalAddr()
|
||||
if syn.FromAddr != remoteAddr {
|
||||
syn.TraceID = newTraceID()
|
||||
remoteAddr = syn.FromAddr
|
||||
}
|
||||
|
||||
s.sendControlPacket(syn)
|
||||
|
||||
pingTimer.Reset(pingInterval)
|
||||
|
||||
case controlMsg[localDiscoveryPacket]:
|
||||
if s.staged.Direct {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: Check if we have local address.
|
||||
// TODO: Send local probe
|
||||
// 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() {
|
||||
continue
|
||||
@ -331,10 +347,6 @@ func (s *peerSupervisor) client() stateFunc {
|
||||
probeAddr = 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