Documentation
¶
Overview ¶
Package procnetroute reads the Linux IPv4 routing table from /proc/net/route.
This package is in builtins/internal/ and is therefore exempt from the builtinAllowedSymbols allowlist check. It may use OS-specific APIs freely.
Sandbox bypass ¶
ReadRoutes intentionally bypasses the AllowedPaths sandbox (callCtx.OpenFile) and calls os.Open directly. This is safe because procPath is always a kernel-managed pseudo-filesystem root (/proc by default) that is hardcoded by the caller — it is never derived from user-supplied input and cannot be redirected by a shell script. The caller is responsible for ensuring that procPath remains a safe, non-user-controlled path.
/proc/net/route format (tab-separated, one route per line after the header):
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT eth0 00000000 0101A8C0 0003 0 0 100 00000000 0 0 0
All IP fields are little-endian uint32 hex: 192.168.1.1 is encoded as 0x0101A8C0 (first octet in the least-significant byte).
Index ¶
Constants ¶
const ( FlagUp = uint32(0x0001) // RTF_UP FlagGateway = uint32(0x0002) // RTF_GATEWAY FlagReject = uint32(0x0200) // RTF_REJECT — kernel will refuse to route to this destination )
Routing-table flags (from linux/route.h).
const DefaultProcPath = procpath.Default
DefaultProcPath is the default proc filesystem root. ReadRoutes appends "net/route" to this path to locate the routing table.
const MaxLineBytes = 1 << 20 // 1 MiB
MaxLineBytes is the per-line buffer cap for the route-table scanner. If any line in the route file exceeds this limit the scanner returns bufio.ErrTooLong and ReadRoutes returns an error; processing is aborted rather than allowing unbounded allocation.
const MaxRoutes = 10_000
MaxRoutes caps the number of UP route entries retained in memory to prevent memory exhaustion.
const MaxTotalLines = MaxRoutes * 10 // 100 000 lines
MaxTotalLines caps the total number of lines (UP + non-UP + malformed) scanned per ReadRoutes call. This bounds CPU time for pathological /proc/net/route files with many non-UP/malformed lines before MaxRoutes UP entries are found. MaxRoutes is the memory guard; MaxTotalLines is the scan-time guard.
Variables ¶
var ErrMaxRoutes = errors.New("procnetroute: route table truncated: exceeded MaxRoutes limit")
ErrMaxRoutes is returned by readRoutes when the route table exceeds MaxRoutes UP entries. Callers should treat this as a hard failure: the route table was truncated and any LPM result derived from partial data may be incorrect.
var ErrMaxTotalLines = errors.New("procnetroute: route table truncated: exceeded MaxTotalLines limit")
ErrMaxTotalLines is returned by readRoutes when more than MaxTotalLines lines are scanned. Callers should treat this as a hard failure: the route table was truncated and any LPM result derived from partial data may be incorrect.
Functions ¶
func HexToIPStr ¶
HexToIPStr converts a /proc/net/route little-endian uint32 to dotted-decimal. The encoding stores the first octet in the least-significant byte: 192.168.1.1 is encoded as 0x0101A8C0, and HexToIPStr(0x0101A8C0) = "192.168.1.1".
func IsContiguousMask ¶
IsContiguousMask reports whether v is a valid CIDR subnet mask in the little-endian encoding used by /proc/net/route, where the first octet is stored in the least-significant byte. For example:
- /24 (255.255.255.0) is stored as 0x00FFFFFF
- /25 (255.255.255.128) is stored as 0x80FFFFFF
- /28 (255.255.255.240) is stored as 0xF0FFFFFF
Non-contiguous masks (e.g. 0xF0F0F0F0) are not valid CIDR prefixes and would produce misleading output from LongestPrefixMatch and formatRoute.
Types ¶
type Route ¶
Route holds a parsed entry from /proc/net/route. IP fields use the same little-endian uint32 encoding as /proc/net/route: for 192.168.1.1 the stored value is 0x0101A8C0 and HexToIPStr(0x0101A8C0) returns "192.168.1.1".
func LongestPrefixMatch ¶
LongestPrefixMatch returns the route that best matches addr by longest-prefix-match with metric as a tie-breaker (lower metric wins), or nil if no route matches.
func ReadRoutes ¶
ReadRoutes opens procPath/net/route and returns all UP route entries. procPath is the proc filesystem root (e.g. DefaultProcPath or a test override). It is implemented on Linux and returns an error on other platforms.
Sandbox bypass: this function calls os.Open directly, bypassing the AllowedPaths sandbox enforced by callCtx.OpenFile. This is intentional — procPath must always be a safe, hardcoded kernel pseudo-filesystem path (e.g. /proc) that is not controllable from user scripts. Never pass a path derived from user input.
Safety invariants:
(a) /proc-prefix requirement: all callers MUST pass a path that starts with
/proc. No runtime assertion enforces this — tests override procPath with
a temp-directory tree to inject synthetic route data, so a /proc-prefix
check would break those tests. This invariant is caller-enforced only.
(b) No ".." components: enforced at runtime by the strings.Contains check
below. The check is applied to the ORIGINAL path (before filepath.Clean)
so traversal sequences like "/proc/../etc/passwd" are caught — after
Clean, such a path becomes "/etc/passwd" and no longer contains "..".
Temp-directory overrides used by tests never contain "..".
Note: the check is deliberately conservative: any path whose component
names happen to contain ".." as a substring (e.g. "/proc..backup") is
also rejected. This is a theoretical false-positive that never occurs in
practice since procPath is always "/proc" or a t.TempDir() path.