Basic relay working!

This commit is contained in:
Owen 2025-02-23 16:49:24 -05:00
parent f6429b6eee
commit b68502de9e
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
4 changed files with 44 additions and 72 deletions

3
.gitignore vendored
View file

@ -1,3 +1,4 @@
newt
.DS_Store
bin/
bin/
nohup.out

14
main.go
View file

@ -258,7 +258,6 @@ func main() {
logLevel string
interfaceName string
generateAndSaveKeyTo string
reachableAt string
)
// if PANGOLIN_ENDPOINT, NEWT_ID, and NEWT_SECRET are set as environment variables, they will be used as default values
@ -270,7 +269,6 @@ func main() {
logLevel = os.Getenv("LOG_LEVEL")
interfaceName = os.Getenv("INTERFACE")
generateAndSaveKeyTo = os.Getenv("GENERATE_AND_SAVE_KEY_TO")
reachableAt = os.Getenv("REACHABLE_AT")
if endpoint == "" {
flag.StringVar(&endpoint, "endpoint", "", "Endpoint of your pangolin server")
@ -296,9 +294,6 @@ func main() {
if generateAndSaveKeyTo == "" {
flag.StringVar(&generateAndSaveKeyTo, "generateAndSaveKeyTo", "", "Path to save generated private key")
}
if reachableAt == "" {
flag.StringVar(&reachableAt, "reachableAt", "", "Endpoint of the http server to tell remote config about")
}
// do a --version check
version := flag.Bool("version", false, "Print the version")
@ -353,7 +348,7 @@ func main() {
}
// Create WireGuard service
wgService, err = wg.NewWireGuardService(interfaceName, mtuInt, reachableAt, generateAndSaveKeyTo, host, id, client)
wgService, err = wg.NewWireGuardService(interfaceName, mtuInt, generateAndSaveKeyTo, host, id, client)
if err != nil {
logger.Fatal("Failed to create WireGuard service: %v", err)
}
@ -469,6 +464,13 @@ persistent_keepalive_interval=5`, fixKey(fmt.Sprintf("%s", privateKey)), fixKey(
updateTargets(pm, "add", wgData.TunnelIP, "udp", TargetData{Targets: wgData.Targets.UDP})
}
// first make sure the wpgService has a port
if wgService != nil {
// add a udp proxy for localost and the wgService port
// TODO: make sure this port is not used in a target
pm.AddTarget("udp", wgData.TunnelIP, int(wgService.Port), fmt.Sprintf("localhost:%d", wgService.Port))
}
err = pm.Start()
if err != nil {
logger.Error("Failed to start proxy manager: %v", err)

View file

@ -1,25 +0,0 @@
INFO: 2025/02/22 23:25:47 Requesting WireGuard configuration from remote server
INFO: 2025/02/22 23:25:47 Sent registration message
INFO: 2025/02/22 23:25:47 Received message: {newt/wg/receive-config map[ipAddress:100.90.128.1/24 listenPort:51822 peers:[]]}
INFO: 2025/02/22 23:25:47 Created WireGuard interface wg1
INFO: 2025/02/22 23:25:47 Assigning IP address 100.90.128.1/24 to interface wg1
INFO: 2025/02/22 23:25:47 WireGuard interface wg1 created and configured
INFO: 2025/02/22 23:25:47 Received registration message
INFO: 2025/02/22 23:25:47 Received: {Type:newt/wg/connect Data:map[endpoint:pangolin.fosrl.io:51820 publicKey:tng9Z/BN32flFjqwwT1yAxN/twFkmgbZA+D9N+YqdjM= serverIP:100.89.128.1 targets:map[tcp:[] udp:[]] tunnelIP:100.89.128.4]}
INFO: 2025/02/22 23:25:47 WireGuard device created. Lets ping the server now...
INFO: 2025/02/22 23:25:47 Ping attempt 1 of 5
INFO: 2025/02/22 23:25:47 Pinging 100.89.128.1
INFO: 2025/02/22 23:25:47 Ping latency: 9.00105ms
INFO: 2025/02/22 23:25:47 Starting ping check
INFO: 2025/02/22 23:26:48 Peer P9pacnRfUSfvDibaQTdTk59q27eRpgtbMMmMpkNwKl0= removed successfully
INFO: 2025/02/22 23:26:48 Peer NMrcorGgTTi4tAUZ1lLru0qISNrt9D9JdsFGyDYlcSQ= added successfully
INFO: 2025/02/22 23:28:58 Peer NMrcorGgTTi4tAUZ1lLru0qISNrt9D9JdsFGyDYlcSQ= removed successfully
INFO: 2025/02/22 23:28:58 Peer n8ZKTG8vsROL/OiqHYJELU/Rg9XDifz0YjE/lQsL0m0= added successfully
INFO: 2025/02/22 23:33:59 Peer n8ZKTG8vsROL/OiqHYJELU/Rg9XDifz0YjE/lQsL0m0= removed successfully
INFO: 2025/02/22 23:33:59 Peer /i8YTgrLkZh08HKXLXqNFQJsyg1E8I2ELXqF0zuP9D8= added successfully
INFO: 2025/02/22 23:34:06 Peer /i8YTgrLkZh08HKXLXqNFQJsyg1E8I2ELXqF0zuP9D8= removed successfully
INFO: 2025/02/22 23:34:06 Peer 50+RB00sDoSG+KAKzl/baaqPkKGOe7upX7uqRCKqsRo= added successfully
INFO: 2025/02/22 23:35:07 Peer 50+RB00sDoSG+KAKzl/baaqPkKGOe7upX7uqRCKqsRo= removed successfully
INFO: 2025/02/22 23:35:07 Peer Aa2Y2NEmc+SITlT89+fsOeqDkXJVu9RBY14+77TXa3w= added successfully
INFO: 2025/02/23 00:55:55 Peer Aa2Y2NEmc+SITlT89+fsOeqDkXJVu9RBY14+77TXa3w= removed successfully
INFO: 2025/02/23 00:55:55 Peer 2AXNjMQzT7GGvdbIG6MJVFpO3FIzQ+qCqZkdSnBA3DE= added successfully

View file

@ -51,12 +51,12 @@ type WireGuardService struct {
wgClient *wgctrl.Client
config WgConfig
key wgtypes.Key
reachableAt string
newtId string
lastReadings map[string]PeerReading
mu sync.Mutex
port uint16
Port uint16
stopHolepunch chan struct{}
host string
}
// Add this type definition
@ -113,7 +113,7 @@ func FindAvailableUDPPort(minPort, maxPort uint16) (uint16, error) {
return 0, fmt.Errorf("no available UDP ports found in range %d-%d", minPort, maxPort)
}
func NewWireGuardService(interfaceName string, mtu int, reachableAt string, generateAndSaveKeyTo string, host string, newtId string, wsClient *websocket.Client) (*WireGuardService, error) {
func NewWireGuardService(interfaceName string, mtu int, generateAndSaveKeyTo string, host string, newtId string, wsClient *websocket.Client) (*WireGuardService, error) {
wgClient, err := wgctrl.New()
if err != nil {
return nil, fmt.Errorf("failed to create WireGuard client: %v", err)
@ -155,20 +155,13 @@ func NewWireGuardService(interfaceName string, mtu int, reachableAt string, gene
client: wsClient,
wgClient: wgClient,
key: key,
reachableAt: reachableAt,
newtId: newtId,
lastReadings: make(map[string]PeerReading),
port: port,
Port: port,
stopHolepunch: make(chan struct{}),
host: host,
}
if err := service.sendUDPHolePunch(host + ":21820"); err != nil {
logger.Error("Failed to send UDP hole punch: %v", err)
}
// start the UDP holepunch
go service.keepSendingUDPHolePunch(host)
// Register websocket handlers
wsClient.RegisterHandler("newt/wg/receive-config", service.handleConfig)
wsClient.RegisterHandler("newt/wg/peer/add", service.handleAddPeer)
@ -185,7 +178,6 @@ func (s *WireGuardService) LoadRemoteConfig() error {
err := s.client.SendMessage("newt/wg/get-config", map[string]interface{}{
"publicKey": fmt.Sprintf("%s", s.key.PublicKey().String()),
"endpoint": s.reachableAt,
})
if err != nil {
logger.Error("Failed to send registration message: %v", err)
@ -216,9 +208,6 @@ func (s *WireGuardService) handleConfig(msg websocket.WSMessage) {
}
s.config = config
// stop the holepunch
// close(s.stopHolepunch)
// Ensure the WireGuard interface and peers are configured
if err := s.ensureWireguardInterface(config); err != nil {
logger.Error("Failed to ensure WireGuard interface: %v", err)
@ -227,6 +216,13 @@ func (s *WireGuardService) handleConfig(msg websocket.WSMessage) {
if err := s.ensureWireguardPeers(config.Peers); err != nil {
logger.Error("Failed to ensure WireGuard peers: %v", err)
}
if err := s.sendUDPHolePunch(s.host + ":21820"); err != nil {
logger.Error("Failed to send UDP hole punch: %v", err)
}
// start the UDP holepunch
go s.keepSendingUDPHolePunch(s.host)
}
func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
@ -245,6 +241,17 @@ func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
}
} else {
logger.Info("WireGuard interface %s already exists\n", s.interfaceName)
// get the exising wireguard port
device, err := s.wgClient.Device(s.interfaceName)
if err != nil {
return fmt.Errorf("failed to get device: %v", err)
}
// get the existing port
s.Port = uint16(device.ListenPort)
logger.Info("WireGuard interface %s already exists with port %d\n", s.interfaceName, s.Port)
return nil
}
@ -273,7 +280,7 @@ func (s *WireGuardService) ensureWireguardInterface(wgconfig WgConfig) error {
}
// Use the service's fixed port instead of the config port
*config.ListenPort = int(s.port)
*config.ListenPort = int(s.Port)
// Create and configure the WireGuard interface
err = s.wgClient.ConfigureDevice(s.interfaceName, config)
@ -390,6 +397,7 @@ func (s *WireGuardService) handleAddPeer(msg websocket.WSMessage) {
err = s.addPeer(peer)
if err != nil {
logger.Info("Error adding peer: %v", err)
return
}
}
@ -411,16 +419,18 @@ func (s *WireGuardService) addPeer(peer Peer) error {
}
// add keep alive using *time.Duration of 1 second
keepalive := time.Second
endpoint, err := net.ResolveUDPAddr("udp", peer.Endpoint)
if err != nil {
return fmt.Errorf("failed to resolve endpoint address: %w", err)
}
// endpoint, err := net.ResolveUDPAddr("udp", peer.Endpoint)
// if err != nil {
// return fmt.Errorf("failed to resolve endpoint address: %w", err)
// }
// make the endpoint localhost to test
peerConfig := wgtypes.PeerConfig{
PublicKey: pubKey,
AllowedIPs: allowedIPs,
PersistentKeepaliveInterval: &keepalive,
Endpoint: endpoint,
// Endpoint: endpoint,
}
config := wgtypes.Config{
@ -626,7 +636,7 @@ func (s *WireGuardService) sendUDPHolePunch(serverAddr string) error {
client := &network.PeerNet{
IP: clientIP,
Port: s.port,
Port: s.Port,
NewtID: s.newtId,
}
@ -647,27 +657,11 @@ func (s *WireGuardService) sendUDPHolePunch(serverAddr string) error {
return fmt.Errorf("failed to send UDP packet: %v", err)
}
// logger.Info("Sent UDP hole punch to %s", serverAddr)
// // Wait for response if needed
// response, err := network.RecvDataPacket(rawConn, server, client)
// if err != nil {
// if err, ok := err.(net.Error); ok && err.Timeout() {
// return fmt.Errorf("connection to %s timed out", serverAddr)
// }
// return fmt.Errorf("error receiving response: %v", err)
// }
// // Process response if needed
// if len(response) > 0 {
// logger.Info("Received response from server")
// }
return nil
}
func (s *WireGuardService) keepSendingUDPHolePunch(host string) {
ticker := time.NewTicker(1 * time.Second)
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
for {