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) }