powerdns-remote-http-example/addr-map.go

142 lines
2.8 KiB
Go
Raw Normal View History

2024-06-04 03:20:21 +03:00
package main
import (
2024-06-06 07:44:26 +03:00
"crypto/rand"
2024-06-04 03:20:21 +03:00
"encoding/binary"
"log"
2024-06-06 07:44:26 +03:00
"math"
2024-06-04 03:20:21 +03:00
"net"
2024-06-06 07:44:26 +03:00
"sync"
"time"
2024-06-04 03:20:21 +03:00
)
2024-06-06 07:44:26 +03:00
const (
addrMapHouseKeepInterval = time.Second / 2
)
var (
addr4, addr6 sync.Map
)
type AddrMap struct {
SrcAddr net.IP
DstAddr net.IP
Ttl uint32
Created time.Time
}
func (a *AddrMap) GetTtl() int32 {
x := math.Trunc(time.Since(a.Created).Round(addrMapHouseKeepInterval).Seconds())
return int32(a.Ttl) - int32(x)
}
func setupAddrMapHousekeeping() {
go func() {
for {
time.Sleep(addrMapHouseKeepInterval)
addr4.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
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 {
2024-06-04 03:20:21 +03:00
addrlen := len(srcIp)
2024-06-06 07:44:26 +03:00
switch addrlen {
case net.IPv4len, net.IPv6len:
default:
log.Fatalf("addrMapGet(): src size mismatch: %v", addrlen)
}
2024-06-04 03:20:21 +03:00
if addrlen != len(dstCidr.IP) {
2024-06-06 07:44:26 +03:00
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))
2024-06-04 03:20:21 +03:00
}
2024-07-07 16:11:02 +03:00
var hkey any
switch addrlen {
case net.IPv4len:
hkey = binary.NativeEndian.Uint32(srcIp)
case net.IPv6len:
hkey = srcIp.To16().String()
}
2024-06-06 07:44:26 +03:00
var curr AddrMap
curr.SrcAddr = make([]byte, addrlen)
curr.DstAddr = make([]byte, addrlen)
copy(curr.DstAddr, srcIp)
curr.Ttl = ttl
2024-06-04 03:20:21 +03:00
2024-07-07 16:11:02 +03:00
_, err := rand.Read(curr.SrcAddr)
if err != nil {
log.Fatalf("rand.Read(): error %v", err)
}
2024-06-06 07:44:26 +03:00
2024-07-07 16:11:02 +03:00
// 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)
}
curr.Created = time.Now()
var xprev any
var loaded bool
switch addrlen {
case net.IPv4len:
xprev, loaded = addr4.LoadOrStore(hkey, curr)
case net.IPv6len:
xprev, loaded = addr6.LoadOrStore(hkey, curr)
}
if !loaded {
// early return
return curr.SrcAddr
}
2024-06-06 07:44:26 +03:00
2024-07-07 16:11:02 +03:00
prev, ok := xprev.(AddrMap)
if !ok {
log.Fatalf("addrMapGet(): wrong value type from sync.Map")
}
2024-06-06 07:44:26 +03:00
2024-07-07 16:11:02 +03:00
copy(curr.SrcAddr, prev.SrcAddr)
if prev.GetTtl() < int32(curr.Ttl) {
2024-06-06 07:44:26 +03:00
switch addrlen {
case net.IPv4len:
2024-07-07 16:11:02 +03:00
addr4.Store(hkey, curr)
2024-06-06 07:44:26 +03:00
case net.IPv6len:
2024-07-07 16:11:02 +03:00
addr6.Store(hkey, curr)
2024-06-06 07:44:26 +03:00
}
2024-06-04 03:20:21 +03:00
}
2024-06-06 07:44:26 +03:00
return curr.SrcAddr
2024-06-04 03:20:21 +03:00
}