rework address mapping

This commit is contained in:
Konstantin Demin 2024-06-06 07:44:26 +03:00
parent f9618226fd
commit 0faa8ec86a
Signed by: krd
GPG Key ID: 4D56F87A8BA65FD0
5 changed files with 145 additions and 38 deletions

View File

@ -1,43 +1,148 @@
package main package main
import ( import (
"crypto/rand"
"encoding/binary" "encoding/binary"
"log" "log"
"math"
"net" "net"
"sync"
"time"
"github.com/cespare/xxhash/v2" "github.com/cespare/xxhash/v2"
) )
// TODO: write more convenient version const (
func addrMap(srcIp net.IP, dstCidr *net.IPNet) net.IP { addrMapHouseKeepInterval = time.Second / 2
addrlen := len(srcIp) )
if addrlen != len(dstCidr.IP) {
log.Fatalf("addrMap(): src/dst size mismatch: %v vs %v", len(srcIp), len(dstCidr.IP))
}
var addr net.IP = make([]byte, addrlen) var (
addr4, addr6 sync.Map
)
hsum := xxhash.Sum64(srcIp) type AddrMap struct {
bsum := binary.NativeEndian.AppendUint64([]byte{}, hsum) SrcAddr net.IP
blen := len(bsum) DstAddr net.IP
if addrlen > blen { Ttl uint32
// extend bsum Created time.Time
tmp := append(make([]byte, addrlen-blen), bsum...) }
bsum = tmp
} func (a *AddrMap) GetTtl() int32 {
if addrlen < blen { x := math.Trunc(time.Since(a.Created).Round(addrMapHouseKeepInterval).Seconds())
// trim bsum return int32(a.Ttl) - int32(x)
bsum = bsum[:addrlen] }
}
func setupAddrMapHousekeeping() {
// apply inverted mask to bsum and sum with addr go func() {
for i := range addrlen / 4 { for {
a := binary.NativeEndian.Uint32(dstCidr.IP[i*4:]) time.Sleep(addrMapHouseKeepInterval)
b := binary.NativeEndian.Uint32(bsum[i*4:]) addr4.Range(func(key, value any) bool {
m := binary.NativeEndian.Uint32(dstCidr.Mask[i*4:]) a, ok := value.(AddrMap)
a += (b & ^m) if ok {
binary.NativeEndian.PutUint32(addr[i*4:], a) if a.GetTtl() > 1 {
} return true
}
return addr }
// delete if value is bogus or if ttl is less than second
addr4.Delete(key)
return true
})
}
}()
go func() {
for {
time.Sleep(addrMapHouseKeepInterval)
addr6.Range(func(key, value any) bool {
a, ok := value.(AddrMap)
if ok {
if a.GetTtl() > 1 {
return true
}
}
// delete if value is bogus or if ttl is less than second
addr6.Delete(key)
return true
})
}
}()
}
func addrMapGet(srcIp net.IP, dstCidr *net.IPNet, ttl uint32) net.IP {
addrlen := len(srcIp)
switch addrlen {
case net.IPv4len, net.IPv6len:
default:
log.Fatalf("addrMapGet(): src size mismatch: %v", addrlen)
}
if addrlen != len(dstCidr.IP) {
log.Fatalf("addrMapGet(): src/dst size mismatch: %v vs %v", addrlen, len(dstCidr.IP))
}
if addrlen != len(dstCidr.Mask) {
log.Fatalf("addrMapGet(): src/dst size mismatch: %v vs %v", addrlen, len(dstCidr.IP))
}
var curr AddrMap
curr.SrcAddr = make([]byte, addrlen)
curr.DstAddr = make([]byte, addrlen)
copy(curr.DstAddr, srcIp)
curr.Ttl = ttl
for {
_, err := rand.Read(curr.SrcAddr)
if err != nil {
log.Fatalf("rand.Read(): error %v", err)
}
// adjust random bytes to dstCidr
for i := range addrlen / 4 {
a := binary.NativeEndian.Uint32(dstCidr.IP[i*4:])
b := binary.NativeEndian.Uint32(curr.SrcAddr[i*4:])
m := binary.NativeEndian.Uint32(dstCidr.Mask[i*4:])
a += (b & ^m)
binary.NativeEndian.PutUint32(curr.SrcAddr[i*4:], a)
}
hsum := xxhash.Sum64(curr.SrcAddr)
curr.Created = time.Now()
var xprev any
var loaded bool
switch addrlen {
case net.IPv4len:
xprev, loaded = addr4.LoadOrStore(hsum, curr)
case net.IPv6len:
xprev, loaded = addr6.LoadOrStore(hsum, curr)
}
if !loaded {
// early return
return curr.SrcAddr
}
prev, ok := xprev.(AddrMap)
if !ok {
log.Fatalf("addrMapGet(): wrong value type from sync.Map")
}
if !net.IP.Equal(curr.SrcAddr, prev.SrcAddr) {
// generate next random address
continue
}
if !net.IP.Equal(curr.DstAddr, prev.DstAddr) {
// generate next random address
continue
}
if prev.GetTtl() < int32(curr.Ttl) {
switch addrlen {
case net.IPv4len:
addr4.Store(hsum, curr)
case net.IPv6len:
addr6.Store(hsum, curr)
}
}
break
}
return curr.SrcAddr
} }

