code wiki / (root) / nx_stun_client_gate.nx

nx_stun_client_gate.nx source

↩ module page · 133 lines · 6871 B

1// nx_stun_client_gate.nx -- proves the sovereign STUN client two ways: 2// PART A (pure): sc_find_xma walks a real STUN response (RFC 5769 2.2, where XOR-MAPPED-ADDRESS is NOT the 3// first attribute) and locates it, decoding 192.0.2.1:32853; a response with no XMA returns -1; the 4// dotted-quad parser accepts valid IPs and rejects malformed ones. 5// PART B (LIVE, real UDP): a fork loopback -- child = an inline reflexive responder, parent = sc_query -- 6// proves sc_query performs a real Binding request/response round-trip and RECOVERS a reflexive address. 7// The server side is inlined from nx_stun primitives (not imported) to avoid a diamond import of nx_stun. 8// license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_stun_client.nx" 11 12func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 13func gn(v: i64) -> i64 { 14 let b: *u8=sys_mmap(28); var m: i64=v; if m<0 {sys_write(1,"-" as *u8,1); m=0-m} 15 let t: *u8=sys_mmap(28); var k: i64=0; if m==0 {t[0]=48 as u8;k=1} while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} 16 var i: i64=0; while i<k {b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 17} 18func gck(pass: i64, name: *u8, fails: *i64) -> i64 { 19 if pass==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8); fails[0]=fails[0]+1 } 20 gw(name); gw("\n" as *u8); return 0 21} 22func hxv(c: i64) -> i64 { 23 if c>=48 { if c<=57 { return c-48 } } 24 if c>=97 { if c<=102 { return c-87 } } 25 if c>=65 { if c<=70 { return c-55 } } 26 return 0 27} 28func hexdec(hex: *u8, nbytes: i64, out: *u8) -> i64 { var i: i64=0; while i<nbytes { out[i]=((hxv(hex[i*2] as i64)<<4) | hxv(hex[i*2+1] as i64)) as u8; i=i+1 } return 0 } 29 30// inline reflexive responder (server child): build header + XOR-MAPPED-ADDRESS(src) + FINGERPRINT. 31func g_respond(buf: *u8, txid: *u8, port: i64, addr: i64) -> i64 { 32 var o: i64 = st_write_header(buf, STUN_BINDING_RESPONSE, 0, txid) 33 st_put16(buf, o, STUN_ATTR_XOR_MAPPED_ADDRESS); st_put16(buf, o+2, 8) 34 let xp: *u8 = (buf as i64 + o + 4) as *u8 35 st_xma_encode(xp, port, addr) 36 o = o + 12 37 st_put16(buf, 2, (o-20)+8) 38 let fp: i64 = st_fingerprint(buf, o) 39 st_put16(buf, o, STUN_ATTR_FINGERPRINT); st_put16(buf, o+2, 4); st_put32(buf, o+4, fp) 40 return o + 8 41} 42 43const CGT_SPORT: i64 = 53230 44 45func main() -> i64 { 46 let fails: *i64 = sys_mmap(16) as *i64 47 fails[0]=0 48 gw("=== nx_stun_client_gate -- sovereign STUN client (pure XMA-walk + live UDP query) ===\n" as *u8) 49 50 // ---- PART A ---- 51 // A1: sc_find_xma on the RFC 5769 2.2 response (XMA is the SECOND attribute, after SOFTWARE) 52 let resp: *u8 = sys_mmap(128) 53 hexdec("0101003c2112a442b7e7a701bc34d686fa87dfae8022000b7465737420766563746f7220002000080001a147e112a643000800142b91f599fd9e90c38c7489f92af9ba53f06be7d780280004c07d4c96" as *u8, 80, resp) 54 var t1: i64=1 55 let xoff: i64 = sc_find_xma(resp, 80) 56 if xoff != 40 { t1=0 } 57 if xoff >= 0 { 58 let xma: *u8 = (resp as i64 + xoff) as *u8 59 if st_xma_port(xma) != 32853 { t1=0 } 60 if st_xma_addr(xma) != 0xC0000201 { t1=0 } 61 } 62 gck(t1, "A1 sc_find_xma locates XOR-MAPPED-ADDRESS past SOFTWARE -> 192.0.2.1:32853 (RFC 5769 2.2)" as *u8, fails) 63 64 // A2: a response with no XMA (header only) -> -1 65 var t2: i64=1 66 let bare: *u8 = sys_mmap(32) 67 let txz: *u8 = sys_mmap(16); var zi: i64=0; while zi<12 { txz[zi]=0 as u8; zi=zi+1 } 68 st_write_header(bare, STUN_BINDING_RESPONSE, 0, txz) 69 if sc_find_xma(bare, 20) != (0-1) { t2=0 } 70 gck(t2, "A2 sc_find_xma returns -1 when no XOR-MAPPED-ADDRESS is present" as *u8, fails) 71 72 // A3: dotted-quad parser 73 var t3: i64=1 74 let oct: *i64 = sys_mmap(64) as *i64 75 if cp_parse_ip("203.0.113.7" as *u8, oct)!=1 { t3=0 } 76 if oct[0]!=203 { t3=0 } 77 if oct[1]!=0 { t3=0 } 78 if oct[2]!=113 { t3=0 } 79 if oct[3]!=7 { t3=0 } 80 if cp_parse_ip("1.2.3" as *u8, oct)!=0 { t3=0 } // too few octets 81 if cp_parse_ip("256.0.0.1" as *u8, oct)!=0 { t3=0 } // octet out of range 82 if cp_parse_ip("1.2.3.4.5" as *u8, oct)!=0 { t3=0 } // too many 83 gck(t3, "A3 dotted-quad parser accepts valid IPv4 + rejects malformed" as *u8, fails) 84 85 // ---- PART B: LIVE UDP query (fork loopback; bind server BEFORE fork) ---- 86 var t4: i64=1 87 let ssa: *u8 = sys_mmap(16) 88 ssa[0]=2 as u8; ssa[1]=0 as u8; ssa[2]=((CGT_SPORT>>8)&0xff) as u8; ssa[3]=(CGT_SPORT&0xff) as u8 89 ssa[4]=127 as u8; ssa[5]=0 as u8; ssa[6]=0 as u8; ssa[7]=1 as u8 90 var pk: i64=8; while pk<16 { ssa[pk]=0 as u8; pk=pk+1 } 91 let sfd: i64 = sys_socket(AF_INET, SOCK_DGRAM, 0) 92 var bound: i64=0 93 if sfd>=0 { sys_set_socket_timeout(sfd, 3); if sys_bind(sfd, ssa, 16)>=0 { bound=1 } } 94 if bound==0 { gck(0, "B live bind server 127.0.0.1:53230" as *u8, fails) } else { 95 let pid: i64 = sys_fork() 96 if pid==0 { 97 // CHILD = inline reflexive responder 98 let rb: *u8 = sys_mmap(2048) 99 let rout: *u8 = sys_mmap(2048) 100 let csrc: *u8 = sys_mmap(16) 101 let cslen: *i64 = sys_mmap(16) as *i64; cslen[0]=16 102 let cn: i64 = sys_recvfrom(sfd, rb, 2048, 0, csrc, cslen) 103 if cn>=20 { 104 let sport: i64 = (((csrc[2] as i64)&0xff)<<8) | ((csrc[3] as i64)&0xff) 105 let saddr: i64 = (((csrc[4] as i64)&0xff)<<24) | (((csrc[5] as i64)&0xff)<<16) | (((csrc[6] as i64)&0xff)<<8) | ((csrc[7] as i64)&0xff) 106 let txid: *u8 = (rb as i64 + 8) as *u8 107 let rrn: i64 = g_respond(rout, txid, sport, saddr) 108 sys_sendto(sfd, rout, rrn, 0, csrc, cslen[0]) 109 } 110 sys_close(sfd) 111 sys_exit(0) 112 } 113 // PARENT = sc_query against the loopback server 114 let oip: *i64 = sys_mmap(16) as *i64 115 let oport: *i64 = sys_mmap(16) as *i64 116 let rc: i64 = sc_query(127, 0, 0, 1, CGT_SPORT, oip, oport) 117 let st: *i64 = sys_mmap(16) as *i64 118 sys_wait4(pid, st, 0) 119 if rc != 0 { t4=0 } 120 if oip[0] != 0x7F000001 { t4=0 } // reflexive IP is our loopback 121 if oport[0] <= 0 { t4=0 } // and a real (ephemeral) port 122 gw(" [measure] LIVE sc_query rc=" as *u8); gn(rc); gw(" reflexive=" as *u8) 123 let a: i64 = oip[0] 124 gn((a>>24)&0xff); gw("." as *u8); gn((a>>16)&0xff); gw("." as *u8); gn((a>>8)&0xff); gw("." as *u8); gn(a&0xff); gw(":" as *u8); gn(oport[0]); gw("\n" as *u8) 125 gck(t4, "B4 LIVE UDP: sc_query round-trips a Binding request/response and recovers reflexive 127.0.0.1:<port>" as *u8, fails) 126 } 127 128 gw(" fails=" as *u8); gn(fails[0]); gw("\n" as *u8) 129 if fails[0]==0 { gw("VERDICT: verdict=GREEN (sovereign STUN client discovers reflexive addresses over real UDP)\n" as *u8); sys_exit(0) } 130 gw("VERDICT: verdict=RED\n" as *u8) 131 sys_exit(1) 132 return 1 133}