mirror of
https://github.com/fosrl/newt.git
synced 2026-04-10 20:06:38 +00:00
Compare commits
6 Commits
dependabot
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6becf0f719 | ||
|
|
4d8d00241d | ||
|
|
7e1e3408d5 | ||
|
|
d7c3c38d24 | ||
|
|
27e471942e | ||
|
|
184bfb12d6 |
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* @oschwartz10612 @miloschwartz
|
||||
@@ -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@pangolin.net
|
||||
whitelist-users:
|
||||
- owen@pangolin.net
|
||||
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
|
||||
@@ -23,9 +23,30 @@ import (
|
||||
|
||||
const (
|
||||
errUnsupportedProtoFmt = "unsupported protocol: %s"
|
||||
maxUDPPacketSize = 65507
|
||||
maxUDPPacketSize = 65507 // Maximum UDP packet size
|
||||
)
|
||||
|
||||
// udpBufferPool provides reusable buffers for UDP packet handling.
|
||||
// This reduces GC pressure from frequent large allocations.
|
||||
var udpBufferPool = sync.Pool{
|
||||
New: func() any {
|
||||
buf := make([]byte, maxUDPPacketSize)
|
||||
return &buf
|
||||
},
|
||||
}
|
||||
|
||||
// getUDPBuffer retrieves a buffer from the pool.
|
||||
func getUDPBuffer() *[]byte {
|
||||
return udpBufferPool.Get().(*[]byte)
|
||||
}
|
||||
|
||||
// putUDPBuffer clears and returns a buffer to the pool.
|
||||
func putUDPBuffer(buf *[]byte) {
|
||||
// Clear the buffer to prevent data leakage
|
||||
clear(*buf)
|
||||
udpBufferPool.Put(buf)
|
||||
}
|
||||
|
||||
// Target represents a proxy target with its address and port
|
||||
type Target struct {
|
||||
Address string
|
||||
@@ -555,7 +576,9 @@ func (pm *ProxyManager) handleTCPProxy(listener net.Listener, targetAddr string)
|
||||
}
|
||||
|
||||
func (pm *ProxyManager) handleUDPProxy(conn *gonet.UDPConn, targetAddr string) {
|
||||
buffer := make([]byte, maxUDPPacketSize) // Max UDP packet size
|
||||
bufPtr := getUDPBuffer()
|
||||
defer putUDPBuffer(bufPtr)
|
||||
buffer := *bufPtr
|
||||
clientConns := make(map[string]*net.UDPConn)
|
||||
var clientsMutex sync.RWMutex
|
||||
|
||||
@@ -638,7 +661,10 @@ func (pm *ProxyManager) handleUDPProxy(conn *gonet.UDPConn, targetAddr string) {
|
||||
go func(clientKey string, targetConn *net.UDPConn, remoteAddr net.Addr, tunnelID string) {
|
||||
start := time.Now()
|
||||
result := "success"
|
||||
bufPtr := getUDPBuffer()
|
||||
defer func() {
|
||||
// Return buffer to pool first
|
||||
putUDPBuffer(bufPtr)
|
||||
// Always clean up when this goroutine exits
|
||||
clientsMutex.Lock()
|
||||
if storedConn, exists := clientConns[clientKey]; exists && storedConn == targetConn {
|
||||
@@ -653,7 +679,7 @@ func (pm *ProxyManager) handleUDPProxy(conn *gonet.UDPConn, targetAddr string) {
|
||||
telemetry.IncProxyConnectionEvent(context.Background(), tunnelID, "udp", telemetry.ProxyConnectionClosed)
|
||||
}()
|
||||
|
||||
buffer := make([]byte, maxUDPPacketSize)
|
||||
buffer := *bufPtr
|
||||
for {
|
||||
n, _, err := targetConn.ReadFromUDP(buffer)
|
||||
if err != nil {
|
||||
|
||||
@@ -71,6 +71,11 @@ func (c *Client) loadConfig() error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
if len(bytes.TrimSpace(data)) == 0 {
|
||||
logger.Info("Config file at %s is empty, will initialize it with provided values", configPath)
|
||||
c.configNeedsSave = true
|
||||
return nil
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := json.Unmarshal(data, &config); err != nil {
|
||||
|
||||
35
websocket/config_test.go
Normal file
35
websocket/config_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadConfig_EmptyFileMarksConfigForSave(t *testing.T) {
|
||||
t.Setenv("CONFIG_FILE", "")
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
configPath := filepath.Join(tmpDir, "config.json")
|
||||
if err := os.WriteFile(configPath, []byte(""), 0o644); err != nil {
|
||||
t.Fatalf("failed to create empty config file: %v", err)
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
config: &Config{
|
||||
Endpoint: "https://example.com",
|
||||
ProvisioningKey: "spk-test",
|
||||
},
|
||||
clientType: "newt",
|
||||
configFilePath: configPath,
|
||||
}
|
||||
|
||||
if err := client.loadConfig(); err != nil {
|
||||
t.Fatalf("loadConfig returned error for empty file: %v", err)
|
||||
}
|
||||
|
||||
if !client.configNeedsSave {
|
||||
t.Fatal("expected empty config file to mark configNeedsSave")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user