Skip to content

Commit

Permalink
don't check interface ips when getting ips from dns pool
Browse files Browse the repository at this point in the history
  • Loading branch information
scareything committed Feb 1, 2024
1 parent f65a9e6 commit 38efe4f
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 113 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/emirpasic/gods v1.18.1
github.com/fatih/color v1.16.0
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa
github.com/gaissmai/extnetip v0.4.0
github.com/go-acme/lego/v4 v4.14.2
github.com/go-openapi/errors v0.21.0
github.com/go-openapi/loads v0.21.5
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/gaissmai/extnetip v0.4.0 h1:9pNd/Z6QSlkda35bug/IYuPYaPMTYRuqcxPce5Z9TTQ=
github.com/gaissmai/extnetip v0.4.0/go.mod h1:M3NWlyFKaVosQXWXKKeIPK+5VM4U85DahdIqNYX4TK4=
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
Expand Down
4 changes: 2 additions & 2 deletions tunnel/entities/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func makeAllowedAddress(addr string) (allowedAddress, error) {
return &domainAddress{domain: strings.ToLower(addr)}, nil
}

if _, cidr, err := utils.GetDialIP(addr); err == nil {
if cidr, err := utils.GetCidr(addr); err == nil {
return &cidrAddress{cidr: *cidr}, nil
}

Expand Down Expand Up @@ -291,7 +291,7 @@ func (self *HostV1Config) GetAllowedSourceAddressRoutes() ([]*net.IPNet, error)
var routes []*net.IPNet
for _, addr := range self.AllowedSourceAddresses {
// need to get CIDR from address - iputils.getInterceptIp?
_, ipNet, err := utils.GetDialIP(addr)
ipNet, err := utils.GetCidr(addr)
if err != nil {
return nil, errors.Errorf("failed to parse allowed source address '%s': %v", addr, err)
}
Expand Down
2 changes: 1 addition & 1 deletion tunnel/intercept/hosting.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func (self *hostingContext) SetCloseCallback(f func()) {
func (self *hostingContext) OnClose() {
log := pfxlog.Logger().WithField("service", self.service.Name)
for _, addr := range self.config.AllowedSourceAddresses {
_, ipNet, err := utils.GetDialIP(addr)
ipNet, err := utils.GetCidr(addr)
if err != nil {
log.WithError(err).Error("failed to get dial IP")
} else if self.addrTracker.RemoveAddress(ipNet.String()) {
Expand Down
2 changes: 1 addition & 1 deletion tunnel/intercept/interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ type InterceptAddrCB interface {

func GetInterceptAddresses(service *entities.Service, protocols []string, resolver dns.Resolver, addressCB InterceptAddrCB) error {
for _, addr := range service.InterceptV1Config.Addresses {
err := getInterceptIP(service, addr, resolver, func(ip net.IP, ipNet *net.IPNet) {
err := getInterceptIP(service, addr, resolver, func(ipNet *net.IPNet) {
for _, protocol := range protocols {
for _, portRange := range service.InterceptV1Config.PortRanges {
addr := &InterceptAddress{
Expand Down
83 changes: 48 additions & 35 deletions tunnel/intercept/iputils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,35 @@ package intercept

import (
"fmt"
"github.com/gaissmai/extnetip"
"github.com/michaelquigley/pfxlog"
"github.com/openziti/ziti/tunnel/dns"
"github.com/openziti/ziti/tunnel/entities"
"github.com/openziti/ziti/tunnel/utils"
"net"
"net/netip"
"sync"
)

var dnsIpLow, dnsIpHigh net.IP
var dnsPrefix netip.Prefix
var dnsCurrentIp netip.Addr
var dnsCurrentIpMtx sync.Mutex

func SetDnsInterceptIpRange(cidr string) error {
ip, ipnet, err := net.ParseCIDR(cidr)
prefix, err := netip.ParsePrefix(cidr)
if err != nil {
return fmt.Errorf("invalid cidr %s: %v", cidr, err)
}

var ips []net.IP
for ip = ip.Mask(ipnet.Mask); ipnet.Contains(ip); utils.IncIP(ip) {
a := make(net.IP, len(ip))
copy(a, ip)
ips = append(ips, a)
}

// remove network address and broadcast address
dnsIpLow = ips[1]
dnsIpHigh = ips[len(ips)-2]

if len(dnsIpLow) != len(dnsIpHigh) {
return fmt.Errorf("lower dns IP length %d differs from upper dns IP length %d", len(dnsIpLow), len(dnsIpHigh))
}
dnsPrefix = prefix
// get last ip in range for logging
_, dnsIpHigh := extnetip.Range(dnsPrefix)

pfxlog.Logger().Infof("dns intercept IP range: %s - %s", dnsIpLow.String(), dnsIpHigh.String())
// skip network address
dnsCurrentIpMtx.Lock()
dnsCurrentIp = dnsPrefix.Addr().Next()
dnsCurrentIpMtx.Unlock()
pfxlog.Logger().Infof("dns intercept IP range: %v - %v", dnsCurrentIp, dnsIpHigh)
return nil
}

Expand All @@ -61,41 +59,56 @@ func cleanUpFunc(hostname string, resolver dns.Resolver) func() {
return f
}

func getInterceptIP(svc *entities.Service, hostname string, resolver dns.Resolver, addrCB func(net.IP, *net.IPNet)) error {
func incDnsIp() (err error) {
dnsCurrentIpMtx.Lock()
defer dnsCurrentIpMtx.Unlock()
ip := dnsCurrentIp.Next()
if ip.IsValid() && dnsPrefix.Contains(ip) {
dnsCurrentIp = ip
} else {
err = fmt.Errorf("cannot allocate ip addrress: ip range exhausted")
}
return
}

func getDnsIp(host string, addrCB func(*net.IPNet), svc *entities.Service, resolver dns.Resolver) (net.IP, error) {
err := incDnsIp()
if err == nil {
addrCB(&net.IPNet{
IP: dnsCurrentIp.AsSlice(),
Mask: net.CIDRMask(dnsCurrentIp.BitLen(), dnsCurrentIp.BitLen()),
})
svc.AddCleanupAction(cleanUpFunc(host, resolver))
}
return dnsCurrentIp.AsSlice(), err
}

func getInterceptIP(svc *entities.Service, hostname string, resolver dns.Resolver, addrCB func(ipNet *net.IPNet)) error {
logger := pfxlog.Logger()

// handle wildcard domain - IPs will be allocated when matching hostnames are queried
if hostname[0] == '*' {
err := resolver.AddDomain(hostname, func(host string) (net.IP, error) {
var ip net.IP
var err error
ip, err = utils.NextIP(dnsIpLow, dnsIpHigh)

if err == nil {
addrCB(ip, utils.Ip2IPnet(ip))
svc.AddCleanupAction(cleanUpFunc(host, resolver))
}
return ip, err
return getDnsIp(hostname, addrCB, svc, resolver)
})
return err
}

ip, ipNet, err := utils.GetDialIP(hostname)
// handle IP or CIDR
ipNet, err := utils.GetCidr(hostname)
if err == nil {
addrCB(ip, ipNet)
addrCB(ipNet)
return err
}

ip, _ = utils.NextIP(dnsIpLow, dnsIpHigh)
if ip == nil {
// handle hostnames
ip, err := getDnsIp(hostname, addrCB, svc, resolver)
if err != nil {
return fmt.Errorf("invalid IP address or unresolvable hostname: %s", hostname)
}
if err = resolver.AddHostname(hostname, ip); err != nil {
logger.WithError(err).Errorf("failed to add host/ip mapping to resolver: %v -> %v", hostname, ip)
}

svc.AddCleanupAction(cleanUpFunc(hostname, resolver))

ipNet = utils.Ip2IPnet(ip)
addrCB(ip, ipNet)
return nil
}
90 changes: 16 additions & 74 deletions tunnel/utils/ipcalc.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,85 +17,27 @@
package utils

import (
"bytes"
"github.com/michaelquigley/pfxlog"
"github.com/pkg/errors"
"fmt"
"net"
"net/netip"
)

func IsLocallyAssigned(addr, lower, upper net.IP) bool {
return bytes.Compare(addr.To16(), lower.To16()) >= 0 && bytes.Compare(addr.To16(), upper.To16()) <= 0
}

// return the next available IP address in the range of provided IPs
func NextIP(lower, upper net.IP) (net.IP, error) {
usedAddrs, err := AllInterfaceAddrs()
if err != nil {
return nil, err
}

// need to make a copy of lower net.IP, since they're just byte arrays. Otherwise
// we're continually changing the lower ip globally
ip := net.IP(make([]byte, len(lower)))
copy(ip, lower)

for ; !ip.Equal(upper); IncIP(ip) {
inUse := false
for _, usedAddr := range usedAddrs {
usedIP, _, _ := net.ParseCIDR(usedAddr.String())
if ip.Equal(usedIP) {
inUse = true
break
}
}
if !inUse {
return ip, nil
}
}

return nil, nil
}

func IncIP(ip net.IP) {
for i := len(ip) - 1; i >= 0; i-- {
ip[i]++
if ip[i] > 0 {
break
}
}
}

// Return the length of a full prefix (no subnetting) for the given IP address.
// Returns 32 for ipv4 addresses, and 128 for ipv6 addresses.
func AddrBits(ip net.IP) int {
if ip == nil {
return 0
} else if ip.To4() != nil {
return net.IPv4len * 8
} else if ip.To16() != nil {
return net.IPv6len * 8
}

pfxlog.Logger().Infof("invalid IP address %s", ip.String())
return 0
}

func Ip2IPnet(ip net.IP) *net.IPNet {
prefixLen := AddrBits(ip)
ipNet := &net.IPNet{IP: ip, Mask: net.CIDRMask(prefixLen, prefixLen)}
return ipNet
}

func GetDialIP(addr string) (net.IP, *net.IPNet, error) {
// hostname is an ip address, return it
if parsedIP := net.ParseIP(addr); parsedIP != nil {
ipNet := Ip2IPnet(parsedIP)
return parsedIP, ipNet, nil
func GetCidr(ipOrCidr string) (*net.IPNet, error) {
ip, err := netip.ParseAddr(ipOrCidr)
if err == nil {
return &net.IPNet{
IP: ip.AsSlice(),
Mask: net.CIDRMask(ip.BitLen(), ip.BitLen()),
}, nil
}

if parsedIP, cidr, err := net.ParseCIDR(addr); err == nil {
return parsedIP, cidr, nil
pfx, err := netip.ParsePrefix(ipOrCidr)
if err == nil {
return &net.IPNet{
IP: pfx.Addr().AsSlice(),
Mask: net.CIDRMask(pfx.Bits(), pfx.Addr().BitLen()),
}, nil
}

return nil, nil, errors.Errorf("could not parse '%s' as IP or CIDR", addr)
return nil, fmt.Errorf("failed to parse '%v' as IP or CIDR", ipOrCidr)
}

0 comments on commit 38efe4f

Please sign in to comment.