summaryrefslogtreecommitdiff
path: root/vendor/github.com/prometheus/procfs/arp.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/prometheus/procfs/arp.go')
-rw-r--r--vendor/github.com/prometheus/procfs/arp.go116
1 files changed, 116 insertions, 0 deletions
diff --git a/vendor/github.com/prometheus/procfs/arp.go b/vendor/github.com/prometheus/procfs/arp.go
new file mode 100644
index 000000000..28783e2dd
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/arp.go
@@ -0,0 +1,116 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Learned from include/uapi/linux/if_arp.h.
+const (
+ // completed entry (ha valid).
+ ATFComplete = 0x02
+ // permanent entry.
+ ATFPermanent = 0x04
+ // Publish entry.
+ ATFPublish = 0x08
+ // Has requested trailers.
+ ATFUseTrailers = 0x10
+ // Obsoleted: Want to use a netmask (only for proxy entries).
+ ATFNetmask = 0x20
+ // Don't answer this addresses.
+ ATFDontPublish = 0x40
+)
+
+// ARPEntry contains a single row of the columnar data represented in
+// /proc/net/arp.
+type ARPEntry struct {
+ // IP address
+ IPAddr net.IP
+ // MAC address
+ HWAddr net.HardwareAddr
+ // Name of the device
+ Device string
+ // Flags
+ Flags byte
+}
+
+// GatherARPEntries retrieves all the ARP entries, parse the relevant columns,
+// and then return a slice of ARPEntry's.
+func (fs FS) GatherARPEntries() ([]ARPEntry, error) {
+ data, err := os.ReadFile(fs.proc.Path("net/arp"))
+ if err != nil {
+ return nil, fmt.Errorf("%s: error reading arp %s: %w", ErrFileRead, fs.proc.Path("net/arp"), err)
+ }
+
+ return parseARPEntries(data)
+}
+
+func parseARPEntries(data []byte) ([]ARPEntry, error) {
+ lines := strings.Split(string(data), "\n")
+ entries := make([]ARPEntry, 0)
+ var err error
+ const (
+ expectedDataWidth = 6
+ expectedHeaderWidth = 9
+ )
+ for _, line := range lines {
+ columns := strings.Fields(line)
+ width := len(columns)
+
+ if width == expectedHeaderWidth || width == 0 {
+ continue
+ } else if width == expectedDataWidth {
+ entry, err := parseARPEntry(columns)
+ if err != nil {
+ return []ARPEntry{}, fmt.Errorf("%s: Failed to parse ARP entry: %v: %w", ErrFileParse, entry, err)
+ }
+ entries = append(entries, entry)
+ } else {
+ return []ARPEntry{}, fmt.Errorf("%s: %d columns found, but expected %d: %w", ErrFileParse, width, expectedDataWidth, err)
+ }
+
+ }
+
+ return entries, err
+}
+
+func parseARPEntry(columns []string) (ARPEntry, error) {
+ entry := ARPEntry{Device: columns[5]}
+ ip := net.ParseIP(columns[0])
+ entry.IPAddr = ip
+
+ if mac, err := net.ParseMAC(columns[3]); err == nil {
+ entry.HWAddr = mac
+ } else {
+ return ARPEntry{}, err
+ }
+
+ if flags, err := strconv.ParseUint(columns[2], 0, 8); err == nil {
+ entry.Flags = byte(flags)
+ } else {
+ return ARPEntry{}, err
+ }
+
+ return entry, nil
+}
+
+// IsComplete returns true if ARP entry is marked with complete flag.
+func (entry *ARPEntry) IsComplete() bool {
+ return entry.Flags&ATFComplete != 0
+}