Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/pion/turn/v4 v4.1.1
github.com/stretchr/testify v1.11.1
golang.org/x/net v0.34.0
golang.org/x/sys v0.30.0
)

require (
Expand All @@ -21,7 +22,6 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/wlynxg/anet v0.0.3 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/sys v0.30.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
87 changes: 87 additions & 0 deletions internal/netmon/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package netmon

import (
"fmt"
"net/netip"
"time"
)

// EventType represents the type of network change event.
type EventType int

const (
// InterfaceAdded indicates a new network interface was added.
InterfaceAdded EventType = iota
// InterfaceRemoved indicates a network interface was removed.
InterfaceRemoved
// AddressAdded indicates an IP address was added to an interface.
AddressAdded
// AddressRemoved indicates an IP address was removed from an interface.
AddressRemoved
// StateChanged indicates the operational state of an interface changed.
StateChanged
// LinkChanged indicates link-level changes (e.g., cable plugged/unplugged).
LinkChanged
)

// String returns a string representation of the event type.
func (e EventType) String() string {
switch e {
case InterfaceAdded:
return "InterfaceAdded"
case InterfaceRemoved:
return "InterfaceRemoved"
case AddressAdded:
return "AddressAdded"
case AddressRemoved:
return "AddressRemoved"
case StateChanged:
return "StateChanged"
case LinkChanged:
return "LinkChanged"
default:
return fmt.Sprintf("Unknown(%d)", e)
}
}

// NetworkEvent represents a network change event.
type NetworkEvent struct {
Type EventType // Type of event
Interface NetworkInterface // Affected interface
Timestamp time.Time // When the event occurred
Details map[string]any // Platform-specific details

// Additional fields for specific event types
OldState InterfaceState // Previous state (for StateChanged)
NewState InterfaceState // New state (for StateChanged)
Address netip.Addr // Affected address (for AddressAdded/Removed)
}

// String returns a string representation of the network event.
func (e NetworkEvent) String() string {
switch e.Type {
case InterfaceAdded:
return fmt.Sprintf("[%s] Interface added: %s", e.Timestamp.Format("15:04:05"), e.Interface.Name)
case InterfaceRemoved:
return fmt.Sprintf("[%s] Interface removed: %s", e.Timestamp.Format("15:04:05"), e.Interface.Name)
case AddressAdded:
return fmt.Sprintf("[%s] Address added: %s on %s", e.Timestamp.Format("15:04:05"), e.Address, e.Interface.Name)
case AddressRemoved:
return fmt.Sprintf("[%s] Address removed: %s from %s", e.Timestamp.Format("15:04:05"), e.Address, e.Interface.Name)
case StateChanged:
return fmt.Sprintf(
"[%s] State changed: %s %s -> %s",
e.Timestamp.Format("15:04:05"),
e.Interface.Name,
e.OldState,
e.NewState,
)
case LinkChanged:
return fmt.Sprintf("[%s] Link changed: %s", e.Timestamp.Format("15:04:05"), e.Interface.Name)
default:
return fmt.Sprintf("[%s] %s: %s", e.Timestamp.Format("15:04:05"), e.Type, e.Interface.Name)
}
}
65 changes: 65 additions & 0 deletions internal/netmon/monitor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

// Package netmon provides event-driven network interface monitoring
// across different operating systems.
package netmon

import (
"net/netip"
)

// NetworkMonitor provides platform-specific network change monitoring.
type NetworkMonitor interface {
// Start begins monitoring network changes indefinitely until Close is called
Start() error

// Events returns a channel for network change events
Events() <-chan NetworkEvent

// GetInterfaces returns current network interfaces
GetInterfaces() ([]NetworkInterface, error)

// Close stops monitoring and releases resources
Close() error
}

// NetworkInterface represents a network interface with its properties.
type NetworkInterface struct {
Name string // Interface name (e.g., "eth0", "en0")
Index int // Interface index
Addresses []netip.Addr // IP addresses assigned to this interface
State InterfaceState // Current state of the interface
MTU int // Maximum transmission unit
Flags uint32 // Interface flags (platform-specific)
HWAddr []byte // Hardware address (MAC)
}

// InterfaceState represents the operational state of a network interface.
type InterfaceState int

const (
// StateDown indicates the interface is administratively down.
StateDown InterfaceState = iota
// StateUp indicates the interface is up and operational.
StateUp
// StateUnknown indicates the state cannot be determined.
StateUnknown
)

// String returns a string representation of the interface state.
func (s InterfaceState) String() string {
switch s {
case StateDown:
return "down"
case StateUp:
return "up"
default:
return "unknown"
}
}

// New creates a new NetworkMonitor for the current platform.
func New() NetworkMonitor {
return newPlatformMonitor()
}
Loading
Loading