mirror of
https://github.com/fosrl/newt.git
synced 2026-03-27 13:06:38 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
595278d455 |
@@ -35,7 +35,7 @@ When Newt receives WireGuard control messages, it will use the information encod
|
|||||||
- `endpoint`: The endpoint where both Gerbil and Pangolin reside in order to connect to the websocket.
|
- `endpoint`: The endpoint where both Gerbil and Pangolin reside in order to connect to the websocket.
|
||||||
|
|
||||||
- `mtu` (optional): MTU for the internal WG interface. Default: 1280
|
- `mtu` (optional): MTU for the internal WG interface. Default: 1280
|
||||||
- `dns` (optional): DNS server to use to resolve the endpoint. Default: 9.9.9.9
|
- `dns` (optional): DNS server to use to resolve the endpoint. Default: 8.8.8.8
|
||||||
- `log-level` (optional): The log level to use (DEBUG, INFO, WARN, ERROR, FATAL). Default: INFO
|
- `log-level` (optional): The log level to use (DEBUG, INFO, WARN, ERROR, FATAL). Default: INFO
|
||||||
- `enforce-hc-cert` (optional): Enforce certificate validation for health checks. Default: false (accepts any cert)
|
- `enforce-hc-cert` (optional): Enforce certificate validation for health checks. Default: false (accepts any cert)
|
||||||
- `docker-socket` (optional): Set the Docker socket to use the container discovery integration
|
- `docker-socket` (optional): Set the Docker socket to use the container discovery integration
|
||||||
@@ -62,7 +62,7 @@ All CLI arguments can be set using environment variables as an alternative to co
|
|||||||
- `NEWT_ID`: Newt ID generated by Pangolin (equivalent to `--id`)
|
- `NEWT_ID`: Newt ID generated by Pangolin (equivalent to `--id`)
|
||||||
- `NEWT_SECRET`: Newt secret for authentication (equivalent to `--secret`)
|
- `NEWT_SECRET`: Newt secret for authentication (equivalent to `--secret`)
|
||||||
- `MTU`: MTU for the internal WG interface. Default: 1280 (equivalent to `--mtu`)
|
- `MTU`: MTU for the internal WG interface. Default: 1280 (equivalent to `--mtu`)
|
||||||
- `DNS`: DNS server to use to resolve the endpoint. Default: 9.9.9.9 (equivalent to `--dns`)
|
- `DNS`: DNS server to use to resolve the endpoint. Default: 8.8.8.8 (equivalent to `--dns`)
|
||||||
- `LOG_LEVEL`: Log level (DEBUG, INFO, WARN, ERROR, FATAL). Default: INFO (equivalent to `--log-level`)
|
- `LOG_LEVEL`: Log level (DEBUG, INFO, WARN, ERROR, FATAL). Default: INFO (equivalent to `--log-level`)
|
||||||
- `DOCKER_SOCKET`: Path to Docker socket for container discovery (equivalent to `--docker-socket`)
|
- `DOCKER_SOCKET`: Path to Docker socket for container discovery (equivalent to `--docker-socket`)
|
||||||
- `PING_INTERVAL`: Interval for pinging the server. Default: 3s (equivalent to `--ping-interval`)
|
- `PING_INTERVAL`: Interval for pinging the server. Default: 3s (equivalent to `--ping-interval`)
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
resources:
|
|
||||||
resource-nice-id:
|
|
||||||
name: this is my resource
|
|
||||||
protocol: http
|
|
||||||
full-domain: level1.test3.example.com
|
|
||||||
host-header: example.com
|
|
||||||
tls-server-name: example.com
|
|
||||||
auth:
|
|
||||||
pincode: 123456
|
|
||||||
password: sadfasdfadsf
|
|
||||||
sso-enabled: true
|
|
||||||
sso-roles:
|
|
||||||
- Member
|
|
||||||
sso-users:
|
|
||||||
- owen@fossorial.io
|
|
||||||
whitelist-users:
|
|
||||||
- owen@fossorial.io
|
|
||||||
targets:
|
|
||||||
# - site: glossy-plains-viscacha-rat
|
|
||||||
- hostname: localhost
|
|
||||||
method: http
|
|
||||||
port: 8000
|
|
||||||
healthcheck:
|
|
||||||
port: 8000
|
|
||||||
hostname: localhost
|
|
||||||
# - site: glossy-plains-viscacha-rat
|
|
||||||
- hostname: localhost
|
|
||||||
method: http
|
|
||||||
port: 8001
|
|
||||||
resource-nice-id2:
|
|
||||||
name: this is other resource
|
|
||||||
protocol: tcp
|
|
||||||
proxy-port: 3000
|
|
||||||
targets:
|
|
||||||
# - site: glossy-plains-viscacha-rat
|
|
||||||
- hostname: localhost
|
|
||||||
port: 3000
|
|
||||||
@@ -39,7 +39,7 @@ func setupClients(client *websocket.Client) {
|
|||||||
func setupClientsNetstack(client *websocket.Client, host string) {
|
func setupClientsNetstack(client *websocket.Client, host string) {
|
||||||
logger.Info("Setting up clients with netstack...")
|
logger.Info("Setting up clients with netstack...")
|
||||||
// Create WireGuard service
|
// Create WireGuard service
|
||||||
wgService, err = wgnetstack.NewWireGuardService(interfaceName, mtuInt, generateAndSaveKeyTo, host, id, client, "9.9.9.9")
|
wgService, err = wgnetstack.NewWireGuardService(interfaceName, mtuInt, generateAndSaveKeyTo, host, id, client, "8.8.8.8")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal("Failed to create WireGuard service: %v", err)
|
logger.Fatal("Failed to create WireGuard service: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,11 +73,8 @@ func parseDockerHost(raw string) (dockerHost, error) {
|
|||||||
s = strings.TrimPrefix(s, "http://")
|
s = strings.TrimPrefix(s, "http://")
|
||||||
s = strings.TrimPrefix(s, "https://")
|
s = strings.TrimPrefix(s, "https://")
|
||||||
return dockerHost{"tcp", s}, nil
|
return dockerHost{"tcp", s}, nil
|
||||||
case strings.HasPrefix(raw, "/"):
|
|
||||||
// Absolute path without scheme - treat as unix socket
|
|
||||||
return dockerHost{"unix", raw}, nil
|
|
||||||
default:
|
default:
|
||||||
// For relative paths or other formats, also default to unix
|
// default fallback to unix
|
||||||
return dockerHost{"unix", raw}, nil
|
return dockerHost{"unix", raw}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,13 +85,6 @@ func CheckSocket(socketPath string) bool {
|
|||||||
if socketPath == "" {
|
if socketPath == "" {
|
||||||
socketPath = "unix:///var/run/docker.sock"
|
socketPath = "unix:///var/run/docker.sock"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the socket path is properly formatted
|
|
||||||
if !strings.Contains(socketPath, "://") {
|
|
||||||
// If no scheme provided, assume unix socket
|
|
||||||
socketPath = "unix://" + socketPath
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err := parseDockerHost(socketPath)
|
host, err := parseDockerHost(socketPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debug("Invalid Docker socket path '%s': %v", socketPath, err)
|
logger.Debug("Invalid Docker socket path '%s': %v", socketPath, err)
|
||||||
@@ -159,13 +149,7 @@ func IsWithinHostNetwork(socketPath string, targetAddress string, targetPort int
|
|||||||
func ListContainers(socketPath string, enforceNetworkValidation bool) ([]Container, error) {
|
func ListContainers(socketPath string, enforceNetworkValidation bool) ([]Container, error) {
|
||||||
// Use the provided socket path or default to standard location
|
// Use the provided socket path or default to standard location
|
||||||
if socketPath == "" {
|
if socketPath == "" {
|
||||||
socketPath = "unix:///var/run/docker.sock"
|
socketPath = "/var/run/docker.sock"
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the socket path is properly formatted for the Docker client
|
|
||||||
if !strings.Contains(socketPath, "://") {
|
|
||||||
// If no scheme provided, assume unix socket
|
|
||||||
socketPath = "unix://" + socketPath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to filter down containers returned to Pangolin
|
// Used to filter down containers returned to Pangolin
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -51,5 +51,4 @@ require (
|
|||||||
golang.org/x/sys v0.35.0 // indirect
|
golang.org/x/sys v0.35.0 // indirect
|
||||||
golang.org/x/time v0.12.0 // indirect
|
golang.org/x/time v0.12.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
1
go.sum
1
go.sum
@@ -161,7 +161,6 @@ google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
|||||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ type Monitor struct {
|
|||||||
|
|
||||||
// NewMonitor creates a new health check monitor
|
// NewMonitor creates a new health check monitor
|
||||||
func NewMonitor(callback StatusChangeCallback, enforceCert bool) *Monitor {
|
func NewMonitor(callback StatusChangeCallback, enforceCert bool) *Monitor {
|
||||||
logger.Debug("Creating new health check monitor with certificate enforcement: %t", enforceCert)
|
logger.Info("Creating new health check monitor with certificate enforcement: %t", enforceCert)
|
||||||
|
|
||||||
// Configure TLS settings based on certificate enforcement
|
// Configure TLS settings based on certificate enforcement
|
||||||
transport := &http.Transport{
|
transport := &http.Transport{
|
||||||
|
|||||||
51
main.go
51
main.go
@@ -74,11 +74,6 @@ type ExitNodePingResult struct {
|
|||||||
WasPreviouslyConnected bool `json:"wasPreviouslyConnected"`
|
WasPreviouslyConnected bool `json:"wasPreviouslyConnected"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlueprintResult struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Message string `json:"message,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom flag type for multiple CA files
|
// Custom flag type for multiple CA files
|
||||||
type stringSlice []string
|
type stringSlice []string
|
||||||
|
|
||||||
@@ -120,7 +115,6 @@ var (
|
|||||||
preferEndpoint string
|
preferEndpoint string
|
||||||
healthMonitor *healthcheck.Monitor
|
healthMonitor *healthcheck.Monitor
|
||||||
enforceHealthcheckCert bool
|
enforceHealthcheckCert bool
|
||||||
blueprintFile string
|
|
||||||
|
|
||||||
// New mTLS configuration variables
|
// New mTLS configuration variables
|
||||||
tlsClientCert string
|
tlsClientCert string
|
||||||
@@ -178,7 +172,6 @@ func main() {
|
|||||||
if tlsPrivateKey == "" {
|
if tlsPrivateKey == "" {
|
||||||
tlsPrivateKey = os.Getenv("TLS_CLIENT_CERT")
|
tlsPrivateKey = os.Getenv("TLS_CLIENT_CERT")
|
||||||
}
|
}
|
||||||
blueprintFile = os.Getenv("BLUEPRINT_FILE")
|
|
||||||
|
|
||||||
if endpoint == "" {
|
if endpoint == "" {
|
||||||
flag.StringVar(&endpoint, "endpoint", "", "Endpoint of your pangolin server")
|
flag.StringVar(&endpoint, "endpoint", "", "Endpoint of your pangolin server")
|
||||||
@@ -193,7 +186,7 @@ func main() {
|
|||||||
flag.StringVar(&mtu, "mtu", "1280", "MTU to use")
|
flag.StringVar(&mtu, "mtu", "1280", "MTU to use")
|
||||||
}
|
}
|
||||||
if dns == "" {
|
if dns == "" {
|
||||||
flag.StringVar(&dns, "dns", "9.9.9.9", "DNS server to use")
|
flag.StringVar(&dns, "dns", "8.8.8.8", "DNS server to use")
|
||||||
}
|
}
|
||||||
if logLevel == "" {
|
if logLevel == "" {
|
||||||
flag.StringVar(&logLevel, "log-level", "INFO", "Log level (DEBUG, INFO, WARN, ERROR, FATAL)")
|
flag.StringVar(&logLevel, "log-level", "INFO", "Log level (DEBUG, INFO, WARN, ERROR, FATAL)")
|
||||||
@@ -278,9 +271,6 @@ func main() {
|
|||||||
if healthFile == "" {
|
if healthFile == "" {
|
||||||
flag.StringVar(&healthFile, "health-file", "", "Path to health file (if unset, health file won't be written)")
|
flag.StringVar(&healthFile, "health-file", "", "Path to health file (if unset, health file won't be written)")
|
||||||
}
|
}
|
||||||
if blueprintFile == "" {
|
|
||||||
flag.StringVar(&blueprintFile, "blueprint-file", "", "Path to blueprint file (if unset, no blueprint will be applied)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// do a --version check
|
// do a --version check
|
||||||
version := flag.Bool("version", false, "Print the version")
|
version := flag.Bool("version", false, "Print the version")
|
||||||
@@ -478,7 +468,7 @@ func main() {
|
|||||||
|
|
||||||
// Register handlers for different message types
|
// Register handlers for different message types
|
||||||
client.RegisterHandler("newt/wg/connect", func(msg websocket.WSMessage) {
|
client.RegisterHandler("newt/wg/connect", func(msg websocket.WSMessage) {
|
||||||
logger.Debug("Received registration message")
|
logger.Info("Received registration message")
|
||||||
if stopFunc != nil {
|
if stopFunc != nil {
|
||||||
stopFunc() // stop the ws from sending more requests
|
stopFunc() // stop the ws from sending more requests
|
||||||
stopFunc = nil // reset stopFunc to nil to avoid double stopping
|
stopFunc = nil // reset stopFunc to nil to avoid double stopping
|
||||||
@@ -571,7 +561,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn("Initial reliable ping failed, but continuing: %v", err)
|
logger.Warn("Initial reliable ping failed, but continuing: %v", err)
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("Initial connection test successful")
|
logger.Info("Initial connection test successful")
|
||||||
}
|
}
|
||||||
|
|
||||||
pingWithRetryStopChan, _ = pingWithRetry(tnet, wgData.ServerIP, pingTimeout)
|
pingWithRetryStopChan, _ = pingWithRetry(tnet, wgData.ServerIP, pingTimeout)
|
||||||
@@ -610,7 +600,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
if err := healthMonitor.AddTargets(wgData.HealthCheckTargets); err != nil {
|
if err := healthMonitor.AddTargets(wgData.HealthCheckTargets); err != nil {
|
||||||
logger.Error("Failed to bulk add health check targets: %v", err)
|
logger.Error("Failed to bulk add health check targets: %v", err)
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("Successfully added %d health check targets", len(wgData.HealthCheckTargets))
|
logger.Info("Successfully added %d health check targets", len(wgData.HealthCheckTargets))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pm.Start()
|
err = pm.Start()
|
||||||
@@ -657,7 +647,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
})
|
})
|
||||||
|
|
||||||
client.RegisterHandler("newt/ping/exitNodes", func(msg websocket.WSMessage) {
|
client.RegisterHandler("newt/ping/exitNodes", func(msg websocket.WSMessage) {
|
||||||
logger.Debug("Received ping message")
|
logger.Info("Received ping message")
|
||||||
if stopFunc != nil {
|
if stopFunc != nil {
|
||||||
stopFunc() // stop the ws from sending more requests
|
stopFunc() // stop the ws from sending more requests
|
||||||
stopFunc = nil // reset stopFunc to nil to avoid double stopping
|
stopFunc = nil // reset stopFunc to nil to avoid double stopping
|
||||||
@@ -979,7 +969,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to send Docker container list: %v", err)
|
logger.Error("Failed to send Docker container list: %v", err)
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("Docker container list sent, count: %d", len(containers))
|
logger.Info("Docker container list sent, count: %d", len(containers))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1095,7 +1085,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
if err := healthMonitor.AddTargets(config.Targets); err != nil {
|
if err := healthMonitor.AddTargets(config.Targets); err != nil {
|
||||||
logger.Error("Failed to add health check targets: %v", err)
|
logger.Error("Failed to add health check targets: %v", err)
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("Added %d health check targets", len(config.Targets))
|
logger.Info("Added %d health check targets", len(config.Targets))
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("Health check targets added: %+v", config.Targets)
|
logger.Debug("Health check targets added: %+v", config.Targets)
|
||||||
@@ -1203,29 +1193,6 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Register handler for getting health check status
|
|
||||||
client.RegisterHandler("newt/blueprint/results", func(msg websocket.WSMessage) {
|
|
||||||
logger.Debug("Received blueprint results message")
|
|
||||||
|
|
||||||
var blueprintResult BlueprintResult
|
|
||||||
|
|
||||||
jsonData, err := json.Marshal(msg.Data)
|
|
||||||
if err != nil {
|
|
||||||
logger.Info("Error marshaling data: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(jsonData, &blueprintResult); err != nil {
|
|
||||||
logger.Info("Error unmarshaling config results data: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if blueprintResult.Success {
|
|
||||||
logger.Info("Blueprint applied successfully!")
|
|
||||||
} else {
|
|
||||||
logger.Warn("Blueprint application failed: %s", blueprintResult.Message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
client.OnConnect(func() error {
|
client.OnConnect(func() error {
|
||||||
publicKey = privateKey.PublicKey()
|
publicKey = privateKey.PublicKey()
|
||||||
logger.Debug("Public key: %s", publicKey)
|
logger.Debug("Public key: %s", publicKey)
|
||||||
@@ -1238,7 +1205,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
}
|
}
|
||||||
// request from the server the list of nodes to ping at newt/ping/request
|
// request from the server the list of nodes to ping at newt/ping/request
|
||||||
stopFunc = client.SendMessageInterval("newt/ping/request", map[string]interface{}{}, 3*time.Second)
|
stopFunc = client.SendMessageInterval("newt/ping/request", map[string]interface{}{}, 3*time.Second)
|
||||||
logger.Debug("Requesting exit nodes from server")
|
logger.Info("Requesting exit nodes from server")
|
||||||
clientsOnConnect()
|
clientsOnConnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1249,8 +1216,6 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
"backwardsCompatible": true,
|
"backwardsCompatible": true,
|
||||||
})
|
})
|
||||||
|
|
||||||
sendBlueprint(client)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to send registration message: %v", err)
|
logger.Error("Failed to send registration message: %v", err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -325,9 +325,11 @@ func (pm *ProxyManager) handleUDPProxy(conn *gonet.UDPConn, targetAddr string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
clientKey := remoteAddr.String()
|
// Use only the client IP as the key, not IP:port
|
||||||
|
// This ensures all packets from the same client reuse the same target connection
|
||||||
|
clientIP := remoteAddr.(*net.UDPAddr).IP.String()
|
||||||
clientsMutex.RLock()
|
clientsMutex.RLock()
|
||||||
targetConn, exists := clientConns[clientKey]
|
targetConn, exists := clientConns[clientIP]
|
||||||
clientsMutex.RUnlock()
|
clientsMutex.RUnlock()
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -344,15 +346,15 @@ func (pm *ProxyManager) handleUDPProxy(conn *gonet.UDPConn, targetAddr string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientsMutex.Lock()
|
clientsMutex.Lock()
|
||||||
clientConns[clientKey] = targetConn
|
clientConns[clientIP] = targetConn
|
||||||
clientsMutex.Unlock()
|
clientsMutex.Unlock()
|
||||||
|
|
||||||
go func(clientKey string, targetConn *net.UDPConn, remoteAddr net.Addr) {
|
go func(clientIP string, targetConn *net.UDPConn, remoteAddr net.Addr) {
|
||||||
defer func() {
|
defer func() {
|
||||||
// Always clean up when this goroutine exits
|
// Always clean up when this goroutine exits
|
||||||
clientsMutex.Lock()
|
clientsMutex.Lock()
|
||||||
if storedConn, exists := clientConns[clientKey]; exists && storedConn == targetConn {
|
if storedConn, exists := clientConns[clientIP]; exists && storedConn == targetConn {
|
||||||
delete(clientConns, clientKey)
|
delete(clientConns, clientIP)
|
||||||
targetConn.Close()
|
targetConn.Close()
|
||||||
}
|
}
|
||||||
clientsMutex.Unlock()
|
clientsMutex.Unlock()
|
||||||
@@ -372,7 +374,7 @@ func (pm *ProxyManager) handleUDPProxy(conn *gonet.UDPConn, targetAddr string) {
|
|||||||
return // defer will handle cleanup
|
return // defer will handle cleanup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(clientKey, targetConn, remoteAddr)
|
}(clientIP, targetConn, remoteAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = targetConn.Write(buffer[:n])
|
_, err = targetConn.Write(buffer[:n])
|
||||||
@@ -380,7 +382,7 @@ func (pm *ProxyManager) handleUDPProxy(conn *gonet.UDPConn, targetAddr string) {
|
|||||||
logger.Error("Error writing to target: %v", err)
|
logger.Error("Error writing to target: %v", err)
|
||||||
targetConn.Close()
|
targetConn.Close()
|
||||||
clientsMutex.Lock()
|
clientsMutex.Lock()
|
||||||
delete(clientConns, clientKey)
|
delete(clientConns, clientIP)
|
||||||
clientsMutex.Unlock()
|
clientsMutex.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
util.go
45
util.go
@@ -21,7 +21,6 @@ import (
|
|||||||
"golang.org/x/net/ipv4"
|
"golang.org/x/net/ipv4"
|
||||||
"golang.zx2c4.com/wireguard/device"
|
"golang.zx2c4.com/wireguard/device"
|
||||||
"golang.zx2c4.com/wireguard/tun/netstack"
|
"golang.zx2c4.com/wireguard/tun/netstack"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func fixKey(key string) string {
|
func fixKey(key string) string {
|
||||||
@@ -559,47 +558,3 @@ func executeUpdownScript(action, proto, target string) (string, error) {
|
|||||||
|
|
||||||
return target, nil
|
return target, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendBlueprint(client *websocket.Client) error {
|
|
||||||
if blueprintFile == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// try to read the blueprint file
|
|
||||||
blueprintData, err := os.ReadFile(blueprintFile)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to read blueprint file: %v", err)
|
|
||||||
} else {
|
|
||||||
// first we should convert the yaml to json and error if the yaml is bad
|
|
||||||
var yamlObj interface{}
|
|
||||||
var blueprintJsonData string
|
|
||||||
|
|
||||||
err = yaml.Unmarshal(blueprintData, &yamlObj)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to parse blueprint YAML: %v", err)
|
|
||||||
} else {
|
|
||||||
// convert to json
|
|
||||||
jsonBytes, err := json.Marshal(yamlObj)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to convert blueprint to JSON: %v", err)
|
|
||||||
} else {
|
|
||||||
blueprintJsonData = string(jsonBytes)
|
|
||||||
logger.Debug("Converted blueprint to JSON: %s", blueprintJsonData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have valid json data, we can send it to the server
|
|
||||||
if blueprintJsonData == "" {
|
|
||||||
logger.Error("No valid blueprint JSON data to send to server")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info("Sending blueprint to server for application")
|
|
||||||
|
|
||||||
// send the blueprint data to the server
|
|
||||||
err = client.SendMessage("newt/blueprint/apply", map[string]interface{}{
|
|
||||||
"blueprint": blueprintJsonData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user