WIP
This commit is contained in:
		
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,15 +2,16 @@ | |||||||
|  |  | ||||||
| ## Roadmap | ## Roadmap | ||||||
|  |  | ||||||
| * Peer: router: create process for managing the routing table | * Use default port 456 | ||||||
| * Peer: router: track mediators, enable / disable ... | * Remove signing key from hub | ||||||
| * Hub: track peer last-seen timestamp (?) | * Peer: UDP hole-punching | ||||||
| * Peer: local peer discovery - part of RoutingProcessor | * Peer: local peer discovery - part of RoutingProcessor | ||||||
| * Peer: update hub w/ latest port on startup | * Peer: update hub w/ latest port on startup | ||||||
|  |  | ||||||
| ## Learnings | ## Learnings | ||||||
|  |  | ||||||
| * Encryption / decryption is 20x faster than signing/opening. | * Encryption / decryption is 20x faster than signing/opening. | ||||||
|  | * Allowing out-of order packets is massively important for throughput with TCP | ||||||
|  |  | ||||||
| ## Principles | ## Principles | ||||||
|  |  | ||||||
| @@ -111,11 +112,3 @@ TimeoutStopSec=24 | |||||||
| [Install] | [Install] | ||||||
| WantedBy=default.target | WantedBy=default.target | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- |  | ||||||
|  |  | ||||||
| ## Sub-packets |  | ||||||
|  |  | ||||||
| If we make our MTU large, like 8k, our computations become more efficient. |  | ||||||
|  |  | ||||||
| We can send packets with header like: |  | ||||||
|   | |||||||
| @@ -14,12 +14,9 @@ const ( | |||||||
|  |  | ||||||
| type connData struct { | type connData struct { | ||||||
| 	// Shared data. | 	// Shared data. | ||||||
| 	routes [256]*atomic.Pointer[route] | 	routes [MAX_IP]*atomic.Pointer[route] | ||||||
| 	route  *atomic.Pointer[route] | 	route  *atomic.Pointer[route] | ||||||
|  |  | ||||||
| 	// Local data. |  | ||||||
| 	mediatorIP byte |  | ||||||
|  |  | ||||||
| 	// Peer data. | 	// Peer data. | ||||||
| 	server     bool   // Never changes. | 	server     bool   // Never changes. | ||||||
| 	peerIP     byte   // Never changes. | 	peerIP     byte   // Never changes. | ||||||
| @@ -29,12 +26,13 @@ type connData struct { | |||||||
| 	encSharedKey []byte         // From hub + private key. | 	encSharedKey []byte         // From hub + private key. | ||||||
| 	publicAddr   netip.AddrPort // From hub. | 	publicAddr   netip.AddrPort // From hub. | ||||||
|  |  | ||||||
|  | 	// Connection establishment and maintenance. | ||||||
| 	pingTimer    *time.Timer | 	pingTimer    *time.Timer | ||||||
| 	timeoutTimer *time.Timer | 	timeoutTimer *time.Timer | ||||||
|  |  | ||||||
| 	// Routing data. | 	// Routing data. | ||||||
| 	addr        netip.AddrPort | 	addr        netip.AddrPort | ||||||
| 	viaIP byte | 	useMediator bool | ||||||
| 	up          bool | 	up          bool | ||||||
|  |  | ||||||
| 	// For sending. | 	// For sending. | ||||||
| @@ -47,10 +45,9 @@ func (d *connData) Route() *route { | |||||||
| 		PeerIP:       d.peerIP, | 		PeerIP:       d.peerIP, | ||||||
| 		Up:           d.up, | 		Up:           d.up, | ||||||
| 		Mediator:     d.peer.Mediator, | 		Mediator:     d.peer.Mediator, | ||||||
| 		SignPubKey:   d.peer.SignPubKey, |  | ||||||
| 		EncSharedKey: d.encSharedKey, | 		EncSharedKey: d.encSharedKey, | ||||||
| 		Addr:         d.addr, | 		Addr:         d.addr, | ||||||
| 		ViaIP:        d.viaIP, | 		useMediator:  d.useMediator, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -61,14 +58,14 @@ func (d *connData) HandlePeerUpdate(state connState, update peerUpdate) connStat | |||||||
| 	if d.peer == nil && update.Peer == nil { | 	if d.peer == nil && update.Peer == nil { | ||||||
| 		return state | 		return state | ||||||
| 	} | 	} | ||||||
| 	return newConnStateFromPeer(update, d) | 	return newStateFromPeerUpdate(update, d) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (d *connData) HandleSendPing() { | func (d *connData) HandleSendPing() { | ||||||
| 	route := d.route.Load() | 	route := d.route.Load() | ||||||
| 	req := Ping{SentAt: time.Now().UnixMilli()} | 	req := Ping{SentAt: time.Now().UnixMilli()} | ||||||
| 	req.Marshal(d.buf[:PING_SIZE]) | 	req.Marshal(d.buf[:PING_SIZE]) | ||||||
| 	d.sender.send(PACKET_TYPE_PING, d.buf[:PING_SIZE], route) | 	d.sender.send(PACKET_TYPE_PING, d.buf[:PING_SIZE], route, nil) | ||||||
| 	d.pingTimer.Reset(pingInterval) | 	d.pingTimer.Reset(pingInterval) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -79,5 +76,5 @@ func (d *connData) sendPong(w wrapper[Ping]) { | |||||||
| 		RecvdAt: time.Now().UnixMilli(), | 		RecvdAt: time.Now().UnixMilli(), | ||||||
| 	} | 	} | ||||||
| 	pong.Marshal(d.buf[:PONG_SIZE]) | 	pong.Marshal(d.buf[:PONG_SIZE]) | ||||||
| 	d.sender.send(PACKET_TYPE_PONG, d.buf[:PONG_SIZE], route) | 	d.sender.send(PACKET_TYPE_PONG, d.buf[:PONG_SIZE], route, nil) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ type connHandler struct { | |||||||
| func newConnHandler( | func newConnHandler( | ||||||
| 	server bool, | 	server bool, | ||||||
| 	peerIP byte, | 	peerIP byte, | ||||||
| 	routes [256]*atomic.Pointer[route], | 	routes [MAX_IP]*atomic.Pointer[route], | ||||||
| 	encPrivKey []byte, | 	encPrivKey []byte, | ||||||
| 	sender *safeConnSender, | 	sender *safeConnSender, | ||||||
| ) *connHandler { | ) *connHandler { | ||||||
| @@ -65,9 +65,6 @@ func (h *connHandler) mainLoop() { | |||||||
| 	for { | 	for { | ||||||
| 		select { | 		select { | ||||||
|  |  | ||||||
| 		case ip := <-h.mediatorUpdates: |  | ||||||
| 			state = state.HandleMediatorUpdate(ip) |  | ||||||
|  |  | ||||||
| 		case update := <-h.peerUpdates: | 		case update := <-h.peerUpdates: | ||||||
| 			state = data.HandlePeerUpdate(state, update) | 			state = data.HandlePeerUpdate(state, update) | ||||||
|  |  | ||||||
| @@ -92,13 +89,6 @@ func (h *connHandler) mainLoop() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *connHandler) UpdateMediator(ip byte) { |  | ||||||
| 	select { |  | ||||||
| 	case c.mediatorUpdates <- ip: |  | ||||||
| 	default: |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *connHandler) HandlePing(w wrapper[Ping]) { | func (c *connHandler) HandlePing(w wrapper[Ping]) { | ||||||
| 	select { | 	select { | ||||||
| 	case c.pings <- w: | 	case c.pings <- w: | ||||||
|   | |||||||
| @@ -15,10 +15,9 @@ type connSender struct { | |||||||
| 	encrypted []byte | 	encrypted []byte | ||||||
| 	nonceBuf  []byte | 	nonceBuf  []byte | ||||||
| 	counter   uint64 | 	counter   uint64 | ||||||
| 	signingKey []byte |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func newConnSender(conn *net.UDPConn, srcIP, streamID byte, signingPrivKey []byte) *connSender { | func newConnSender(conn *net.UDPConn, srcIP, streamID byte) *connSender { | ||||||
| 	return &connSender{ | 	return &connSender{ | ||||||
| 		conn:      conn, | 		conn:      conn, | ||||||
| 		sourceIP:  srcIP, | 		sourceIP:  srcIP, | ||||||
| @@ -26,34 +25,42 @@ func newConnSender(conn *net.UDPConn, srcIP, streamID byte, signingPrivKey []byt | |||||||
| 		encrypted: make([]byte, BUFFER_SIZE), | 		encrypted: make([]byte, BUFFER_SIZE), | ||||||
| 		nonceBuf:  make([]byte, NONCE_SIZE), | 		nonceBuf:  make([]byte, NONCE_SIZE), | ||||||
| 		counter:   uint64(fasttime.Now()) << 30, // Ensure counter is always increasing. | 		counter:   uint64(fasttime.Now()) << 30, // Ensure counter is always increasing. | ||||||
| 		signingKey: signingPrivKey, |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (cs *connSender) send(packetType byte, packet []byte, route *route) { | func (cs *connSender) send(packetType byte, packet []byte, dstRoute, viaRoute *route) { | ||||||
|  | 	if dstRoute.useMediator && viaRoute == nil { | ||||||
|  | 		log.Printf("Dropping forwarded packet: no mediator.") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	cs.counter++ | 	cs.counter++ | ||||||
|  |  | ||||||
| 	nonce := Nonce{ | 	nonce := Nonce{ | ||||||
| 		Timestamp:  fasttime.Now(), | 		Timestamp:  fasttime.Now(), | ||||||
| 		Counter:    cs.counter, | 		Counter:    cs.counter, | ||||||
| 		SourceIP:   cs.sourceIP, | 		SourceIP:   cs.sourceIP, | ||||||
| 		ViaIP:      route.ViaIP, | 		DestIP:     dstRoute.PeerIP, | ||||||
| 		DestIP:     route.PeerIP, |  | ||||||
| 		StreamID:   cs.streamID, | 		StreamID:   cs.streamID, | ||||||
| 		PacketType: packetType, | 		PacketType: packetType, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	nonce.Marshal(cs.nonceBuf) | 	if dstRoute.useMediator { | ||||||
|  | 		nonce.ViaIP = viaRoute.PeerIP | ||||||
| 	encrypted := encryptPacket(route.EncSharedKey, cs.nonceBuf, packet, cs.encrypted) |  | ||||||
|  |  | ||||||
| 	var toSend []byte |  | ||||||
| 	if route.ViaIP != 0 { |  | ||||||
| 		toSend = signPacket(cs.signingKey, encrypted, packet) |  | ||||||
| 	} else { |  | ||||||
| 		toSend = encrypted |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if _, err := cs.conn.WriteToUDPAddrPort(toSend, route.Addr); err != nil { | 	nonce.Marshal(cs.nonceBuf) | ||||||
|  |  | ||||||
|  | 	addr := dstRoute.Addr | ||||||
|  |  | ||||||
|  | 	encrypted := encryptPacket(dstRoute.EncSharedKey, cs.nonceBuf, packet, cs.encrypted) | ||||||
|  | 	if viaRoute != nil { | ||||||
|  | 		packet, encrypted = encrypted, packet | ||||||
|  | 		encrypted = encryptPacket(viaRoute.EncSharedKey, cs.nonceBuf, packet, encrypted) | ||||||
|  | 		addr = viaRoute.Addr | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if _, err := cs.conn.WriteToUDPAddrPort(encrypted, addr); err != nil { | ||||||
| 		log.Fatalf("Failed to write UDP packet: %v\n%s", err, debug.Stack()) | 		log.Fatalf("Failed to write UDP packet: %v\n%s", err, debug.Stack()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -69,8 +76,8 @@ func newSafeConnSender(sender *connSender) *safeConnSender { | |||||||
| 	return &safeConnSender{sender: sender} | 	return &safeConnSender{sender: sender} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *safeConnSender) send(packetType byte, packet []byte, route *route) { | func (s *safeConnSender) send(packetType byte, packet []byte, route, viaRoute *route) { | ||||||
| 	s.lock.Lock() | 	s.lock.Lock() | ||||||
| 	defer s.lock.Unlock() | 	defer s.lock.Unlock() | ||||||
| 	s.sender.send(packetType, packet, route) | 	s.sender.send(packetType, packet, route, viaRoute) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,32 +11,31 @@ func logState(s connState, msg string, args ...any) { | |||||||
| 	log.Printf("["+s.Name()+"] "+msg, args...) | 	log.Printf("["+s.Name()+"] "+msg, args...) | ||||||
| } | } | ||||||
|  |  | ||||||
| // ---------------------------------------------------------------------------- |  | ||||||
|  |  | ||||||
| // The connection state corresponds to what we're connected TO. | // The connection state corresponds to what we're connected TO. | ||||||
| type connState interface { | type connState interface { | ||||||
| 	Name() string | 	Name() string | ||||||
| 	HandleMediatorUpdate(ip byte) connState | 	//HandleConnReq(wrapper[ConnReq]) connState | ||||||
| 	HandlePing(wrapper[Ping]) connState | 	HandlePing(wrapper[Ping]) connState | ||||||
| 	HandlePong(wrapper[Pong]) connState | 	HandlePong(wrapper[Pong]) connState | ||||||
| 	HandleTimeout() connState | 	HandleTimeout() connState | ||||||
| } | } | ||||||
|  |  | ||||||
| // Helper function. | // Helper functions. | ||||||
|  |  | ||||||
| func newConnStateFromPeer(update peerUpdate, data *connData) connState { | func newStateFromPeerUpdate(update peerUpdate, data *connData) connState { | ||||||
| 	peer := update.Peer | 	if update.Peer != nil { | ||||||
|  | 		return newStateFromPeer(update.Peer, data) | ||||||
| 	if peer == nil { | 	} | ||||||
| 	return newConnNull(data) | 	return newConnNull(data) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func newStateFromPeer(peer *m.Peer, data *connData) connState { | ||||||
| 	if _, isPublic := netip.AddrFromSlice(peer.PublicIP); isPublic { | 	if _, isPublic := netip.AddrFromSlice(peer.PublicIP); isPublic { | ||||||
| 		return newStateServerDown(data, peer) | 		return newStateServerDown(data, peer) | ||||||
| 	} else if data.server { | 	} else if data.server { | ||||||
| 		return newStateClientDown(data, peer) | 		return newStateClientDown(data, peer) | ||||||
| 	} else { | 	} else { | ||||||
| 		return newStateMediatedDown(data, peer) | 		return newStateMediated(data, peer) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -56,7 +55,7 @@ func newConnNull(data *connData) connState { | |||||||
| 	c.pingTimer.Stop() | 	c.pingTimer.Stop() | ||||||
| 	c.timeoutTimer.Stop() | 	c.timeoutTimer.Stop() | ||||||
| 	c.addr = c.publicAddr | 	c.addr = c.publicAddr | ||||||
| 	c.viaIP = 0 | 	c.useMediator = false | ||||||
| 	c.up = false | 	c.up = false | ||||||
| 	c.route.Store(nil) | 	c.route.Store(nil) | ||||||
| 	return c | 	return c | ||||||
| @@ -66,8 +65,8 @@ func (c connNull) Name() string { | |||||||
| 	return "NoPeer" | 	return "NoPeer" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c connNull) HandleMediatorUpdate(ip byte) connState { | func (c connNull) HandleConnReq(w wrapper[ConnReq]) connState { | ||||||
| 	c.mediatorIP = ip | 	logState(c, "Ignoring conn request.") | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -102,10 +101,10 @@ func newStateServerDown(data *connData, peer *m.Peer) connState { | |||||||
| 	c.peer = peer | 	c.peer = peer | ||||||
| 	c.encSharedKey = computeSharedKey(peer.EncPubKey, c.encPrivKey) | 	c.encSharedKey = computeSharedKey(peer.EncPubKey, c.encPrivKey) | ||||||
| 	c.publicAddr = pubAddr | 	c.publicAddr = pubAddr | ||||||
| 	c.pingTimer.Reset(time.Millisecond) // Ping right away to bring up. | 	c.pingTimer.Reset(time.Second) // Ping right away to bring up. | ||||||
| 	c.timeoutTimer.Stop()          // No timeouts yet. | 	c.timeoutTimer.Stop()          // No timeouts yet. | ||||||
| 	c.addr = c.publicAddr | 	c.addr = c.publicAddr | ||||||
| 	c.viaIP = 0 | 	c.useMediator = false | ||||||
| 	c.up = false | 	c.up = false | ||||||
| 	c.route.Store(c.Route()) | 	c.route.Store(c.Route()) | ||||||
|  |  | ||||||
| @@ -116,9 +115,9 @@ func (c stateServerDown) Name() string { | |||||||
| 	return "Server:DOWN" | 	return "Server:DOWN" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateServerDown) HandleMediatorUpdate(ip byte) connState { | func (c stateServerDown) HandleConnReq(w wrapper[ConnReq]) connState { | ||||||
| 	// Server connection doesn't use a mediator. | 	// Send ConnResp. | ||||||
| 	c.mediatorIP = ip | 	// TODO | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -149,7 +148,7 @@ func newStateServerUp(data *connData, w wrapper[Pong]) connState { | |||||||
| 	c.pingTimer.Reset(pingInterval) | 	c.pingTimer.Reset(pingInterval) | ||||||
| 	c.timeoutTimer.Reset(timeoutInterval) | 	c.timeoutTimer.Reset(timeoutInterval) | ||||||
| 	c.addr = w.SrcAddr | 	c.addr = w.SrcAddr | ||||||
| 	c.viaIP = 0 | 	c.useMediator = false | ||||||
| 	c.up = true | 	c.up = true | ||||||
| 	c.route.Store(c.Route()) | 	c.route.Store(c.Route()) | ||||||
| 	return c | 	return c | ||||||
| @@ -159,12 +158,6 @@ func (c stateServerUp) Name() string { | |||||||
| 	return "Server:UP" | 	return "Server:UP" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateServerUp) HandleMediatorUpdate(ip byte) connState { |  | ||||||
| 	// Server connection doesn't use a mediator. |  | ||||||
| 	c.mediatorIP = ip |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateServerUp) HandlePing(w wrapper[Ping]) connState { | func (c stateServerUp) HandlePing(w wrapper[Ping]) connState { | ||||||
| 	logState(c, "Ignoring ping.") | 	logState(c, "Ignoring ping.") | ||||||
| 	return c | 	return c | ||||||
| @@ -176,7 +169,7 @@ func (c stateServerUp) HandlePong(w wrapper[Pong]) connState { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateServerUp) HandleTimeout() connState { | func (c stateServerUp) HandleTimeout() connState { | ||||||
| 	return newStateServerDown(c.connData, c.peer) | 	return newStateFromPeer(c.peer, c.connData) | ||||||
| } | } | ||||||
|  |  | ||||||
| //////////////////////// | //////////////////////// | ||||||
| @@ -197,7 +190,7 @@ func newStateClientDown(data *connData, peer *m.Peer) connState { | |||||||
| 	c.encPrivKey = data.encPrivKey | 	c.encPrivKey = data.encPrivKey | ||||||
| 	c.encSharedKey = computeSharedKey(peer.EncPubKey, c.encPrivKey) | 	c.encSharedKey = computeSharedKey(peer.EncPubKey, c.encPrivKey) | ||||||
| 	c.addr = c.publicAddr | 	c.addr = c.publicAddr | ||||||
| 	c.viaIP = 0 | 	c.useMediator = false | ||||||
| 	c.up = false | 	c.up = false | ||||||
| 	c.route.Store(c.Route()) | 	c.route.Store(c.Route()) | ||||||
|  |  | ||||||
| @@ -211,13 +204,8 @@ func (c stateClientDown) Name() string { | |||||||
| 	return "Client:DOWN" | 	return "Client:DOWN" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateClientDown) HandleMediatorUpdate(ip byte) connState { |  | ||||||
| 	// Client connection doesn't use a mediator. |  | ||||||
| 	c.mediatorIP = ip |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateClientDown) HandlePing(w wrapper[Ping]) connState { | func (c stateClientDown) HandlePing(w wrapper[Ping]) connState { | ||||||
|  | 	log.Printf("Got ping...") | ||||||
| 	next := newStateClientUp(c.connData, w) | 	next := newStateClientUp(c.connData, w) | ||||||
| 	c.sendPong(w) // Have to send after transitionsing so route is ok. | 	c.sendPong(w) // Have to send after transitionsing so route is ok. | ||||||
| 	return next | 	return next | ||||||
| @@ -244,7 +232,7 @@ type stateClientUp struct { | |||||||
| func newStateClientUp(data *connData, w wrapper[Ping]) connState { | func newStateClientUp(data *connData, w wrapper[Ping]) connState { | ||||||
| 	c := stateClientUp{data} | 	c := stateClientUp{data} | ||||||
| 	c.addr = w.SrcAddr | 	c.addr = w.SrcAddr | ||||||
| 	c.viaIP = 0 | 	c.useMediator = false | ||||||
| 	c.up = true | 	c.up = true | ||||||
| 	c.route.Store(c.Route()) | 	c.route.Store(c.Route()) | ||||||
|  |  | ||||||
| @@ -257,12 +245,6 @@ func (c stateClientUp) Name() string { | |||||||
| 	return "Client:UP" | 	return "Client:UP" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateClientUp) HandleMediatorUpdate(ip byte) connState { |  | ||||||
| 	// Client connection doesn't use a mediator. |  | ||||||
| 	c.mediatorIP = ip |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateClientUp) HandlePing(w wrapper[Ping]) connState { | func (c stateClientUp) HandlePing(w wrapper[Ping]) connState { | ||||||
| 	// The connection is from a client. If the client's address changes, we | 	// The connection is from a client. If the client's address changes, we | ||||||
| 	// should follow that change. | 	// should follow that change. | ||||||
| @@ -281,112 +263,51 @@ func (c stateClientUp) HandlePong(w wrapper[Pong]) connState { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateClientUp) HandleTimeout() connState { | func (c stateClientUp) HandleTimeout() connState { | ||||||
| 	return newStateClientDown(c.connData, c.peer) | 	return newStateFromPeer(c.peer, c.connData) | ||||||
| } | } | ||||||
|  |  | ||||||
| ////////////////////////// | ////////////// | ||||||
| // Unconnected Mediator // | // Mediated // | ||||||
| ////////////////////////// | ////////////// | ||||||
|  |  | ||||||
| type stateMediatedDown struct { | type stateMediated struct { | ||||||
| 	*connData | 	*connData | ||||||
| } | } | ||||||
|  |  | ||||||
| func newStateMediatedDown(data *connData, peer *m.Peer) connState { | func newStateMediated(data *connData, peer *m.Peer) connState { | ||||||
| 	addr, _ := netip.AddrFromSlice(peer.PublicIP) | 	addr, _ := netip.AddrFromSlice(peer.PublicIP) | ||||||
| 	pubAddr := netip.AddrPortFrom(addr, peer.Port) | 	pubAddr := netip.AddrPortFrom(addr, peer.Port) | ||||||
|  |  | ||||||
| 	c := stateMediatedDown{data} | 	c := stateMediated{data} | ||||||
| 	c.peer = peer | 	c.peer = peer | ||||||
| 	c.publicAddr = pubAddr | 	c.publicAddr = pubAddr | ||||||
| 	c.encPrivKey = data.encPrivKey | 	c.encPrivKey = data.encPrivKey | ||||||
| 	c.encSharedKey = computeSharedKey(peer.EncPubKey, c.encPrivKey) | 	c.encSharedKey = computeSharedKey(peer.EncPubKey, c.encPrivKey) | ||||||
| 	c.addr = c.publicAddr | 	c.addr = c.publicAddr | ||||||
| 	c.viaIP = 0 | 	c.useMediator = true | ||||||
| 	c.up = false | 	c.up = true | ||||||
| 	c.route.Store(c.Route()) | 	c.route.Store(c.Route()) | ||||||
|  |  | ||||||
| 	c.pingTimer.Stop()    // No pings for mediators. | 	c.pingTimer.Stop()    // No pings for mediators. | ||||||
| 	c.timeoutTimer.Stop() // No timeouts yet. | 	c.timeoutTimer.Stop() // No timeouts yet. | ||||||
|  |  | ||||||
| 	// If we have a mediator route, we can connect. |  | ||||||
| 	if mRoute := c.routes[c.mediatorIP].Load(); mRoute != nil { |  | ||||||
| 		return newStateMediatedUp(data, mRoute) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateMediatedDown) Name() string { | func (c stateMediated) Name() string { | ||||||
| 	return "Mediated:DOWN" | 	return "Mediated:UP" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateMediatedDown) HandleMediatorUpdate(ip byte) connState { | func (c stateMediated) HandlePing(w wrapper[Ping]) connState { | ||||||
| 	c.mediatorIP = ip |  | ||||||
| 	if mRoute := c.routes[c.mediatorIP].Load(); mRoute != nil { |  | ||||||
| 		return newStateMediatedUp(c.connData, mRoute) |  | ||||||
| 	} |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateMediatedDown) HandlePing(w wrapper[Ping]) connState { |  | ||||||
| 	logState(c, "Ignorning ping.") | 	logState(c, "Ignorning ping.") | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateMediatedDown) HandlePong(w wrapper[Pong]) connState { | func (c stateMediated) HandlePong(w wrapper[Pong]) connState { | ||||||
| 	logState(c, "Ignorning pong.") | 	logState(c, "Ignorning pong.") | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c stateMediatedDown) HandleTimeout() connState { | func (c stateMediated) HandleTimeout() connState { | ||||||
| 	logState(c, "Unexpected timeout.") | 	logState(c, "Unexpected timeout.") | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
| //////////////////////// |  | ||||||
| // Connected Mediator // |  | ||||||
| //////////////////////// |  | ||||||
|  |  | ||||||
| type stateMediatedUp struct { |  | ||||||
| 	*connData |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newStateMediatedUp(data *connData, route *route) connState { |  | ||||||
| 	c := stateMediatedUp{data} |  | ||||||
| 	c.addr = route.Addr |  | ||||||
| 	c.viaIP = route.PeerIP |  | ||||||
| 	c.up = true |  | ||||||
| 	c.route.Store(c.Route()) |  | ||||||
|  |  | ||||||
| 	// No pings for mediated routes. |  | ||||||
| 	c.pingTimer.Stop() |  | ||||||
| 	c.timeoutTimer.Stop() |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateMediatedUp) Name() string { |  | ||||||
| 	return "Mediated:UP" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateMediatedUp) HandleMediatorUpdate(ip byte) connState { |  | ||||||
| 	c.mediatorIP = ip |  | ||||||
| 	if mRoute := c.routes[c.mediatorIP].Load(); mRoute != nil { |  | ||||||
| 		return newStateMediatedUp(c.connData, mRoute) |  | ||||||
| 	} |  | ||||||
| 	return newStateMediatedDown(c.connData, c.peer) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateMediatedUp) HandlePing(w wrapper[Ping]) connState { |  | ||||||
| 	logState(c, "Ignoring ping.") |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateMediatedUp) HandlePong(w wrapper[Pong]) connState { |  | ||||||
| 	logState(c, "Ignoring pong.") |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c stateMediatedUp) HandleTimeout() connState { |  | ||||||
| 	return newStateMediatedDown(c.connData, c.peer) |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ package peer | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"golang.org/x/crypto/nacl/box" | 	"golang.org/x/crypto/nacl/box" | ||||||
| 	"golang.org/x/crypto/nacl/sign" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func encryptPacket(sharedKey, nonce, packet, out []byte) []byte { | func encryptPacket(sharedKey, nonce, packet, out []byte) []byte { | ||||||
| @@ -16,15 +15,6 @@ func decryptPacket(sharedKey, packet, out []byte) (decrypted []byte, ok bool) { | |||||||
| 	return decrypted, ok | 	return decrypted, ok | ||||||
| } | } | ||||||
|  |  | ||||||
| // Signed packet should be encrypted with the encryptPacket function first. |  | ||||||
| func signPacket(privKey, packet, out []byte) []byte { |  | ||||||
| 	return sign.Sign(out[:0], packet, (*[64]byte)(privKey)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func openPacket(pubKey, packet, out []byte) (encPacket []byte, ok bool) { |  | ||||||
| 	return sign.Open(out[:0], packet, (*[32]byte)(pubKey)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func computeSharedKey(peerPubKey, privKey []byte) []byte { | func computeSharedKey(peerPubKey, privKey []byte) []byte { | ||||||
| 	shared := [32]byte{} | 	shared := [32]byte{} | ||||||
| 	box.Precompute(&shared, (*[32]byte)(peerPubKey), (*[32]byte)(privKey)) | 	box.Precompute(&shared, (*[32]byte)(peerPubKey), (*[32]byte)(privKey)) | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"golang.org/x/crypto/nacl/box" | 	"golang.org/x/crypto/nacl/box" | ||||||
| 	"golang.org/x/crypto/nacl/sign" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestEncryptDecryptPacket(t *testing.T) { | func TestEncryptDecryptPacket(t *testing.T) { | ||||||
| @@ -105,60 +104,3 @@ func BenchmarkDecryptPacket(b *testing.B) { | |||||||
| 		decrypted, _ = decryptPacket(sharedDecKey[:], encrypted, decrypted) | 		decrypted, _ = decryptPacket(sharedDecKey[:], encrypted, decrypted) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func BenchmarkSignPacket(b *testing.B) { |  | ||||||
| 	_, privKey1, err := sign.GenerateKey(rand.Reader) |  | ||||||
| 	if err != nil { |  | ||||||
| 		b.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	original := make([]byte, 8192) |  | ||||||
| 	rand.Read(original) |  | ||||||
| 	out := make([]byte, 9000) |  | ||||||
|  |  | ||||||
| 	b.ResetTimer() |  | ||||||
| 	for i := 0; i < b.N; i++ { |  | ||||||
| 		signPacket(privKey1[:], original, out) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestSignOpenPacket(t *testing.T) { |  | ||||||
| 	pubKey, privKey, err := sign.GenerateKey(rand.Reader) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	packet := make([]byte, MTU) |  | ||||||
|  |  | ||||||
| 	rand.Read(packet) |  | ||||||
|  |  | ||||||
| 	signedPacket := signPacket(privKey[:], packet, make([]byte, BUFFER_SIZE)) |  | ||||||
|  |  | ||||||
| 	encPacket, ok := openPacket(pubKey[:], signedPacket, make([]byte, BUFFER_SIZE)) |  | ||||||
| 	if !ok { |  | ||||||
| 		t.Fatal(ok) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if !bytes.Equal(encPacket, packet) { |  | ||||||
| 		t.Fatal("not equal") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func BenchmarkOpenPacket(b *testing.B) { |  | ||||||
| 	pubKey, privKey, err := sign.GenerateKey(rand.Reader) |  | ||||||
| 	if err != nil { |  | ||||||
| 		b.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	packet := make([]byte, MTU) |  | ||||||
|  |  | ||||||
| 	rand.Read(packet) |  | ||||||
|  |  | ||||||
| 	signedPacket := signPacket(privKey[:], packet, make([]byte, 9000)) |  | ||||||
| 	out := make([]byte, BUFFER_SIZE) |  | ||||||
|  |  | ||||||
| 	b.ResetTimer() |  | ||||||
| 	for i := 0; i < b.N; i++ { |  | ||||||
| 		out, _ = openPacket(pubKey[:], signedPacket, out) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								peer/duplist.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								peer/duplist.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | package peer | ||||||
|  |  | ||||||
|  | type dupList struct { | ||||||
|  | 	items [64]uint64 | ||||||
|  | 	index int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *dupList) isDuplicate(in uint64) bool { | ||||||
|  | 	for _, i := range l.items { | ||||||
|  | 		if i == in { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	l.items[l.index] = in | ||||||
|  | 	l.index = (l.index + 1) % 64 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
| @@ -1,22 +1,14 @@ | |||||||
| package peer | package peer | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
|  | 	MAX_IP       = 65 | ||||||
| 	DEFAULT_PORT = 515 | 	DEFAULT_PORT = 515 | ||||||
| 	NONCE_SIZE   = 24 | 	NONCE_SIZE   = 24 | ||||||
| 	KEY_SIZE     = 32 | 	KEY_SIZE     = 32 | ||||||
| 	SIG_SIZE     = 64 | 	SIG_SIZE     = 64 | ||||||
| 	MTU          = 1376 | 	MTU          = 1436 | ||||||
| 	BUFFER_SIZE  = 2048 // Definitely big enough. | 	BUFFER_SIZE  = 1536 // Definitely big enough. | ||||||
|  |  | ||||||
| 	STREAM_DATA    = 0 | 	STREAM_DATA    = 0 | ||||||
| 	STREAM_ROUTING = 1 // Routing queries and responses. | 	STREAM_ROUTING = 1 // Routing queries and responses. | ||||||
|  |  | ||||||
| 	// Basic packet types |  | ||||||
| 	PACKET_TYPE_DATA = 0 |  | ||||||
| 	PACKET_TYPE_PING = 1 |  | ||||||
| 	PACKET_TYPE_PONG = 2 |  | ||||||
|  |  | ||||||
| 	// Packet sizes. |  | ||||||
| 	PING_SIZE = 8 |  | ||||||
| 	PONG_SIZE = 16 |  | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -14,10 +14,11 @@ func (peer *Peer) ifReader() { | |||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		sender  = newConnSender(peer.conn, peer.ip, STREAM_DATA, peer.signPrivKey) | 		sender   = newConnSender(peer.conn, peer.ip, STREAM_DATA) | ||||||
| 		n        int | 		n        int | ||||||
| 		destIP   byte | 		destIP   byte | ||||||
| 		router   = peer.router | 		router   = peer.router | ||||||
|  | 		viaRoute *route | ||||||
| 		route    *route | 		route    *route | ||||||
| 		iface    = peer.iface | 		iface    = peer.iface | ||||||
| 		err      error | 		err      error | ||||||
| @@ -54,6 +55,16 @@ func (peer *Peer) ifReader() { | |||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		sender.send(PACKET_TYPE_DATA, packet, route) | 		if route.useMediator { | ||||||
|  | 			viaRoute = router.GetMediator() | ||||||
|  | 			if viaRoute == nil || !viaRoute.Up { | ||||||
|  | 				log.Printf("Dropping packet due to no mediator: %d", destIP) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			viaRoute = nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		sender.send(PACKET_TYPE_DATA, packet, route, viaRoute) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ func (peer *Peer) netReader() { | |||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
|  | 		dupList   = &dupList{} | ||||||
| 		n         int | 		n         int | ||||||
| 		srcAddr   netip.AddrPort | 		srcAddr   netip.AddrPort | ||||||
| 		nonce     Nonce | 		nonce     Nonce | ||||||
| @@ -56,8 +57,9 @@ NEXT_PACKET: | |||||||
| 		goto NEXT_PACKET | 		goto NEXT_PACKET | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if nonce.Counter <= counters[nonce.StreamID][nonce.SourceIP] { | 	if dupList.isDuplicate(nonce.Counter) { | ||||||
| 		log.Printf("Dropping packet with bad counter: -%d", counters[nonce.StreamID][nonce.SourceIP]-nonce.Counter) | 		//if nonce.Counter+64 <= counters[nonce.StreamID][nonce.SourceIP] { | ||||||
|  | 		log.Printf("Dropping packet with bad counter: %d (-%d) - %v", nonce.Counter, counters[nonce.StreamID][nonce.SourceIP]-nonce.Counter, srcAddr) | ||||||
| 		goto NEXT_PACKET | 		goto NEXT_PACKET | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -67,26 +69,28 @@ NEXT_PACKET: | |||||||
| 		goto NEXT_PACKET | 		goto NEXT_PACKET | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	switch ip { |  | ||||||
| 	case nonce.DestIP: |  | ||||||
| 		goto DECRYPT |  | ||||||
| 	case nonce.ViaIP: |  | ||||||
| 		goto VALIDATE_SIGNATURE |  | ||||||
| 	default: |  | ||||||
| 		log.Printf("Bad packet: %+v", nonce) |  | ||||||
| 		goto NEXT_PACKET |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| DECRYPT: |  | ||||||
|  |  | ||||||
| 	decrypted, ok = decryptPacket(route.EncSharedKey, packet, decrypted) | 	decrypted, ok = decryptPacket(route.EncSharedKey, packet, decrypted) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		log.Printf("Failed to decrypt packet: %v", nonce) | 		log.Printf("Failed to decrypt packet: %v", nonce) | ||||||
| 		goto NEXT_PACKET | 		goto NEXT_PACKET | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Only updated after verification. | 	// Only updated after we've decrypted. | ||||||
|  | 	if nonce.Counter > counters[nonce.StreamID][nonce.SourceIP] { | ||||||
| 		counters[nonce.StreamID][nonce.SourceIP] = nonce.Counter | 		counters[nonce.StreamID][nonce.SourceIP] = nonce.Counter | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch ip { | ||||||
|  | 	case nonce.DestIP: | ||||||
|  | 		goto PROCESS_LOCAL | ||||||
|  | 	case nonce.ViaIP: | ||||||
|  | 		goto FORWARD | ||||||
|  | 	default: | ||||||
|  | 		log.Printf("Invalid nonce: %+v", nonce) | ||||||
|  | 		goto NEXT_PACKET | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | PROCESS_LOCAL: | ||||||
|  |  | ||||||
| 	switch nonce.StreamID { | 	switch nonce.StreamID { | ||||||
| 	case STREAM_DATA: | 	case STREAM_DATA: | ||||||
| @@ -112,16 +116,7 @@ WRITE_ROUTING_PACKET: | |||||||
|  |  | ||||||
| 	goto NEXT_PACKET | 	goto NEXT_PACKET | ||||||
|  |  | ||||||
| VALIDATE_SIGNATURE: | FORWARD: | ||||||
|  |  | ||||||
| 	decrypted, ok = openPacket(route.SignPubKey, packet, decrypted) |  | ||||||
| 	if !ok { |  | ||||||
| 		log.Printf("Failed to open signed packet: %v", nonce) |  | ||||||
| 		goto NEXT_PACKET |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Only updated after verification. |  | ||||||
| 	counters[nonce.StreamID][nonce.SourceIP] = nonce.Counter |  | ||||||
|  |  | ||||||
| 	route = peer.router.GetRoute(nonce.DestIP) | 	route = peer.router.GetRoute(nonce.DestIP) | ||||||
| 	if route == nil || !route.Up { | 	if route == nil || !route.Up { | ||||||
| @@ -130,7 +125,7 @@ VALIDATE_SIGNATURE: | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// We don't forward twice. | 	// We don't forward twice. | ||||||
| 	if route.ViaIP != 0 { | 	if route.useMediator { | ||||||
| 		log.Printf("Dropping double-forward packet: %v", nonce) | 		log.Printf("Dropping double-forward packet: %v", nonce) | ||||||
| 		goto NEXT_PACKET | 		goto NEXT_PACKET | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -15,8 +15,6 @@ type Peer struct { | |||||||
| 	isMediator bool | 	isMediator bool | ||||||
| 	encPubKey  []byte | 	encPubKey  []byte | ||||||
| 	encPrivKey []byte | 	encPrivKey []byte | ||||||
| 	signPubKey  []byte |  | ||||||
| 	signPrivKey []byte |  | ||||||
| 	conn       *net.UDPConn | 	conn       *net.UDPConn | ||||||
| 	iface      io.ReadWriteCloser | 	iface      io.ReadWriteCloser | ||||||
|  |  | ||||||
| @@ -36,8 +34,6 @@ func NewPeer(netName, listenIP string, port uint16) (*Peer, error) { | |||||||
| 		apiKey:     conf.APIKey, | 		apiKey:     conf.APIKey, | ||||||
| 		encPubKey:  conf.EncPubKey, | 		encPubKey:  conf.EncPubKey, | ||||||
| 		encPrivKey: conf.EncPrivKey, | 		encPrivKey: conf.EncPrivKey, | ||||||
| 		signPubKey:  conf.SignPubKey, |  | ||||||
| 		signPrivKey: conf.SignPrivKey, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_, peer.isServer = netip.AddrFromSlice(conf.PublicIP) | 	_, peer.isServer = netip.AddrFromSlice(conf.PublicIP) | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package peer | package peer | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"log" | ||||||
| 	"math/rand" | 	"math/rand" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| @@ -31,15 +32,11 @@ func (r *Router) manageMediator() { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if len(mediators) == 0 { | 		if len(mediators) == 0 { | ||||||
| 			ip = 0 | 			r.mediatorIP.Store(nil) | ||||||
| 		} else { | 		} else { | ||||||
| 			ip = mediators[rand.Intn(len(mediators))].PeerIP | 			ip = mediators[rand.Intn(len(mediators))].PeerIP | ||||||
| 		} | 			log.Printf("Got mediator IP: %d", ip) | ||||||
|  | 			r.mediatorIP.Store(&ip) | ||||||
| 		for _, conn := range r.conns { |  | ||||||
| 			if conn != nil { |  | ||||||
| 				conn.UpdateMediator(ip) |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -55,9 +55,9 @@ func (r *Router) _pollHub(client *http.Client, req *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for i, peer := range state.Peers { | 	for i := range r.conns { | ||||||
| 		if r.conns[i] != nil { | 		if r.conns[i] != nil { | ||||||
| 			r.conns[i].UpdatePeer(peerUpdate{PeerIP: byte(i), Peer: peer}) | 			r.conns[i].UpdatePeer(peerUpdate{PeerIP: byte(i), Peer: state.Peers[i]}) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ package peer | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"net/netip" | 	"net/netip" | ||||||
| 	"unsafe" |  | ||||||
| 	"vppn/m" | 	"vppn/m" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -15,10 +14,9 @@ type route struct { | |||||||
| 	PeerIP       byte | 	PeerIP       byte | ||||||
| 	Up           bool | 	Up           bool | ||||||
| 	Mediator     bool | 	Mediator     bool | ||||||
| 	SignPubKey   []byte |  | ||||||
| 	EncSharedKey []byte // Shared key for encoding / decoding packets. | 	EncSharedKey []byte // Shared key for encoding / decoding packets. | ||||||
| 	Addr         netip.AddrPort // Address to send to. | 	Addr         netip.AddrPort | ||||||
| 	ViaIP        byte           // If != 0, this is a forwarding address. | 	useMediator  bool | ||||||
| } | } | ||||||
|  |  | ||||||
| type peerUpdate struct { | type peerUpdate struct { | ||||||
| @@ -41,34 +39,3 @@ func newWrapper[T any](srcAddr netip.AddrPort, nonce Nonce) wrapper[T] { | |||||||
| 		Nonce:   nonce, | 		Nonce:   nonce, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // ---------------------------------------------------------------------------- |  | ||||||
|  |  | ||||||
| type Ping struct { |  | ||||||
| 	SentAt int64 // unix milli |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *Ping) Parse(buf []byte) { |  | ||||||
| 	p.SentAt = *(*int64)(unsafe.Pointer(&buf[0])) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p Ping) Marshal(buf []byte) { |  | ||||||
| 	*(*int64)(unsafe.Pointer(&buf[0])) = p.SentAt |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ---------------------------------------------------------------------------- |  | ||||||
|  |  | ||||||
| type Pong struct { |  | ||||||
| 	SentAt  int64 // unix mili |  | ||||||
| 	RecvdAt int64 // unix mili |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *Pong) Parse(buf []byte) { |  | ||||||
| 	p.SentAt = *(*int64)(unsafe.Pointer(&buf[0])) |  | ||||||
| 	p.RecvdAt = *(*int64)(unsafe.Pointer(&buf[8])) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *Pong) Marshal(buf []byte) { |  | ||||||
| 	*(*int64)(unsafe.Pointer(&buf[0])) = p.SentAt |  | ||||||
| 	*(*int64)(unsafe.Pointer(&buf[8])) = p.RecvdAt |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -12,12 +12,17 @@ type Router struct { | |||||||
| 	conf m.PeerConfig | 	conf m.PeerConfig | ||||||
|  |  | ||||||
| 	// Routes used by the peer. | 	// Routes used by the peer. | ||||||
| 	conns  [256]*connHandler | 	conns      [MAX_IP]*connHandler | ||||||
| 	routes [256]*atomic.Pointer[route] | 	routes     [MAX_IP]*atomic.Pointer[route] | ||||||
|  | 	addrs      [MAX_IP]*atomic.Pointer[netip.AddrPort] | ||||||
|  | 	mediatorIP *atomic.Pointer[byte] | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewRouter(conf m.PeerConfig, conn *net.UDPConn) *Router { | func NewRouter(conf m.PeerConfig, conn *net.UDPConn) *Router { | ||||||
| 	r := &Router{conf: conf} | 	r := &Router{ | ||||||
|  | 		conf:       conf, | ||||||
|  | 		mediatorIP: &atomic.Pointer[byte]{}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	for i := range r.routes { | 	for i := range r.routes { | ||||||
| 		r.routes[i] = &atomic.Pointer[route]{} | 		r.routes[i] = &atomic.Pointer[route]{} | ||||||
| @@ -25,7 +30,7 @@ func NewRouter(conf m.PeerConfig, conn *net.UDPConn) *Router { | |||||||
|  |  | ||||||
| 	_, isServer := netip.AddrFromSlice(conf.PublicIP) | 	_, isServer := netip.AddrFromSlice(conf.PublicIP) | ||||||
|  |  | ||||||
| 	sender := newConnSender(conn, conf.PeerIP, STREAM_ROUTING, conf.SignPrivKey) | 	sender := newConnSender(conn, conf.PeerIP, STREAM_ROUTING) | ||||||
|  |  | ||||||
| 	for i := range r.conns { | 	for i := range r.conns { | ||||||
| 		if byte(i) != conf.PeerIP { | 		if byte(i) != conf.PeerIP { | ||||||
| @@ -54,6 +59,13 @@ func (rm *Router) GetRoute(ip byte) *route { | |||||||
| 	return rm.routes[ip].Load() | 	return rm.routes[ip].Load() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (rm *Router) GetMediator() *route { | ||||||
|  | 	if ip := rm.mediatorIP.Load(); ip != nil { | ||||||
|  | 		return rm.GetRoute(*ip) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func (r *Router) HandlePacket(src netip.AddrPort, nonce Nonce, data []byte) { | func (r *Router) HandlePacket(src netip.AddrPort, nonce Nonce, data []byte) { | ||||||
| 	if nonce.SourceIP == r.conf.PeerIP { | 	if nonce.SourceIP == r.conf.PeerIP { | ||||||
| 		log.Printf("Packet to self...") | 		log.Printf("Packet to self...") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user