Loopback Port Forwarding

A management client that could only ever dial one hardcoded TCP port — pointed at every device on every customer network at once, by giving each device its own address inside 127.0.0.0/8.

US 10,097,523 B2 ↗ · Martello Technologies · granted Oct 9, 2018 · Kuker, Tenney, Tse

Java Applet SSH TCP Sockets

The Constraint

MarWatch monitored voice and network equipment sitting behind other people's firewalls. A probe application — MarProbe — ran inside each customer network and dialed out to the central service, holding an SSH tunnel open. That inverted tunnel is the whole trick: nobody had to punch a hole in the customer's firewall, and there was no VPN client to install, conflict with, or remember credentials for.

Remote access rode that tunnel. Click a device in the web portal, and the central server would ask the probe to open a port forward back through its own tunnel, cross-connect your session into it, and hand your traffic to the device. For anything web-based this was a link you could click. For everything else, you needed something on the operator's machine to terminate the near end.

The problem was the tools operators actually used. Vendor element managers are not thoughtful pieces of software. The one that mattered most had a host field and no port field — it dialed one TCP port, the same port, always, with no setting, no config file, no argument to override it. Every device it managed listened on that same port too, which is fine on a LAN where each device has its own IP, and fatal the moment you try to funnel several of them through one machine.

Why Port-Per-Device Doesn't Work

The textbook answer is the SSH local forward: -L 12001:10.10.4.20:2002, then point your client at localhost:12001. Want a second device? Pick 12002. This is how every ad-hoc tunnel gets built, and it fails here for a boring reason — it assumes you can tell the client which port to use. You can't. The client dials the one port it knows, so 127.0.0.1 can host exactly one forward at a time.

Which reduced the workflow to: open a tunnel, do your work, tear it down, open the next one. An operator triaging a multi-site outage did that dance per device, and got no ability to have two windows open side by side comparing the controller at one site to the controller at another.

Sixteen Million Local Addresses

The fix comes from noticing that the port is the wrong half of the socket to vary. A listening socket is identified by an address and port, and loopback is not one address — it's a /8. The entire 127.0.0.0/8 block, about 16.7 million addresses, is reserved for the local host, and on Linux and Windows the stack routes all of it to the loopback interface with no configuration at all.

So the agent binds one address per device, all on the same immovable port:

bind(127.31.4.20:2002)  →  Northwind  PBX Controller   10.10.4.20:2002
bind(127.31.4.21:2002)  →  Northwind  Border Gateway   10.10.4.21:2002
bind(127.60.1.30:2002)  →  Coastal    PBX Controller   10.60.1.30:2002
bind(127.60.1.31:2002)  →  Coastal    Voicemail        10.60.1.31:2002

These are four distinct sockets — different bind addresses, identical ports, no collision. The operator types 127.60.1.30 into the host field the client does have, and the accepting socket is itself the routing decision: the agent knows which of the two PBX controllers you meant because of which address you knocked on, not because the application told it anything. As far as the client is concerned it is talking to something on the local machine, exactly the way it expects to.

And there is no scarcity to manage. Sixteen million addresses against a few hundred devices per operator means the allocator never has to think.

Stable, Not Allocated

The addresses being stable matters as much as them being distinct. Element managers keep site lists, saved connection profiles, bookmarks. If the agent handed out addresses on a first-come counter, every restart would reshuffle them, and every saved profile would quietly start pointing at a different customer's PBX — the worst possible failure mode for a tool whose whole job is making changes to phone systems.

So the mapping is a property of the device, not of the session: derived once, persisted, and reused forever. Encoding the site in the second octet and carrying the device's last two octets through (10.10.4.20 → 127.31.4.20) made the addresses legible at a glance during troubleshooting, with the persisted table remaining authoritative — overlapping RFC 1918 ranges across customers means the mnemonic can't be trusted to be unique on its own.

Nothing Is Dialed Until Something Connects

Binding a listener is nearly free. Building a tunnel is not: it costs an authorization check, a round trip down the probe's SSH tunnel, a device proxy on the central server, and a TCP connection inside the customer network. Standing all of that up for every device an operator might touch would mean hundreds of idle forwards per operator and a permanent hole punched through to equipment nobody is looking at.

