code wiki / _hdl_build / nx_cidr.nx
nx_cidr.nx source
↩ module page · 64 lines · 3389 B
1// nx_cidr.nx -- CIDR longest-prefix matching for the access-provisioning wall (the network-tier + IP-allowlist
2// layers). Pure logic over caller rule arrays; reuses nx_ipaddr (ipv4_parse) for string parsing -- aligns with
3// the existing net stack, does NOT reinvent IP parsing. Used by nx_nettier (PUBLIC/LAN/VPN classification) and
4// any per-area IP allowlist. license_tier: ORIGINAL
5import "nx_ipaddr.nx"
6import "nx_syscalls.nx"
7
8// 32-bit network mask for a prefix length 0..32 (high `prefix` bits set), as a u32 in i64.
9func cidr_mask(prefix: i64) -> i64 {
10 if prefix <= 0 { return 0 }
11 if prefix >= 32 { return 0xffffffff }
12 let shift: i64 = 32 - prefix
13 return (0xffffffff << shift) & 0xffffffff
14}
15
16// is ip (u32 in i64) within netw/prefix? 1/0.
17func cidr_match(ip: i64, netw: i64, prefix: i64) -> i64 {
18 let m: i64 = cidr_mask(prefix)
19 if (ip & m) == (netw & m) { return 1 }
20 return 0
21}
22
23// LONGEST-PREFIX tier lookup over parallel arrays nets[]/prefixes[]/tiers[] (n rules): the most-specific
24// matching rule wins; no match -> default_tier (the deny-by-default analog for trust: caller passes the
25// least-trusted tier as the default). Mirrors nx_vault_acl's longest-prefix discipline.
26func cidr_tier(ip: i64, nets: *i64, prefixes: *i64, tiers: *i64, n: i64, default_tier: i64) -> i64 {
27 var best_prefix: i64 = 0 - 1
28 var best_tier: i64 = default_tier
29 var i: i64 = 0
30 while i < n {
31 if cidr_match(ip, nets[i], prefixes[i]) == 1 {
32 if prefixes[i] > best_prefix { best_prefix = prefixes[i]; best_tier = tiers[i] }
33 }
34 i = i + 1
35 }
36 return best_tier
37}
38
39// parse "a.b.c.d" -> u32 (convenience over nx_ipaddr ipv4_parse). negative on malformed.
40func cidr_ip(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return ipv4_parse(s, n) }
41
42// ---- MERGED from the former runtime/ nx_cidr (so the unified lib keeps notation-parsing too; no functionality
43// lost, no sprawl). RFC 4632: host bits in the network address are ignored on parse; canonicalize masks them. ----
44const CIDR_ERR_FORMAT: i64 = 0 - 1
45const CIDR_ERR_BAD_PREFIX: i64 = 0 - 2
46
47// parse "a.b.c.d/N" -> ip (u32) + prefix via ip_out[0]/prefix_out[0]. 0 ok, negative CIDR_ERR_* / ipv4_parse err.
48func cidr_parse(s: *u8, n: i64, ip_out: *i64, prefix_out: *i64) -> i64 {
49 var slash: i64 = 0 - 1; var i: i64 = 0
50 while i < n { if (s[i] as i64) == 47 { slash = i; i = n } else { i = i + 1 } }
51 if slash < 0 { return CIDR_ERR_FORMAT }
52 let ip_val: i64 = ipv4_parse(s, slash)
53 if ip_val < 0 { return ip_val }
54 var prefix: i64 = 0; var j: i64 = slash + 1; var saw: i64 = 0
55 while j < n { let c: i64 = s[j] as i64; if c < 48 { return CIDR_ERR_BAD_PREFIX } if c > 57 { return CIDR_ERR_BAD_PREFIX } prefix = prefix * 10 + (c - 48); saw = 1; j = j + 1 }
56 if saw == 0 { return CIDR_ERR_BAD_PREFIX }
57 if prefix > 32 { return CIDR_ERR_BAD_PREFIX }
58 ip_out[0] = ip_val & 0xFFFFFFFF; prefix_out[0] = prefix
59 return 0
60}
61// canonicalize: clear host bits -> the network address.
62func cidr_network_address(ip: i64, prefix: i64) -> i64 { return (ip & cidr_mask(prefix)) & 0xFFFFFFFF }
63// containment by (network, prefix, addr) arg order -- preserves the former runtime API as an alias of cidr_match.
64func cidr_contains(network: i64, prefix: i64, addr: i64) -> i64 { return cidr_match(addr, network, prefix) }