code wiki / (root) / nx_tracker_url.nx

nx_tracker_url.nx source

↩ module page · 139 lines · 6553 B

1// nx_tracker_url.nx -- parse a BitTorrent tracker URL (from nx_magnet's tr= list) into 2// scheme/host/port/path, the input the announce round-trip needs (resolve host -> IP, dial 3// host:port). Pure/deterministic/sovereign. scheme: udp=1 (BEP-15), http=2, https=3, else 0=reject. 4// Default port by scheme when absent (http=80, https=443, udp=6969); default path "/announce". 5// Self-gating (main = baked KAT). license_tier: ORIGINAL 6// 7// module: nishi-core.torrent.tracker_url 8// depends: nishi-core.sys.syscalls 9// capability: TORRENT_TRACKER_URL_PARSE 10import "nx_syscalls.nx" 11const K_MAGIC_6969: i64 = 6969 12const K_MAGIC_1337: i64 = 1337 13 14func tu_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 15func tu_wn(fd: i64, v: i64) -> i64 { 16 let t: *u8=sys_mmap(28); var m: i64=v; if m<0 {m=0-m; sys_write(fd,"-" as *u8,1)} 17 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} 18 let b: *u8=sys_mmap(28); var i: i64=0; while i<k {b[i]=t[k-1-i]; i=i+1}; sys_write(fd,b,k); return 0 19} 20func tu_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 21// buf[a,..) starts with lit? 22func tu_starts(buf: *u8, a: i64, n: i64, lit: *u8) -> i64 { 23 let ll: i64 = tu_len(lit) 24 if a + ll > n { return 0 } 25 var i: i64 = 0 26 while i < ll { if buf[a+i] != lit[i] { return 0 } i = i + 1 } 27 return 1 28} 29// str equals lit? 30func tu_streq(s: *u8, lit: *u8) -> i64 { 31 var i: i64 = 0 32 while s[i] != (0 as u8) { if s[i] != lit[i] { return 0 } i = i + 1 } 33 if lit[i] != (0 as u8) { return 0 } 34 return 1 35} 36 37// parse url -> scheme_id (ret), host (out), port (out), path (out). 0 = unknown/invalid scheme. 38func tu_parse(url: *u8, port_out: *i64, host: *u8, path: *u8) -> i64 { 39 let n: i64 = tu_len(url) 40 var scheme: i64 = 0 41 var rest: i64 = 0 42 if tu_starts(url, 0, n, "udp://" as *u8) == 1 { scheme = 1; rest = 6 } 43 if tu_starts(url, 0, n, "http://" as *u8) == 1 { scheme = 2; rest = 7 } 44 if tu_starts(url, 0, n, "https://" as *u8) == 1 { scheme = 3; rest = 8 } 45 if scheme == 0 { return 0 } 46 // host = [rest, until ':' or '/' or end) 47 var i: i64 = rest 48 var h: i64 = 0 49 while i < n { if url[i] == (58 as u8) { i = n + 1 } else { if url[i] == (47 as u8) { i = n + 2 } else { host[h] = url[i]; h = h + 1; i = i + 1 } } } 50 host[h] = 0 as u8 51 // default port by scheme 52 var port: i64 = K_MAGIC_6969 53 if scheme == 2 { port = 80 } 54 if scheme == 3 { port = 443 } 55 // re-scan from rest+h to find ':' (explicit port) and '/' (path) 56 var p: i64 = rest + h 57 if p < n { if url[p] == (58 as u8) { 58 // explicit port digits 59 var pv: i64 = 0 60 var any: i64 = 0 61 p = p + 1 62 // FLAG-TERMINATED, not cursor-sentinel. This previously exited with `p = n + 5` and then 63 // "restored" with `p = p - 5`, which lands on n -- the LIMIT -- never on the '/' index the 64 // comment claimed. Nothing read p afterwards, so it cost nothing here; it was a loaded trap 65 // for whoever used p next. ★★★★★ A LOOP THAT BREAKS BY CLOBBERING ITS OWN CURSOR CANNOT ALSO 66 // REPORT WHERE IT STOPPED -- separate cursor, explicit flag. 67 var pdone: i64 = 0 68 while pdone == 0 { 69 if p >= n { pdone = 1 } 70 if pdone == 0 { 71 if url[p] == (47 as u8) { pdone = 1 } else { 72 let c: i64 = url[p] as i64 73 if c >= 48 { if c <= 57 { pv = pv*10 + (c-48); any = 1 } } 74 p = p + 1 75 } 76 } 77 } 78 if any == 1 { port = pv } 79 } } 80 port_out[0] = port 81 // path = from the FIRST '/' after the authority to end; else "/announce" 82 var sp: i64 = rest 83 var slashpos: i64 = 0 - 1 84 while sp < n { if url[sp] == (47 as u8) { slashpos = sp; sp = n + 100 } else { sp = sp + 1 } } 85 if slashpos >= 0 { 86 var k: i64 = 0 87 var q: i64 = slashpos 88 while q < n { path[k] = url[q]; k = k + 1; q = q + 1 } 89 path[k] = 0 as u8 90 } else { 91 path[0]=47 as u8; path[1]=97 as u8; path[2]=110 as u8; path[3]=110 as u8; path[4]=111 as u8; path[5]=117 as u8; path[6]=110 as u8; path[7]=99 as u8; path[8]=101 as u8; path[9]=0 as u8 // "/announce" 92 } 93 return scheme 94} 95 96func main() -> i64 { 97 let host: *u8 = sys_mmap(512) 98 let path: *u8 = sys_mmap(512) 99 let port: *i64 = sys_mmap(16) as *i64 100 101 // pos1: udp with explicit port + path 102 let s1: i64 = tu_parse("udp://tracker.opentrackr.org:1337/announce" as *u8, port, host, path) 103 var pos1: i64 = 0 104 if s1 == 1 { if port[0] == K_MAGIC_1337 { if tu_streq(host, "tracker.opentrackr.org" as *u8) == 1 { if tu_streq(path, "/announce" as *u8) == 1 { pos1 = 1 } } } } 105 106 // pos2: http with explicit port 107 let s2: i64 = tu_parse("http://torrent.ubuntu.com:6969/announce" as *u8, port, host, path) 108 var pos2: i64 = 0 109 if s2 == 2 { if port[0] == K_MAGIC_6969 { if tu_streq(host, "torrent.ubuntu.com" as *u8) == 1 { pos2 = 1 } } } 110 111 // pos3: https, no explicit port -> default 443; path "/x" 112 let s3: i64 = tu_parse("https://tracker.example/x" as *u8, port, host, path) 113 var pos3: i64 = 0 114 if s3 == 3 { if port[0] == 443 { if tu_streq(host, "tracker.example" as *u8) == 1 { if tu_streq(path, "/x" as *u8) == 1 { pos3 = 1 } } } } 115 116 // pos4: udp, no port, no path -> default 6969 + "/announce" 117 let s4: i64 = tu_parse("udp://t.example" as *u8, port, host, path) 118 var pos4: i64 = 0 119 if s4 == 1 { if port[0] == K_MAGIC_6969 { if tu_streq(host, "t.example" as *u8) == 1 { if tu_streq(path, "/announce" as *u8) == 1 { pos4 = 1 } } } } 120 121 // neg1: unknown scheme 122 var neg1: i64 = 0 123 if tu_parse("ftp://x:1/y" as *u8, port, host, path) == 0 { neg1 = 1 } 124 // neg2: no scheme 125 var neg2: i64 = 0 126 if tu_parse("tracker.example:80/announce" as *u8, port, host, path) == 0 { neg2 = 1 } 127 128 tu_w(1, "TRACKERURL-GATE authored=organ pos1_udp=" as *u8); tu_wn(1, pos1) 129 tu_w(1, " pos2_http=" as *u8); tu_wn(1, pos2) 130 tu_w(1, " pos3_https_defport=" as *u8); tu_wn(1, pos3) 131 tu_w(1, " pos4_noport_nopath=" as *u8); tu_wn(1, pos4) 132 tu_w(1, " neg1_badscheme=" as *u8); tu_wn(1, neg1) 133 tu_w(1, " neg2_noscheme=" as *u8); tu_wn(1, neg2) 134 var ok: i64 = 0 135 if pos1==1 { if pos2==1 { if pos3==1 { if pos4==1 { if neg1==1 { if neg2==1 { ok = 1 } } } } } } 136 if ok == 1 { tu_w(1, " verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 137 tu_w(1, " verdict=RED\n" as *u8); sys_exit(1) 138 return 1 139}