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}