mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-06-19 07:36:59 +00:00
fix: count private network interfaces
This commit is contained in:
@@ -0,0 +1,363 @@
|
||||
# Windows Network Traffic Stats Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Fix Windows network traffic statistics showing zero when the active adapter is named like `Ethernet0` and uses a private IPv4 address.
|
||||
|
||||
**Architecture:** Keep the fix inside `internal/analytic/network.go`. Extract the interface selection rule into a small testable helper, then let `GetNetworkStat()` aggregate any up, non-loopback, non-virtual interface with a hardware address and at least one usable unicast IP address, including private IPv4 ranges. Continue excluding disconnected, loopback, link-local-only, TAP, tunnel, VPN, Docker, and similar virtual interfaces.
|
||||
|
||||
**Tech Stack:** Go, `net`, `github.com/shirou/gopsutil/v4/net`, existing `go test` workflow.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
- Modify: `internal/analytic/network.go`
|
||||
- Keep `GetNetworkStat()` as the public entry point.
|
||||
- Add a lightweight `networkInterfaceInfo` struct so selection logic can be unit-tested without depending on host NICs.
|
||||
- Replace the current public-IP-only gate with `hasUsableUnicastIP()`.
|
||||
- Create: `internal/analytic/network_test.go`
|
||||
- Unit tests for Windows-style adapter names and private IPs.
|
||||
- Regression tests for virtual, loopback, down, and link-local-only interfaces.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add Failing Network Interface Selection Tests
|
||||
|
||||
**Files:**
|
||||
- Create: `internal/analytic/network_test.go`
|
||||
|
||||
- [ ] **Step 1: Create tests for the Windows regression and exclusions**
|
||||
|
||||
Create `internal/analytic/network_test.go`:
|
||||
|
||||
```go
|
||||
package analytic
|
||||
|
||||
import (
|
||||
stdnet "net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func mustCIDR(t *testing.T, value string) stdnet.Addr {
|
||||
t.Helper()
|
||||
|
||||
ip, ipNet, err := stdnet.ParseCIDR(value)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse CIDR %q: %v", value, err)
|
||||
}
|
||||
ipNet.IP = ip
|
||||
return ipNet
|
||||
}
|
||||
|
||||
func TestShouldCountNetworkInterfaceAcceptsWindowsEthernetPrivateIPv4(t *testing.T) {
|
||||
iface := networkInterfaceInfo{
|
||||
Name: "Ethernet0",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "10.100.1.10/28")},
|
||||
}
|
||||
|
||||
if !shouldCountNetworkInterface(iface) {
|
||||
t.Fatalf("expected Windows Ethernet interface with private IPv4 to be counted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldCountNetworkInterfaceRejectsTapAdapter(t *testing.T) {
|
||||
iface := networkInterfaceInfo{
|
||||
Name: "TAP-Windows Adapter V9",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0xff, 0x55, 0x61, 0x3a, 0xd2},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "10.8.0.2/24")},
|
||||
}
|
||||
|
||||
if shouldCountNetworkInterface(iface) {
|
||||
t.Fatalf("expected TAP adapter to be excluded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldCountNetworkInterfaceRejectsLinkLocalOnly(t *testing.T) {
|
||||
iface := networkInterfaceInfo{
|
||||
Name: "Ethernet0",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "fe80::c562:f8dc:9cd4:18eb/64")},
|
||||
}
|
||||
|
||||
if shouldCountNetworkInterface(iface) {
|
||||
t.Fatalf("expected link-local-only interface to be excluded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldCountNetworkInterfaceRejectsLoopback(t *testing.T) {
|
||||
iface := networkInterfaceInfo{
|
||||
Name: "Loopback Pseudo-Interface 1",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagLoopback,
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "127.0.0.1/8")},
|
||||
}
|
||||
|
||||
if shouldCountNetworkInterface(iface) {
|
||||
t.Fatalf("expected loopback interface to be excluded")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests and verify they fail because the helper does not exist**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
go test ./internal/analytic
|
||||
```
|
||||
|
||||
Expected: FAIL with compile errors containing `undefined: networkInterfaceInfo` and `undefined: shouldCountNetworkInterface`.
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Implement Testable Interface Classification
|
||||
|
||||
**Files:**
|
||||
- Modify: `internal/analytic/network.go`
|
||||
|
||||
- [ ] **Step 1: Add testable interface metadata and selection helpers**
|
||||
|
||||
Add this near the top of `internal/analytic/network.go`, after imports and before `GetNetworkStat()`:
|
||||
|
||||
```go
|
||||
type networkInterfaceInfo struct {
|
||||
Name string
|
||||
Flags stdnet.Flags
|
||||
HardwareAddr stdnet.HardwareAddr
|
||||
Addrs []stdnet.Addr
|
||||
}
|
||||
|
||||
func shouldCountNetworkInterface(iface networkInterfaceInfo) bool {
|
||||
if iface.Flags&stdnet.FlagUp == 0 || iface.Flags&stdnet.FlagLoopback != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if isVirtualInterface(iface.Name) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(iface.HardwareAddr) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return hasUsableUnicastIP(iface.Addrs)
|
||||
}
|
||||
|
||||
func buildCountedInterfaceSet(interfaces []networkInterfaceInfo) map[string]bool {
|
||||
countedInterfaces := make(map[string]bool)
|
||||
for _, iface := range interfaces {
|
||||
if shouldCountNetworkInterface(iface) {
|
||||
countedInterfaces[iface.Name] = true
|
||||
}
|
||||
}
|
||||
return countedInterfaces
|
||||
}
|
||||
|
||||
func hasUsableUnicastIP(addrs []stdnet.Addr) bool {
|
||||
for _, addr := range addrs {
|
||||
ip, _, err := stdnet.ParseCIDR(addr.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !ip.IsGlobalUnicast() {
|
||||
continue
|
||||
}
|
||||
|
||||
if ip.IsLinkLocalUnicast() || ip.IsLoopback() || ip.IsMulticast() || ip.IsUnspecified() {
|
||||
continue
|
||||
}
|
||||
|
||||
if isReservedIP(ip) {
|
||||
continue
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests and verify helper behavior passes but `GetNetworkStat()` still uses old selection**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
go test ./internal/analytic
|
||||
```
|
||||
|
||||
Expected: PASS for the new helper tests if they are the only changed tests; the runtime path has not been updated yet.
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Wire `GetNetworkStat()` to the New Selection Rule
|
||||
|
||||
**Files:**
|
||||
- Modify: `internal/analytic/network.go`
|
||||
|
||||
- [ ] **Step 1: Replace the existing external-interface discovery loop**
|
||||
|
||||
In `GetNetworkStat()`, replace the current logic that checks `isPhysicalInterface()` and `isRealExternalIP()` with this loop:
|
||||
|
||||
```go
|
||||
interfaceInfos := make([]networkInterfaceInfo, 0, len(interfaces))
|
||||
|
||||
for _, iface := range interfaces {
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
interfaceInfos = append(interfaceInfos, networkInterfaceInfo{
|
||||
Name: iface.Name,
|
||||
Flags: iface.Flags,
|
||||
HardwareAddr: iface.HardwareAddr,
|
||||
Addrs: addrs,
|
||||
})
|
||||
}
|
||||
|
||||
countedInterfaces := buildCountedInterfaceSet(interfaceInfos)
|
||||
```
|
||||
|
||||
Then update the aggregation condition from:
|
||||
|
||||
```go
|
||||
if externalInterfaces[stat.Name] {
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```go
|
||||
if countedInterfaces[stat.Name] {
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Remove now-unused physical/public-IP selection helpers**
|
||||
|
||||
Remove these functions if they are no longer referenced:
|
||||
|
||||
```go
|
||||
func isPhysicalInterface(name string) bool
|
||||
func isNumericSuffix(s string) bool
|
||||
func isRealExternalIP(ip stdnet.IP, ipNet *stdnet.IPNet) bool
|
||||
```
|
||||
|
||||
Keep `isReservedIP()` because `hasUsableUnicastIP()` still uses it.
|
||||
|
||||
- [ ] **Step 3: Run gofmt**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
gofmt -w internal/analytic/network.go internal/analytic/network_test.go
|
||||
```
|
||||
|
||||
Expected: no output.
|
||||
|
||||
- [ ] **Step 4: Run analytic package tests**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
go test ./internal/analytic
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Add Regression Coverage for Aggregation Name Matching
|
||||
|
||||
**Files:**
|
||||
- Modify: `internal/analytic/network_test.go`
|
||||
|
||||
- [ ] **Step 1: Add a test for building the counted interface map**
|
||||
|
||||
Add this test:
|
||||
|
||||
```go
|
||||
func TestBuildCountedInterfaceSetIncludesOnlyEligibleNames(t *testing.T) {
|
||||
interfaces := []networkInterfaceInfo{
|
||||
{
|
||||
Name: "Ethernet0",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "10.100.1.10/28")},
|
||||
},
|
||||
{
|
||||
Name: "TAP-Windows Adapter V9",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0xff, 0x55, 0x61, 0x3a, 0xd2},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "10.8.0.2/24")},
|
||||
},
|
||||
}
|
||||
|
||||
counted := buildCountedInterfaceSet(interfaces)
|
||||
if !counted["Ethernet0"] {
|
||||
t.Fatalf("expected Ethernet0 to be counted")
|
||||
}
|
||||
if counted["TAP-Windows Adapter V9"] {
|
||||
t.Fatalf("expected TAP adapter to be excluded")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
go test ./internal/analytic
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Final Verification
|
||||
|
||||
**Files:**
|
||||
- Verify only; no edits.
|
||||
|
||||
- [ ] **Step 1: Check the changed file list**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff --stat -- internal/analytic/network.go internal/analytic/network_test.go
|
||||
```
|
||||
|
||||
Expected: only the network stat implementation and its tests are listed.
|
||||
|
||||
- [ ] **Step 2: Run package tests**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
go test ./internal/analytic
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 3: Optional broader backend smoke test**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
go test ./api/analytic ./internal/analytic
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
---
|
||||
|
||||
## Self-Review
|
||||
|
||||
- Spec coverage: The plan addresses the observed Windows Server 2012 R2 output where `Ethernet0` has a private `10.100.x.x` address and traffic is currently filtered to zero.
|
||||
- Risk control: The plan keeps virtual/tunnel exclusions and avoids switching blindly to `net.IOCounters(false)`, which could count loopback and virtual adapters.
|
||||
- Test coverage: The plan adds regression tests for the Windows physical adapter case and for the exclusion cases that the old filter tried to protect.
|
||||
+69
-131
@@ -8,6 +8,64 @@ import (
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
)
|
||||
|
||||
type networkInterfaceInfo struct {
|
||||
Name string
|
||||
Flags stdnet.Flags
|
||||
HardwareAddr stdnet.HardwareAddr
|
||||
Addrs []stdnet.Addr
|
||||
}
|
||||
|
||||
func shouldCountNetworkInterface(iface networkInterfaceInfo) bool {
|
||||
if iface.Flags&stdnet.FlagUp == 0 || iface.Flags&stdnet.FlagLoopback != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if isVirtualInterface(iface.Name) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(iface.HardwareAddr) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return hasUsableUnicastIP(iface.Addrs)
|
||||
}
|
||||
|
||||
func buildCountedInterfaceSet(interfaces []networkInterfaceInfo) map[string]bool {
|
||||
countedInterfaces := make(map[string]bool)
|
||||
for _, iface := range interfaces {
|
||||
if shouldCountNetworkInterface(iface) {
|
||||
countedInterfaces[iface.Name] = true
|
||||
}
|
||||
}
|
||||
return countedInterfaces
|
||||
}
|
||||
|
||||
func hasUsableUnicastIP(addrs []stdnet.Addr) bool {
|
||||
for _, addr := range addrs {
|
||||
ip, _, err := stdnet.ParseCIDR(addr.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !ip.IsGlobalUnicast() {
|
||||
continue
|
||||
}
|
||||
|
||||
if ip.IsLinkLocalUnicast() || ip.IsLoopback() || ip.IsMulticast() || ip.IsUnspecified() {
|
||||
continue
|
||||
}
|
||||
|
||||
if isReservedIP(ip) {
|
||||
continue
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func GetNetworkStat() (data *net.IOCountersStat, err error) {
|
||||
networkStats, err := net.IOCounters(true)
|
||||
if err != nil {
|
||||
@@ -36,60 +94,27 @@ func GetNetworkStat() (data *net.IOCountersStat, err error) {
|
||||
totalFifoOut uint64
|
||||
)
|
||||
|
||||
// Create a map of external interface names
|
||||
externalInterfaces := make(map[string]bool)
|
||||
|
||||
// Identify external interfaces
|
||||
interfaceInfos := make([]networkInterfaceInfo, 0, len(interfaces))
|
||||
for _, iface := range interfaces {
|
||||
// Skip down or loopback interfaces
|
||||
if iface.Flags&stdnet.FlagUp == 0 ||
|
||||
iface.Flags&stdnet.FlagLoopback != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip common virtual interfaces by name pattern
|
||||
if isVirtualInterface(iface.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if this is a physical network interface
|
||||
if isPhysicalInterface(iface.Name) && len(iface.HardwareAddr) > 0 {
|
||||
externalInterfaces[iface.Name] = true
|
||||
continue
|
||||
}
|
||||
|
||||
// Get addresses for this interface
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip interfaces without addresses
|
||||
if len(addrs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check for non-private IP addresses
|
||||
for _, addr := range addrs {
|
||||
ip, ipNet, err := stdnet.ParseCIDR(addr.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip virtual, local, multicast, and special purpose IPs
|
||||
if !isRealExternalIP(ip, ipNet) {
|
||||
continue
|
||||
}
|
||||
|
||||
externalInterfaces[iface.Name] = true
|
||||
break
|
||||
}
|
||||
interfaceInfos = append(interfaceInfos, networkInterfaceInfo{
|
||||
Name: iface.Name,
|
||||
Flags: iface.Flags,
|
||||
HardwareAddr: iface.HardwareAddr,
|
||||
Addrs: addrs,
|
||||
})
|
||||
}
|
||||
|
||||
// Accumulate stats only from external interfaces
|
||||
countedInterfaces := buildCountedInterfaceSet(interfaceInfos)
|
||||
|
||||
// Accumulate stats only from counted interfaces
|
||||
for _, stat := range networkStats {
|
||||
if externalInterfaces[stat.Name] {
|
||||
if countedInterfaces[stat.Name] {
|
||||
totalBytesRecv += stat.BytesRecv
|
||||
totalBytesSent += stat.BytesSent
|
||||
totalPacketsRecv += stat.PacketsRecv
|
||||
@@ -139,93 +164,6 @@ func isVirtualInterface(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isPhysicalInterface checks if the interface is a physical network interface
|
||||
// including server, cloud VM, and container physical interfaces
|
||||
func isPhysicalInterface(name string) bool {
|
||||
// Common prefixes for physical network interfaces across different platforms
|
||||
physicalPrefixes := []string{
|
||||
"eth", // Common Linux Ethernet interface
|
||||
"en", // macOS and some Linux
|
||||
"ens", // Predictable network interface names in systemd
|
||||
"enp", // Predictable network interface names in systemd (PCI)
|
||||
"eno", // Predictable network interface names in systemd (on-board)
|
||||
"wlan", // Wireless interfaces
|
||||
"wifi", // Some wireless interfaces
|
||||
"wl", // Shortened wireless interfaces
|
||||
"bond", // Bonded interfaces
|
||||
"em", // Some server network interfaces
|
||||
"p", // Some specialized network cards
|
||||
"lan", // Some network interfaces
|
||||
}
|
||||
|
||||
// Check for exact matches for common primary interfaces
|
||||
if name == "eth0" || name == "en0" || name == "em0" {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check for common physical interface patterns
|
||||
for _, prefix := range physicalPrefixes {
|
||||
if strings.HasPrefix(strings.ToLower(name), prefix) {
|
||||
// Check if the remaining part is numeric or empty
|
||||
suffix := strings.TrimPrefix(strings.ToLower(name), prefix)
|
||||
if suffix == "" || isNumericSuffix(suffix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// isNumericSuffix checks if a string is a numeric suffix or starts with a number
|
||||
func isNumericSuffix(s string) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the first character is a digit
|
||||
if s[0] >= '0' && s[0] <= '9' {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// isRealExternalIP checks if an IP is a genuine external (public) IP
|
||||
func isRealExternalIP(ip stdnet.IP, ipNet *stdnet.IPNet) bool {
|
||||
// Skip if it's not a global unicast address
|
||||
if !ip.IsGlobalUnicast() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Skip private IPs
|
||||
if ip.IsPrivate() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Skip link-local addresses
|
||||
if ip.IsLinkLocalUnicast() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Skip loopback
|
||||
if ip.IsLoopback() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Skip multicast
|
||||
if ip.IsMulticast() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check for special reserved ranges
|
||||
if isReservedIP(ip) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// isReservedIP checks if an IP belongs to special reserved ranges
|
||||
func isReservedIP(ip stdnet.IP) bool {
|
||||
// Handle IPv4
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package analytic
|
||||
|
||||
import (
|
||||
stdnet "net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func mustCIDR(t *testing.T, value string) stdnet.Addr {
|
||||
t.Helper()
|
||||
|
||||
ip, ipNet, err := stdnet.ParseCIDR(value)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse CIDR %q: %v", value, err)
|
||||
}
|
||||
ipNet.IP = ip
|
||||
return ipNet
|
||||
}
|
||||
|
||||
func TestShouldCountNetworkInterfaceAcceptsWindowsEthernetPrivateIPv4(t *testing.T) {
|
||||
iface := networkInterfaceInfo{
|
||||
Name: "Ethernet0",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "10.100.1.10/28")},
|
||||
}
|
||||
|
||||
if !shouldCountNetworkInterface(iface) {
|
||||
t.Fatalf("expected Windows Ethernet interface with private IPv4 to be counted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldCountNetworkInterfaceRejectsTapAdapter(t *testing.T) {
|
||||
iface := networkInterfaceInfo{
|
||||
Name: "TAP-Windows Adapter V9",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0xff, 0x55, 0x61, 0x3a, 0xd2},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "10.8.0.2/24")},
|
||||
}
|
||||
|
||||
if shouldCountNetworkInterface(iface) {
|
||||
t.Fatalf("expected TAP adapter to be excluded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldCountNetworkInterfaceRejectsLinkLocalOnly(t *testing.T) {
|
||||
iface := networkInterfaceInfo{
|
||||
Name: "Ethernet0",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "fe80::c562:f8dc:9cd4:18eb/64")},
|
||||
}
|
||||
|
||||
if shouldCountNetworkInterface(iface) {
|
||||
t.Fatalf("expected link-local-only interface to be excluded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldCountNetworkInterfaceRejectsLoopback(t *testing.T) {
|
||||
iface := networkInterfaceInfo{
|
||||
Name: "Loopback Pseudo-Interface 1",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagLoopback,
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "127.0.0.1/8")},
|
||||
}
|
||||
|
||||
if shouldCountNetworkInterface(iface) {
|
||||
t.Fatalf("expected loopback interface to be excluded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCountedInterfaceSetIncludesOnlyEligibleNames(t *testing.T) {
|
||||
interfaces := []networkInterfaceInfo{
|
||||
{
|
||||
Name: "Ethernet0",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "10.100.1.10/28")},
|
||||
},
|
||||
{
|
||||
Name: "TAP-Windows Adapter V9",
|
||||
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
|
||||
HardwareAddr: stdnet.HardwareAddr{0x00, 0xff, 0x55, 0x61, 0x3a, 0xd2},
|
||||
Addrs: []stdnet.Addr{mustCIDR(t, "10.8.0.2/24")},
|
||||
},
|
||||
}
|
||||
|
||||
counted := buildCountedInterfaceSet(interfaces)
|
||||
if !counted["Ethernet0"] {
|
||||
t.Fatalf("expected Ethernet0 to be counted")
|
||||
}
|
||||
if counted["TAP-Windows Adapter V9"] {
|
||||
t.Fatalf("expected TAP adapter to be excluded")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user