Every physical link faces outside, up or down
The filter accepts what does not arrive on a link the machine names as outward, and the host named only links carrying a default route. An unplugged wired port was left unfiltered for whenever it was plugged in (novox/hq issue 197). A link backed by a physical device is now named whether or not it is up.
This commit is contained in:
@@ -29,17 +29,32 @@ import (
|
||||
// routing table without one.
|
||||
const ProcNet = "/proc/net"
|
||||
|
||||
// Links are the interfaces carrying a default route, for both address families, sorted and without
|
||||
// repeats.
|
||||
// SysClassNet is where the kernel lists the machine's network interfaces, one directory each. A
|
||||
// parameter for the same reason.
|
||||
const SysClassNet = "/sys/class/net"
|
||||
|
||||
// Links are the interfaces carrying a default route, for both address families, and every interface
|
||||
// backed by a physical device, sorted and without repeats.
|
||||
//
|
||||
// **A physical link faces outside whether or not it is up** (novox/hq issue 197). The filter accepts
|
||||
// whatever did not arrive on a link named here, so a link left out of this list is not filtered at
|
||||
// all. A cable unplugged when the machine last reported carries no default route, and was left out:
|
||||
// plugged in, everything arriving on it was accepted until the next report and the next push — and a
|
||||
// second physical link that never carries the default route was never filtered. A physical device is
|
||||
// read from the kernel's own list, where it has a `device` entry; a bridge, a veth, the tunnel and the
|
||||
// loopback have none, and stay what they are, this machine's own.
|
||||
//
|
||||
// A machine may have more than one: a laptop with a cable and a radio has two, and both face
|
||||
// outside. A machine with none — no route off itself — returns nothing, and the mesh refuses to
|
||||
// compose a filter for it rather than writing a rule around a link with no name, which would be a
|
||||
// rule set that does not load and a machine filtering nothing while its unit reports success.
|
||||
func Links(procNet string) ([]string, error) {
|
||||
func Links(procNet, sysClassNet string) ([]string, error) {
|
||||
if procNet == "" {
|
||||
procNet = ProcNet
|
||||
}
|
||||
if sysClassNet == "" {
|
||||
sysClassNet = SysClassNet
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
|
||||
four, err := defaultsV4(filepath.Join(procNet, "route"))
|
||||
@@ -50,7 +65,11 @@ func Links(procNet string) ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, name := range append(four, six...) {
|
||||
devices, err := physical(sysClassNet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, name := range append(append(four, six...), devices...) {
|
||||
if name != "" && name != "lo" {
|
||||
seen[name] = true
|
||||
}
|
||||
@@ -64,6 +83,25 @@ func Links(procNet string) ([]string, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// physical is every interface the kernel lists with a device behind it. A list that is not there is
|
||||
// not an error — a machine without sysfs mounted reports what its routing table says, as before.
|
||||
func physical(sysClassNet string) ([]string, error) {
|
||||
entries, err := os.ReadDir(sysClassNet)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []string
|
||||
for _, e := range entries {
|
||||
if _, err := os.Stat(filepath.Join(sysClassNet, e.Name(), "device")); err == nil {
|
||||
out = append(out, e.Name())
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// defaultsV4 reads /proc/net/route, whose columns are
|
||||
//
|
||||
// Iface Destination Gateway Flags RefCnt Use Metric Mask ...
|
||||
|
||||
Reference in New Issue
Block a user