9.0 KiB
latd ↔ VT1200 — status, instructions & handoff
Current state: latd is STOPPED. No latd, login, osc-filter.py or
tcpdump processes remain; lat/local/run/ is empty. Everything is inside
lat/ — nothing was installed system-wide.
Root of this directory = lat/ (referred to as $LAT below).
$LAT = /home/arti/code/k-space/vt1200/lat
1. Endpoint facts (needed to reproduce)
| Thing | Value |
|---|---|
| VT1200 LAT/Ethernet MAC | 08:00:2b:16:4b:5a |
| VT1200 IP | 100.103.100.103 |
| Host interface on that segment | enp197s0f3u1 (host 100.103.255.254) |
| latd node name | SID (this host's hostname) |
| LAT Ethertype | 0x6004 |
| LAT service-announcement multicast | 09:00:2b:00:00:0f |
Important: the VT1200's LAT Terminal Window connects by default to the
service named after the latd node name (SID), i.e. the node-name service —
not to a service you type, unless you type one explicitly.
2. One-command workflow (lat/run-local.sh)
cd $LAT
sudo ./run-local.sh build # bootstrap + configure + make -> lat/local/build-debug/
sudo ./run-local.sh start # start latd + apply group/service config
sudo ./run-local.sh status # show config + advertised services
sudo ./run-local.sh capture # tcpdump LAT frames to lat/local/capture-*.pcap
sudo ./run-local.sh stop # stop latd
sudo ./run-local.sh restart
Env overrides:
IFACE=enp197s0f3u1 VARIANT=debug sudo -E ./run-local.sh start
# IFACE interface latd uses (default enp197s0f3u1)
# VARIANT release|debug (default debug; debug = verbose, -DNO_FORK)
build writes its output to lat/local/build.log.
start writes the verbose latd log to lat/local/latd.log.
What start does
-
setsid latcp -s -d -v -v -i $IFACE(foreground/verbose latd, detached) -
latcp -m 10— advertise every 10 s -
latcp -G 1— advertise in group 1 (must match the VT1200's group code) -
removes the default
SIDservice, then re-addsSIDandVT1200both running$LAT/tools/osc-filter.pyThe default service that latd creates at startup is named after the node (
SID) and runs/bin/loginunfiltered — it must be replaced, or the VT1200 will freeze on it.latcp -Aon an existing name fails ("Local service already exists"), sostartdeletes it first.
3. Manual equivalent (exactly how it was run by hand)
All commands run as root (sudo). BUILD below is the chosen build dir.
Build
cd $LAT/code/latd && ./bootstrap.sh # only once; needs autoconf+automake
# release build
mkdir -p $LAT/local/build && cd $LAT/local/build
../../code/latd/configure \
--with-latcp-socket=$LAT/local/run/latcp \
--with-llogin-socket=$LAT/local/run/latlogin
make -j"$(nproc)"
# verbose/debug build (what was used for the investigation)
mkdir -p $LAT/local/build-debug && cd $LAT/local/build-debug
../../code/latd/configure --enable-debug \
--with-latcp-socket=$LAT/local/run/latcp \
--with-llogin-socket=$LAT/local/run/latlogin
make -j"$(nproc)"
--enable-debug adds -g3 -O0 -DVERBOSE_DEBUG -DNO_FORK; the running latd was
the debug one. Sockets are kept under lat/local/run/ (configure options), so
nothing lands in /var/run. /etc/latd.conf does not exist, so no global
startup script is run.
Run
cd $LAT/local/build-debug
sudo setsid ./latcp -s -d -v -v -i enp197s0f3u1 >$LAT/local/latd.log 2>&1 </dev/null &
sudo ./latcp -m 10
sudo ./latcp -G 1
sudo ./latcp -D -a SID # drop the unfiltered default
sudo ./latcp -A -a SID -i 'filtered login (node name)' -r 100 -C $LAT/tools/osc-filter.py
sudo ./latcp -A -a VT1200 -i 'filtered login' -r 100 -C $LAT/tools/osc-filter.py
sudo ./latcp -d # verify
sudo ./latcp -h # stop
Capture / decode
sudo tcpdump -i enp197s0f3u1 -w $LAT/local/out.pcap 'ether proto 0x6004'
tshark -r $LAT/local/out.pcap -T fields -e frame.number -e eth.src \
-e lat.msg_typ -e lat.slot.type -e lat.slot.slot_data
tshark -r $LAT/local/out.pcap -Y 'lat.msg_typ==10' -V -O lat # announcements
4. Root cause of the "login hangs" behaviour
Modern Linux writes OSC strings (ESC ] … BEL / ESC ] … ESC \) into the
terminal stream. The VT1200's 1990 terminal emulator is not a general VT
emulator for control strings and locks up on them. Sources observed here:
| Source | Sequence | Guard |
|---|---|---|
pam_systemd (via login) |
OSC 3008 type=session |
only if TERM != dumb (pam_systemd.c: if (streq_ptr(term,"dumb")) return PAM_SUCCESS;) |
/etc/profile.d/80-systemd-osc-context.sh |
OSC 3008 type=shell/command |
bash-only; skipped when TERM=dumb |
~/.config/zsh/functions/semantic-prompt.zsh |
OSC 133, OSC 122 |
none — unconditional |
~/.config/zsh/functions/osc7-pwd.zsh |
OSC 7 |
none — unconditional |
Evidence: vt-session.pcap — latd sends a 222-byte OSC 3008 then a 160-byte
prompt containing OSC 133, after which the VT1200 never transmits again.
Confirmation: a service running a bare /bin/sh (no OSC) works.
Upstream context: systemd issues #38527 and #41973.
Because the zsh scripts emit OSC unconditionally, TERM=dumb alone is not
enough — the output must be filtered.
5. Fix: lat/tools/osc-filter.py
A pty filter used as the latd service command (default inner command
/bin/login):
- forks
loginon an inner pty and relays both directions; - drops control strings (
ESC ]OSC,ESC PDCS,ESC XSOS,ESC ^PM,ESC _APC) from child→terminal; keeps all CSI (e.g. colours); - handles sequences split across reads;
- puts the outer pty (latd's) into raw mode, so it is a transparent pipe
— this is what makes passwords hidden (no local echo) and makes
^Creachlogin(noISIGon the outer tty).
Verified locally against the exact captured OSC 3008 / OSC 133 bytes.
Status: with the filter, login and authentication succeeded on the VT1200
and the password/^C problems were fixed by the raw-mode change. The final
test produced a VT1200 coredump — see §7.
6. Pitfalls / gotchas learned
- The VT1200 connects to the node-name service (
SID) by default; that service is created by latd unfiltered. Always replace/re-point it. latcp -Arefuses an existing service name ("Local service already exists"); delete withlatcp -D -a NAMEfirst.- Services need group 1 on both ends (
latcp -G 1+ the terminal'sCustomize → LAT…group code), or they won't appear in the VT's list. latcp -sruns/etc/latd.confif it exists (hardcoded) — it does not here.latdmust be started vialatcp -s(it refusesLATCP_STARTEDotherwise);-C <cmd>and-u <user>onlatcp -Aset the service's command/user.- Don't
pkill -f 'login -- …'— the pattern matches your own shell; usepkill -x login.
7. VT1200 CRASH (open item for the next session)
During the last test (login via osc-filter.py, outer pty in raw mode) the
terminal crashed with a coredump. This may be a usefully reachable firmware
bug — the whole EXPLOIT_NOTES.md effort is about exactly that.
- Capture of that session:
lat/local/filter-test2.pcap(547 LAT frames). - Related earlier capture (OSC leaking, using the unfiltered
SID):lat/local/filter-test.pcap.
Suggested next steps: replay/step the frames in filter-test2.pcap, isolate the
byte sequence that trips the firmware, and compare against vt-session.pcap
(which merely froze, no crash).
8. Evidence / artifacts (lat/local/)
| File | What |
|---|---|
filter-test2.pcap |
capture around the run that crashed the VT1200 |
filter-test.pcap |
earlier filtered attempt where OSC still leaked (unfiltered SID) |
vt-session.pcap |
the original freeze, with the OSC 3008 + OSC 133 payloads |
probe.pcap, lat-announce.pcap, session-*.pcap |
service announcements / early probes |
latd.log |
full verbose latd log (sessions, slots, credits) |
build.log |
last run-local.sh build output |
svc-plain.sh, svc-osc.sh |
A/B probe scripts used to confirm the OSC trigger |
HANDOFF.md |
this file |
Other relevant paths:
lat/code/latd/ # latd 1.36 source (GPL-2.0)
lat/manuals/ # DEC LAT specification + network manager's guide
lat/tools/osc-filter.py # the filter
lat/run-local.sh # build/run/capture helper
lat/local/build/ # release build
lat/local/build-debug/ # debug build (used for the investigation)
9. Remaining open items
- Reproduce/root-cause the VT1200 coredump from
filter-test2.pcap(§7). - Set a proper
TERMfor the VT1200 session (currently unset) — e.g.vt220. - Decide the service naming (node-name
SIDvs an explicitVT1200). - Optional: build latd with
--disable-defserviceso the unfiltered default service never exists (thenrun-local.shneedn't deleteSID).