Files
archy/scripts/tests/c01_nts_disposable.py

64 lines
2.8 KiB
Python

#!/usr/bin/python3
"""Fresh native NTS observation with fixed-source, destination-limited egress."""
import ctypes
import hashlib
import json
import os
from pathlib import Path
import pwd
import socket
import subprocess
import sys
import time
assert os.geteuid()==0 and Path('/run/.containerenv').exists()
assert socket.gethostname()=='c01-nts-composed'
root=Path('/opt/c01-nts')
sys.path.insert(0,str(root))
import c01_nts
subprocess.run(['/usr/sbin/nft','-f',str(root/'egress.nft')],check=True)
policy=c01_nts.Policy(frozenset({'time.cloudflare.com','nts.netnod.se'}))
c01_nts.CONFIG.parent.mkdir(parents=True,exist_ok=True)
c01_nts.CONFIG.write_bytes(c01_nts.configuration(policy))
c01_nts.CONFIG.chmod(0o644)
account=pwd.getpwnam(c01_nts.OBSERVER_USER)
c01_nts.SOCKET.parent.mkdir(mode=0o700,exist_ok=True)
os.chown(c01_nts.SOCKET.parent,account.pw_uid,account.pw_gid)
c01_nts.SOCKET.parent.chmod(0o700)
libc=ctypes.CDLL(None)
def no_privileges():
if libc.prctl(38,1,0,0,0)!=0: os._exit(111)
log=(root/'chronyd.log').open('wb')
daemon=subprocess.Popen([str(c01_nts.CHRONYD),'-x','-U','-n','-u',c01_nts.OBSERVER_USER,
'-f',str(c01_nts.CONFIG)],env={'PATH':'/usr/bin:/bin','LC_ALL':'C'},stdout=log,stderr=log,
preexec_fn=no_privileges)
failures=[]
try:
end=time.monotonic()+240
while time.monotonic()<end:
assert daemon.poll() is None, 'dedicated observer exited'
result=subprocess.run(['/usr/local/bin/archipelago','c01-observe-nts-v1'],capture_output=True,text=True,timeout=10)
if result.returncode==0:
observation=json.loads(result.stdout)
status=Path(f'/proc/{daemon.pid}/status').read_text()
fields=dict(line.split(':',1) for line in status.splitlines() if ':' in line)
assert fields['NoNewPrivs'].strip()=='1'
assert all(int(fields[k],16)&(1<<25)==0 for k in ('CapEff','CapPrm','CapAmb'))
record={'observation':observation,'native_sha256':hashlib.sha256(Path('/usr/local/bin/archipelago').read_bytes()).hexdigest(),
'prior_refusals':failures,'daemon_no_new_privileges':True,'daemon_has_sys_time':False,
'recovery_grant_issued':False,'platform_suspend_qualified':False,
'egress_rules':subprocess.check_output(['/usr/sbin/nft','list','ruleset'],text=True)}
(root/'result.json').write_text(json.dumps(record,indent=2)+'\n')
print(json.dumps(record),flush=True)
break
failures.append(result.stderr[-2000:])
time.sleep(4)
else:
(root/'result.json').write_text(json.dumps({'status':'unavailable','failures':failures},indent=2)+'\n')
raise RuntimeError('fresh native NTS observation unavailable within240s')
finally:
daemon.terminate()
daemon.wait(timeout=10)
log.close()