Skip to content

Commit

Permalink
modify logic to allow subnets for InterfaceIPs and updated docs and t…
Browse files Browse the repository at this point in the history
…ests to reflect it
  • Loading branch information
masonj5n committed Oct 3, 2023
1 parent 1f621da commit 0f9b8fc
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 29 deletions.
8 changes: 4 additions & 4 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ The following environment variables are available to configure the NetObserv eBF
excluded from flow tracing. It takes priority over `INTERFACES` values.
If an entry is enclosed by slashes (e.g. `/br-/`), it will match as regular expression,
otherwise it will be matched as a case-sensitive string.
* `INTERFACE_IPS` (optional) Comma-separated list of IPs in CIDR notation (i.e. 192.0.2.0/24) whose
interfaces should be listened on. This is an alternative to specifying `INTERFACES`, useful when
you know ahead of time what IPs an interface will have but not the OS-assigned interface name itself.
Exclusive with INTERFACES/EXCLUDE_INTERFACES.
* `INTERFACE_IPS` (optional) Comma-separated list of IPs/Subnets in CIDR notation (i.e. 192.0.2.0/24).
Any interface with an associated IP address within the given ranges will be listened on. This is an
alternative to specifying `INTERFACES`, useful when you know ahead of time what IP or IP range an
interface will have but not the OS-assigned interface name itself. Exclusive with INTERFACES/EXCLUDE_INTERFACES.
* `SAMPLING` (default: disabled). Rate at which packets should be sampled and sent to the target
collector. E.g. if set to 10, one out of 10 packets, on average, will be sent to the target
collector.
Expand Down
14 changes: 7 additions & 7 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,25 +142,25 @@ func flowsAgent(cfg *Config,

if len(cfg.InterfaceIPs) > 0 {
// configure ip interface filter
f, err := initIPInterfaceFilter(cfg.InterfaceIPs, func(ifaceName string) ([]netip.Prefix, error) {
f, err := initIPInterfaceFilter(cfg.InterfaceIPs, func(ifaceName string) ([]netip.Addr, error) {
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
return []netip.Prefix{}, fmt.Errorf("error retrieving interface by name: %w", err)
return []netip.Addr{}, fmt.Errorf("error retrieving interface by name: %w", err)
}
addrs, err := iface.Addrs()
if err != nil {
return []netip.Prefix{}, fmt.Errorf("error retrieving addresses from interface: %w", err)
return []netip.Addr{}, fmt.Errorf("error retrieving addresses from interface: %w", err)
}

prefixes := []netip.Prefix{}
interfaceAddrs := []netip.Addr{}
for _, addr := range addrs {
prefix, err := netip.ParsePrefix(addr.String())
if err != nil {
return []netip.Prefix{}, fmt.Errorf("parsing given ip to netip.Prefix: %w", err)
return []netip.Addr{}, fmt.Errorf("parsing given ip to netip.Addr: %w", err)
}
prefixes = append(prefixes, prefix)
interfaceAddrs = append(interfaceAddrs, prefix.Addr())
}
return prefixes, nil
return interfaceAddrs, nil

})
if err != nil {
Expand Down
5 changes: 3 additions & 2 deletions pkg/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ type Config struct {
// BuffersLength establishes the length of communication channels between the different processing
// stages
BuffersLength int `env:"BUFFERS_LENGTH" envDefault:"50"`
// InterfaceIPs is a list of IPs whose interfaces should be listened on. This allows users to specify
// interfaces without knowing the OS-assigned interface names. Exclusive with Interfaces/ExcludeInterfaces.
// InterfaceIPs is a list of CIDR-notation IPs/Subnets where any interface containing an IP in the given ranges
// should be listened on. This allows users to specify interfaces without knowing the OS-assigned interface names.
// Exclusive with Interfaces/ExcludeInterfaces.
InterfaceIPs []string `env:"INTERFACE_IPS" envSeparator:","`
// ExporterBufferLength establishes the length of the buffer of flow batches (not individual flows)
// that can be accumulated before the Kafka or GRPC exporter. When this buffer is full (e.g.
Expand Down
18 changes: 9 additions & 9 deletions pkg/agent/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"net/netip"
"regexp"
"strings"

"golang.org/x/exp/slices"
)

type InterfaceFilter interface {
Expand All @@ -18,13 +16,13 @@ type ipInterfaceFilter struct {
// Almost always going to be a wrapper around getting
// the interface from net.InterfaceByName and then calling
// .Addrs() on the interface
ipsFromIface func(ifaceName string) ([]netip.Prefix, error)
ipsFromIface func(ifaceName string) ([]netip.Addr, error)
}

// initIPInterfaceFilter allows filtering network interfaces that are accepted/exlucded by the user,
// initIPInterfaceFilter allows filtering network interfaces that are accepted/excluded by the user,
// according to the provided INTERFACE_IPS from the configuration. It allows interfaces where at least
// one of the provided CIDRs are associated with it.
func initIPInterfaceFilter(ips []string, ipsFromIface func(ifaceName string) ([]netip.Prefix, error)) (ipInterfaceFilter, error) {
func initIPInterfaceFilter(ips []string, ipsFromIface func(ifaceName string) ([]netip.Addr, error)) (ipInterfaceFilter, error) {
ipIfaceFilter := ipInterfaceFilter{}
ipIfaceFilter.ipsFromIface = ipsFromIface

Expand All @@ -40,14 +38,16 @@ func initIPInterfaceFilter(ips []string, ipsFromIface func(ifaceName string) ([]
}

func (f *ipInterfaceFilter) Allowed(iface string) (bool, error) {
prefixes, err := f.ipsFromIface(iface)
ifaceAddrs, err := f.ipsFromIface(iface)
if err != nil {
return false, fmt.Errorf("error calling ipsFromIface(): %w", err)
}

for _, prefix := range prefixes {
if slices.Contains(f.allowedIPs, prefix) {
return true, nil
for _, ifaceAddr := range ifaceAddrs {
for _, allowedPrefix := range f.allowedIPs {
if allowedPrefix.Contains(ifaceAddr) {
return true, nil
}
}
}
return false, nil
Expand Down
17 changes: 10 additions & 7 deletions pkg/agent/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,30 +67,33 @@ func TestInterfaceFilter_ExclusionTakesPriority(t *testing.T) {
}

func TestInterfaceFilter_InterfaceIPs(t *testing.T) {
mockIPByIface := func(iface string) ([]netip.Prefix, error) {
mockIPByIface := func(iface string) ([]netip.Addr, error) {
switch iface {
case "eth0":
return []netip.Prefix{netip.MustParsePrefix("198.51.100.1/24")}, nil
return []netip.Addr{netip.MustParsePrefix("198.51.100.1/24").Addr()}, nil

case "eth1":
return []netip.Prefix{netip.MustParsePrefix("198.51.100.2/24")}, nil
return []netip.Addr{netip.MustParsePrefix("198.51.100.2/24").Addr()}, nil

case "eth2":
return []netip.Prefix{netip.MustParsePrefix("2001:db8::1/32"), netip.MustParsePrefix("198.51.100.3/24")}, nil
return []netip.Addr{netip.MustParsePrefix("2001:db8::1/32").Addr(), netip.MustParsePrefix("198.51.100.3/24").Addr()}, nil

case "eth3":
return []netip.Prefix{netip.MustParsePrefix("2001:db8::2/32")}, nil
return []netip.Addr{netip.MustParsePrefix("2001:db8::2/32").Addr()}, nil

case "eth4":
return []netip.Addr{netip.MustParsePrefix("192.0.2.120/24").Addr()}, nil

default:
panic("unexpected interface name")
}
}

ifaces, err := initIPInterfaceFilter([]string{"198.51.100.1/24", "2001:db8::1/32"}, mockIPByIface)
ifaces, err := initIPInterfaceFilter([]string{"198.51.100.1/32", "2001:db8::1/128", "192.0.2.0/24"}, mockIPByIface)
require.NoError(t, err)

// Allowed
for _, iface := range []string{"eth0", "eth2"} {
for _, iface := range []string{"eth0", "eth2", "eth4"} {
iface := iface
allowed, err := ifaces.Allowed(iface)
require.NoError(t, err)
Expand Down

0 comments on commit 0f9b8fc

Please sign in to comment.