code wiki / (root) / nx_antibot_gate.nx

nx_antibot_gate.nx source

↩ module page · 107 lines · 7553 B

1// nx_antibot_gate.nx -- GATE for nx_antibot (the /compare/webscraping R4 contract abt_classify). Network-free; 2// specimens assembled at runtime from the marker rows' own vocabulary. The accept rule pre-declared on the board: 3// vendor challenge pages are named by vendor; a long article that MENTIONS captcha / Cloudflare / Access Denied reads 4// CLEAN (the false-positive control, because a wall verdict costs the index a page); 429 is a rate limit; 403 with a 5// body is a status block; an empty 200 is its own class, never a wall. 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_antibot.nx" 9import "nx_gate_verdict.nx" 10 11const AG_CAP: i64 = 65536 12 13func ag_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 14func ag_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } d[p] = 0 as u8; return p } 15func ag_vendor_is(v: *u8) -> i64 { 16 let vl: i64 = ag_len(v) 17 if vl != abt_last_vendor_len_g { return 0 } 18 var i: i64 = 0 19 while i < vl { if abt_last_vendor_g[i] != v[i] { return 0 } i = i + 1 } 20 return 1 21} 22func ag_cls(status: i64, s: *u8) -> i64 { return abt_classify(status, s, ag_len(s)) } 23 24func main() -> i64 { 25 gv_head("=== nx_antibot gate (bot-wall classification from marker rows, network-free) ===" as *u8) 26 let ctr: *i64 = gv_ctr() 27 let nr: i64 = abt_reload() 28 gv_puts(" markers=" as *u8); gv_num(nr); gv_puts(" malformed=" as *u8); gv_num(abt_nrows_bad_g) 29 gv_puts(" small_page_bytes=" as *u8); gv_num(abt_small_bytes_g); gv_puts(" shell_max_text=" as *u8); gv_num(abt_shell_max_text_g) 30 gv_puts(" conf_src=" as *u8); if abt_conf_src_g == 1 { gv_puts("file" as *u8) } else { gv_puts("defaults" as *u8) } gv_puts("\n" as *u8) 31 gv_subjects("marker-rows" as *u8, nr, ctr) 32 var t0: i64 = 0 33 if abt_nrows_bad_g == 0 { t0 = 1 } 34 gv_check("T0 every marker row parses (a malformed row is a missing wall, announced)" as *u8, t0, ctr) 35 36 // ---- vendor specimens (tier 1, any size) ---- 37 let cf: *u8 = "<html><head><title>Just a moment...</title></head><body><form id=\"challenge-form\" action=\"/x?__cf_chl_f_tk=abc\"><script src=\"/cdn-cgi/challenge-platform/h/b/orchestrate/jsch/v1\"></script></form></body></html>" as *u8 38 let c1: i64 = ag_cls(503, cf) 39 var t1: i64 = 0 40 if c1 == ABT_VENDOR_WALL { if ag_vendor_is("cloudflare" as *u8) == 1 { t1 = 1 } } 41 gv_check("T1 a Cloudflare challenge page -> VENDOR-WALL named cloudflare" as *u8, t1, ctr) 42 let ak: *u8 = "<html><body><h1>Pardon Our Interruption</h1><p>As you were browsing something about your browser made us think you were a bot.</p></body></html>" as *u8 43 var t2: i64 = 0 44 if ag_cls(200, ak) == ABT_VENDOR_WALL { if ag_vendor_is("akamai" as *u8) == 1 { t2 = 1 } } 45 gv_check("T2 an Akamai interruption page -> VENDOR-WALL named akamai, even on a 200" as *u8, t2, ctr) 46 let px: *u8 = "<html><head><script>window._pxAppId='PX1234';</script></head><body></body></html>" as *u8 47 var t3: i64 = 0 48 if ag_cls(403, px) == ABT_VENDOR_WALL { if ag_vendor_is("perimeterx" as *u8) == 1 { t3 = 1 } } 49 gv_check("T3 a PerimeterX block -> VENDOR-WALL named perimeterx" as *u8, t3, ctr) 50 let dd: *u8 = "<html><body><script src=\"https://ct.captcha-delivery.com/c.js\"></script></body></html>" as *u8 51 var t4: i64 = 0 52 if ag_cls(403, dd) == ABT_VENDOR_WALL { if ag_vendor_is("datadome" as *u8) == 1 { t4 = 1 } } 53 gv_check("T4 a DataDome captcha page -> VENDOR-WALL named datadome" as *u8, t4, ctr) 54 let an: *u8 = "<html><head><title>Making sure you're not a bot!</title></head><body><img src=\"/.within.website/x/cmd/anubis/static/img/happy.webp\"></body></html>" as *u8 55 var t5: i64 = 0 56 if ag_cls(200, an) == ABT_VENDOR_WALL { if ag_vendor_is("anubis" as *u8) == 1 { t5 = 1 } } 57 gv_check("T5 an Anubis proof-of-work interstitial -> VENDOR-WALL named anubis" as *u8, t5, ctr) 58 59 // ---- status rules ---- 60 var t6: i64 = 0 61 if ag_cls(429, "<html><body>slow down</body></html>" as *u8) == ABT_RATE_LIMIT { t6 = 1 } 62 gv_check("T6 HTTP 429 -> RATE-LIMIT regardless of body" as *u8, t6, ctr) 63 var t7: i64 = 0 64 if ag_cls(403, "<html><body><p>Forbidden by policy on this host.</p></body></html>" as *u8) == ABT_STATUS_BLOCK { t7 = 1 } 65 gv_check("T7 HTTP 403 with an HTML body and no marker -> STATUS-BLOCK (vendor unknown, not invented)" as *u8, t7, ctr) 66 var t7b: i64 = 0 67 if ag_cls(403, "" as *u8) != ABT_STATUS_BLOCK { t7b = 1 } 68 gv_check("T7b HTTP 403 with NO body is not a status block (nothing to classify)" as *u8, t7b, ctr) 69 70 // ---- generic tier only on SHORT or error bodies ---- 71 let shortden: *u8 = "<html><body><h1>Access Denied</h1><p>You don't have permission to access this resource.</p></body></html>" as *u8 72 var t8: i64 = 0 73 if ag_cls(200, shortden) == ABT_GENERIC_WALL { t8 = 1 } 74 gv_check("T8 a short Access Denied page on a 200 -> GENERIC-WALL" as *u8, t8, ctr) 75 76 // ---- FALSE-POSITIVE CONTROL: a long article that talks ABOUT walls must read CLEAN ---- 77 let art: *u8 = sys_mmap(AG_CAP) 78 var o: i64 = 0 79 o = ag_cat(art, o, "<html><head><title>How bot walls work</title></head><body><article>" as *u8) 80 var para: i64 = 0 81 while para < 40 { 82 o = ag_cat(art, o, "<p>Sites deploy a captcha or a CAPTCHA when they suspect automation; Cloudflare, Akamai and DataDome all sell this, and a visitor may see Access Denied, verify you are human, or bot detection notices while the page is still an ordinary article of prose about the mechanism, not a wall itself. " as *u8) 83 o = ag_cat(art, o, "This paragraph exists so the body is long enough that a generic phrase cannot be mistaken for a challenge; a real challenge page is short and structural.</p>\n" as *u8) 84 para = para + 1 85 } 86 o = ag_cat(art, o, "</article></body></html>" as *u8) 87 let cart: i64 = abt_classify(200, art, o) 88 gv_puts(" prose control bytes=" as *u8); gv_num(o); gv_puts(" code=" as *u8); gv_num(cart); gv_puts("\n" as *u8) 89 var t9: i64 = 0 90 if cart == ABT_CLEAN { if o > abt_small_bytes_g { t9 = 1 } } 91 gv_check("T9 FALSE-POSITIVE CONTROL: a long article mentioning captcha, Cloudflare, Access Denied reads CLEAN" as *u8, t9, ctr) 92 gv_bite("T10 BITE: the classifier fires on the short Access Denied page and stays silent on the long article" as *u8, t8, 1 - t9, ctr) 93 94 // ---- empty shell is its own class ---- 95 let shell: *u8 = "<html><head><script src=\"/app.js\"></script></head><body><div id=\"root\"></div></body></html>" as *u8 96 var t11: i64 = 0 97 if ag_cls(200, shell) == ABT_EMPTY_SHELL { t11 = 1 } 98 gv_check("T11 a 200 with no rendered text -> EMPTY-SHELL (a class of its own, never reported as a wall)" as *u8, t11, ctr) 99 var t12: i64 = 0 100 if cart == ABT_CLEAN { if ag_cls(200, "<html><body><p>Hello world content that is short but real.</p></body></html>" as *u8) == ABT_EMPTY_SHELL { t12 = 1 } } 101 gv_check("T12 a short real page under shell_max_text also reads EMPTY-SHELL, and the crawler's thin bar is the same number" as *u8, t12, ctr) 102 var t13: i64 = 0 103 if ag_len(abt_code_name(ABT_VENDOR_WALL)) > 0 { if ag_len(abt_code_name(ABT_CLEAN)) > 0 { t13 = 1 } } 104 gv_check("T13 every code has an outcome-row name" as *u8, t13, ctr) 105 106 return gv_verdict("ANTIBOT-GATE" as *u8, ctr, "walls classified from specimen rows and named by vendor; long prose about walls reads CLEAN; 429 rate-limit, 403 status-block, empty 200 its own class" as *u8) 107}