hysteria/extras/network/pool.go
Niko Marmeladkov da8366eb8a
feat: L3 VPN tunnel, FileMask noise, Hysteria outbound
- Network: Layer 3 IP tunnel over QUIC with TUN interfaces and IP pool
- FileMask: new noise/obfuscation layer masking traffic as encrypted file downloads
- Hysteria outbound: chain Hysteria servers via pluggable outbound
2026-06-16 16:07:55 +03:00

75 lines
1.3 KiB
Go

package network
import (
"fmt"
"net"
"sync"
)
type IPPool struct {
network *net.IPNet
gateway net.IP
leased map[string]bool
mu sync.Mutex
start net.IP
size int
}
func NewIPPool(netIP net.IP, ipnet *net.IPNet) (*IPPool, error) {
ones, bits := ipnet.Mask.Size()
if bits != 32 {
return nil, fmt.Errorf("only IPv4 supported")
}
size := 1 << (bits - ones)
if size < 3 {
return nil, fmt.Errorf("pool too small: %s", ipnet)
}
start := make(net.IP, 4)
copy(start, netIP.Mask(ipnet.Mask))
start[3]++
gateway := make(net.IP, 4)
copy(gateway, start)
pool := &IPPool{
network: ipnet,
gateway: gateway,
leased: make(map[string]bool),
start: start,
size: size - 2,
}
pool.leased[gateway.String()] = true
return pool, nil
}
func (p *IPPool) Allocate() net.IP {
p.mu.Lock()
defer p.mu.Unlock()
ip := make(net.IP, 4)
copy(ip, p.start)
for i := 0; i < p.size; i++ {
if !p.leased[ip.String()] {
p.leased[ip.String()] = true
return ip
}
for j := 3; j >= 0; j-- {
ip[j]++
if ip[j] != 0 {
break
}
}
}
return nil
}
func (p *IPPool) Release(ip net.IP) {
p.mu.Lock()
defer p.mu.Unlock()
delete(p.leased, ip.String())
}
func (p *IPPool) Gateway() net.IP {
return p.gateway
}
func (p *IPPool) Network() *net.IPNet {
return p.network
}