- 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
75 lines
1.3 KiB
Go
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
|
|
}
|