Skip to content

Commit

Permalink
packetbeat: add option to allow sniffer to change device when default…
Browse files Browse the repository at this point in the history
… route changes (#32681)

* packetbeat: add option to allow sniffer to change device when default route changes

Rather than attempting to append new sniffer device data to an established dump,
file, dump files are rolled when a new device is used. The alternative would
require keeping a track of link type and *pcapgo.Writer between calls to sniff
to ensure that the dump file is not truncated and that the header is
appropriately written.

If the user needs to have a single pcap file for the session, they can be merged
using either wireshark or mergecap.

* packetbeat/sniffer: add logic to allow requests for interface refresh

Use this when there have been too many timeouts, or when there is an error
condition during packet capture.

* register a default_route metric when following default route
  • Loading branch information
efd6 authored Sep 13, 2022
1 parent fa5047c commit 9f4bb06
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 35 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ https://github.com/elastic/beats/compare/v8.2.0\...main[Check the HEAD diff]

*Packetbeat*

- Add option to allow sniffer to change device when default route changes. {issue}31905[31905] {pull}32681[32681]

*Functionbeat*

Expand Down
5 changes: 5 additions & 0 deletions packetbeat/_meta/config/beat.yml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
# to sniff on the device carrying the default route.
packetbeat.interfaces.device: {{ call .device .GOOS }}

# Specify the amount of time between polling for changes in the default
# route. This option is only used when one of the default route devices
# is specified.
packetbeat.interfaces.poll_default_route: 1m

# The network CIDR blocks that are considered "internal" networks for
# the purpose of network perimeter boundary classification. The valid
# values for internal_networks are the same as those that can be used
Expand Down
2 changes: 1 addition & 1 deletion packetbeat/beater/packetbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ var cmdLineArgs = flags{
loop: flag.Int("l", 1, "Loop file. 0 - loop forever"),
oneAtAtime: flag.Bool("O", false, "Read packets one at a time (press Enter)"),
topSpeed: flag.Bool("t", false, "Read packets as fast as possible, without sleeping"),
dumpfile: flag.String("dump", "", "Write all captured packets to this libpcap file"),
dumpfile: flag.String("dump", "", "Write all captured packets to libpcap files with this prefix - a timestamp and pcap extension are added"),
}

func initialConfig() config.Config {
Expand Down
24 changes: 14 additions & 10 deletions packetbeat/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ func (c Config) FromStatic(cfg *conf.C) (Config, error) {
if err != nil {
return c, err
}
if 0 < c.Interfaces.PollDefaultRoute && c.Interfaces.PollDefaultRoute < time.Second {
c.Interfaces.PollDefaultRoute = time.Second
}
return c, nil
}

Expand Down Expand Up @@ -76,17 +79,18 @@ func (c Config) ICMP() (*conf.C, error) {
}

type InterfacesConfig struct {
Device string `config:"device"`
Type string `config:"type"`
File string `config:"file"`
WithVlans bool `config:"with_vlans"`
BpfFilter string `config:"bpf_filter"`
Snaplen int `config:"snaplen"`
BufferSizeMb int `config:"buffer_size_mb"`
EnableAutoPromiscMode bool `config:"auto_promisc_mode"`
InternalNetworks []string `config:"internal_networks"`
Device string `config:"device"`
PollDefaultRoute time.Duration `config:"poll_default_route"`
Type string `config:"type"`
File string `config:"file"`
WithVlans bool `config:"with_vlans"`
BpfFilter string `config:"bpf_filter"`
Snaplen int `config:"snaplen"`
BufferSizeMb int `config:"buffer_size_mb"`
EnableAutoPromiscMode bool `config:"auto_promisc_mode"`
InternalNetworks []string `config:"internal_networks"`
TopSpeed bool
Dumpfile string
Dumpfile string // Dumpfile is the basename of pcap dumpfiles. The file names will have a creation time stamp and .pcap extension appended.
OneAtATime bool
Loop int
}
Expand Down
5 changes: 5 additions & 0 deletions packetbeat/packetbeat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
# to sniff on the device carrying the default route.
packetbeat.interfaces.device: any

# Specify the amount of time between polling for changes in the default
# route. This option is only used when one of the default route devices
# is specified.
packetbeat.interfaces.poll_default_route: 1m

# The network CIDR blocks that are considered "internal" networks for
# the purpose of network perimeter boundary classification. The valid
# values for internal_networks are the same as those that can be used
Expand Down
15 changes: 15 additions & 0 deletions packetbeat/sniffer/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ import (
"runtime"
"strconv"
"strings"
"sync"
"syscall"

"github.com/google/gopacket/pcap"

"github.com/elastic/beats/v7/packetbeat/route"
"github.com/elastic/elastic-agent-libs/logp"
"github.com/elastic/elastic-agent-libs/monitoring"
)

var deviceAnySupported = runtime.GOOS == "linux"
Expand Down Expand Up @@ -93,6 +95,7 @@ func resolveDeviceName(name string) (string, error) {
iface string
err error
)
registerDefaultRouteMetricOnce()
switch name {
case "default_route":
for _, inet := range []int{syscall.AF_INET, syscall.AF_INET6} {
Expand All @@ -114,6 +117,7 @@ func resolveDeviceName(name string) (string, error) {
if err != nil {
return "", fmt.Errorf("failed to get default route device: %w", err)
}
defaultRouteMetric.Set(iface)

devices, err := ListDeviceNames(false, false)
if err != nil {
Expand Down Expand Up @@ -148,6 +152,17 @@ func resolveDeviceName(name string) (string, error) {
return name, nil
}

var (
registerRoute sync.Once
defaultRouteMetric *monitoring.String
)

func registerDefaultRouteMetricOnce() {
registerRoute.Do(func() {
defaultRouteMetric = monitoring.NewString(nil, "packetbeat.default_route")
})
}

func sameDevice(route, pcap string) bool {
if runtime.GOOS == "windows" {
// The device returned by route does not have the same device tree
Expand Down
Loading

0 comments on commit 9f4bb06

Please sign in to comment.