So the listeners are the only thing that exists up front. The first SYN on a bound address is the trigger; everything downstream is built in response to it, and torn down when the last socket closes. The setup sequence — the one the demo below steps through — runs in that gap between accept() and the client's first byte:

  1. The agent accepts on the alias and resolves it to a device.
  2. The central server checks the operator's authorization and looks up which probe owns that device.
  3. A port-forward request goes down the probe's existing tunnel, and the probe checks the device against its own access list — the customer's copy of the rules, enforced inside the customer's network.
  4. The server creates a device proxy and issues a session key, a nonce, and a socket address.
  5. The agent and the probe both dial that proxy. The proxy decrypts the opening packets from each side, matches the nonces, and only then stops inspecting and becomes a pipe.
  6. The probe opens TCP to the device, and the byte stream is continuous end to end.

That last handshake is why neither end has to be reachable from the other. Both ends dial the middle; the middle proves they belong together. Nothing listens on the operator's machine except loopback, and nothing listens on the customer network at all.

An Applet, and Why There Was Also a Desktop Client

The near end shipped first as a signed Java applet, because in 2011 that was how you got code onto an operator's machine without asking them to install anything — the portal page handed the applet its proxy address, key and nonce, and the applet opened its local sockets and dialed out. No installer, no admin rights, no support call.

Loopback is where that stopped being enough. Linux and Windows accept a bind to any address in 127.0.0.0/8 out of the box. macOS does not: only 127.0.0.1 is actually configured on lo0, and every additional address has to be added as an interface alias — ifconfig lo0 alias 127.31.4.20 up — which needs root, which a sandboxed applet in a browser is never going to have.

That single platform difference is what the desktop client existed to solve. Same forwarding engine, but installed, so it could configure the aliases it needed and keep the mapping table across restarts instead of rebuilding it per page load. The applet remained the zero-install path for the platforms that didn't need the help, and the two shared the protocol end.

What's Mine

The patent covers the system as a whole: probe-initiated tunnels, the server-initiated port forward, the device proxy, the nonce-authenticated meet-in-the-middle, and the local agent that terminates the near end. My contribution was that last piece — the applet and desktop client, and the loopback binding scheme that turned "one hardcoded port" from a hard blocker into a non-issue.

The demo below is a re-creation, not the original code. The sequence and the failure modes are the real ones; the timings are chosen to be legible rather than measured.

Interactive Demo

Five devices across two customer sites, one management client stuck on port 2002. Open a device and watch the on-demand setup run hop by hop; open several and watch them coexist. Switch to 127.0.0.1 only to see what the constraint costs you without the alias trick — the second device you try to open collides with the first. Cut a site's probe to drop its tunnel and see what happens to sessions that depend on it.

your workstationcentral servercustomer networkMarWatchssh ↩ssh ↩element mgrport 2002 🔒127.31.4.20:2002127.31.4.21:2002127.60.1.30:2002127.60.1.31:2002127.60.1.9:2002MarProbeNorthwind GroupMarProbeCoastal LegalPBX Controller10.10.4.20:2002Border Gateway10.10.4.21:2002PBX Controller10.60.1.30:2002Voicemail Server10.60.1.31:2002Edge Switch10.60.1.9:2002

Every device owns a stable loopback address. The app dials port 2002 on all of them, and the bind address says which device it meant.

1 accept
2 authorize
3 port forward
4 device proxy
5 nonce auth
6 connect
established

Nothing is tunnelled yet — the agent is just listening. Open a device to trigger the on-demand setup.

local binddeviceforwards tostatetraffic
127.31.4.20:2002PBX Controller · Northwind Group10.10.4.20:2002LISTEN
127.31.4.21:2002Border Gateway · Northwind Group10.10.4.21:2002LISTEN
127.60.1.30:2002PBX Controller · Coastal Legal10.60.1.30:2002LISTEN
127.60.1.31:2002Voicemail Server · Coastal Legal10.60.1.31:2002LISTEN
127.60.1.9:2002Edge Switch · Coastal Legal10.60.1.9:2002LISTEN
Clock 00:00.0
Concurrent 0 / 5
Peak 0
Sessions Opened 0
Bind Collisions 0
Forwarded 0 B
00:00.0 local agent bound 5 aliases on 127.0.0.0/8, all :2002
00:00.0 MarProbe/coastal established reverse SSH tunnel to MarWatch
00:00.0 MarProbe/northwind established reverse SSH tunnel to MarWatch