4
cfg.go
View File

@ -20,8 +20,8 @@ const (
cfgNftTableFamily = nft.TableFamilyINet cfgNftTableFamily = nft.TableFamilyINet
cfgNftMapV4 = "tele4" cfgNftMapV4 = "tele4"
cfgNftMapV6 = "tele6" cfgNftMapV6 = "tele6"
cfgNftCidrV4 = "251.0.0.0/8" cfgNftCidrV4 = "198.18.0.0/15"
cfgNftCidrV6 = "2001:db8:11::/48" cfgNftCidrV6 = "2001:db8:11::/80"
cfgSoaNs = "gw.vpn." cfgSoaNs = "gw.vpn."
cfgSoaMbox = "dns.gw.vpn." cfgSoaMbox = "dns.gw.vpn."

View File

@ -140,18 +140,19 @@ func dnsRemap(qname string, qtype uint16, orig *dns.Msg) ([]PowerDnsAnswer, erro
continue continue
} }
// HACK: clip ttl
r.Ttl = dnsClipTtl(r.Ttl)
var srcAddr net.IP = make([]byte, r.AddrLen) var srcAddr net.IP = make([]byte, r.AddrLen)
copy(srcAddr, r.Addr) copy(srcAddr, r.Addr)
var dstAddr net.IP var dstAddr net.IP
switch r.AddrLen { switch r.AddrLen {
case net.IPv4len: case net.IPv4len:
dstAddr = addrMap(r.Addr, nftCidrV4) dstAddr = addrMapGet(r.Addr, nftCidrV4, r.Ttl)
case net.IPv6len: case net.IPv6len:
dstAddr = addrMap(r.Addr, nftCidrV6) dstAddr = addrMapGet(r.Addr, nftCidrV6, r.Ttl)
} }
// HACK: clip ttl
r.Ttl = dnsClipTtl(r.Ttl)
// HACK: replace addr // HACK: replace addr
copy(r.Addr, dstAddr) copy(r.Addr, dstAddr)

View File

@ -1,7 +1,7 @@
#!/usr/sbin/nft -f #!/usr/sbin/nft -f
define n_tele4 = 251.0.0.0/8 define n_tele4 = 198.18.0.0/15
define n_tele6 = 2001:db8:11::/48 define n_tele6 = 2001:db8:11::/80
table inet uni { table inet uni {

View File

@ -25,6 +25,7 @@ func main() {
setupNftables() setupNftables()
r := setupGin() r := setupGin()
setupAddrMapHousekeeping()
log.Printf("%s: ready\n", userAgent) log.Printf("%s: ready\n", userAgent)
if err := r.Run(cfgListen); err != nil { if err := r.Run(cfgListen); err != nil {