#!/usr/bin/env python3 """Back up one MTD partition of the GPON stick over telnet, md5-verified. Usage: gpon_backup.py [idle_timeout] [hard_cap] Streams `cat /dev/mtdN | uuencode` over the telnet session and uudecodes locally (Python's uu module was removed in 3.13, so we decode by hand).""" import socket, sys, time, re, hashlib from gpon_env import HOST, PORT, USER, PASS idx = sys.argv[1] outfile = sys.argv[2] idle_to = float(sys.argv[3]) if len(sys.argv)>3 else 12.0 hard_cap = float(sys.argv[4]) if len(sys.argv)>4 else 300.0 def strip_iac(data, outbuf): res=bytearray(); i=0 while iidle: break if time.time()-start>cap: break return buf.decode('latin-1','replace') def send(x): s.sendall(x.encode()+b'\r\n') out=rx(2,8) if re.search(r'(ogin|sername)',out): send(USER); out+=rx(2,6) if re.search(r'assword',out,re.I): send(PASS); out+=rx(2,6) send('system'); rx(1.5,5) send('shell'); rx(1.5,5) send('md5sum /dev/mtd%s'%idx) m=rx(90,150, stop=lambda b: re.search(rb'[0-9a-f]{32}\s+/dev/mtd',b)) mm=re.search(r'([0-9a-f]{32})\s+/dev/mtd%s'%re.escape(idx), m) expected=mm.group(1) if mm else None t0=time.time() send('cat /dev/mtd%s | uuencode p'%idx) def done(b): bi=b.find(b'begin ') return bi>=0 and (b'\nend\r' in b[bi:] or b'\nend\n' in b[bi:]) d=rx(idle_to, hard_cap, stop=done) dt=time.time()-t0 try: s.close() except Exception: pass def uudecode(text): out=bytearray(); started=False for ln in text.split('\n'): ln=ln.rstrip('\r') if not started: if ln.startswith('begin '): started=True continue if ln=='end': break if ln=='' or ln=='`': continue n=(ord(ln[0])-0x20)&0x3f if n<=0: continue data=ln[1:]; dec=bytearray() for i in range(0,len(data),4): g=data[i:i+4]; v=[(ord(c)-0x20)&0x3f for c in g] while len(v)<4: v.append(0) dec.append(((v[0]<<2)|(v[1]>>4))&0xff) dec.append(((v[1]<<4)|(v[2]>>2))&0xff) dec.append(((v[2]<<6)|v[3])&0xff) out.extend(dec[:n]) return bytes(out) raw=uudecode(d) with open(outfile,'wb') as f: f.write(raw) actual=hashlib.md5(raw).hexdigest() print("mtd%s -> %s : %d bytes in %.1fs"%(idx,outfile,len(raw),dt)) print(" expected md5 (stick): %s"%expected) print(" actual md5 (local): %s"%actual) print(" VERIFY: %s"%("OK" if (expected and actual==expected) else "*** MISMATCH / INCOMPLETE ***"))