Files
the-other-dude/poller/internal/tunnel/portpool.go
Jason Staack c2eea6847f fix: WinBox tunnel bind address, port range, and proxy support
- Bind tunnel listeners to 0.0.0.0 instead of 127.0.0.1 so tunnels
  are reachable through reverse proxies and container networks
- Reduce port range to 49000-49004 (5 concurrent tunnels)
- Derive WinBox URI host from request Host header instead of
  hardcoding 127.0.0.1, enabling use behind reverse proxies
- Add README security warning about default encryption keys

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 19:03:53 -05:00

64 lines
1.2 KiB
Go

package tunnel
import (
"fmt"
"net"
"sync"
)
// PortPool tracks available ports in a fixed range for WinBox tunnel allocation.
type PortPool struct {
mu sync.Mutex
used []bool
base int
count int
}
func NewPortPool(min, max int) *PortPool {
count := max - min + 1
return &PortPool{
used: make([]bool, count),
base: min,
count: count,
}
}
// Allocate returns the next free port, verifying it can actually be bound.
// Returns error if all ports are exhausted.
func (pp *PortPool) Allocate() (int, error) {
pp.mu.Lock()
defer pp.mu.Unlock()
for i := 0; i < pp.count; i++ {
if pp.used[i] {
continue
}
port := pp.base + i
if !canBind(port) {
continue
}
pp.used[i] = true
return port, nil
}
return 0, fmt.Errorf("no ports available in range %d-%d", pp.base, pp.base+pp.count-1)
}
// Release returns a port to the pool.
func (pp *PortPool) Release(port int) {
pp.mu.Lock()
defer pp.mu.Unlock()
idx := port - pp.base
if idx >= 0 && idx < pp.count {
pp.used[idx] = false
}
}
func canBind(port int) bool {
ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
if err != nil {
return false
}
ln.Close()
return true
}