whiteboard

01 — Whiteboard model

Learning objectives

Intuition

Before typing SSH, know who listens and who dials. Wrong mental model → wrong flag under pressure.

Friend annotation — where you type vs who listens

Usual class topology: you already SSH to B. You type both -L and -R on A (your laptop). The flag does not mean "run -R on the target."

You said Precise meaning
-L opens my 8080 for whatever is on their 80 Yes. Listener on A:8080. Browser hits 127.0.0.1:8080 on A → B dials C:80 (or 127.0.0.1:80 on B).
-R opens 8080 on the target back to my 8080 Yes, with port names clear: listener on B (often 127.0.0.1:18080). Something on B hits that port → A serves your 127.0.0.1:8080.
# both from YOUR laptop (A)
ssh -N -L 127.0.0.1:8080:127.0.0.1:80 user@B   # pull their :80 to your :8080
ssh -N -R 127.0.0.1:18080:127.0.0.1:8080 user@B # push your :8080 onto B as :18080

Only if B opens SSH back to you (you are the SSH server) do the roles flip. That is a different topology — not the default demo.

Mermaid — -L local forward

sequenceDiagram
  participant You as A your laptop
  participant B as B bastion
  participant C as C service :80

  Note over You: Listener on A :8080
  You->>You: curl 127.0.0.1:8080
  You->>B: SSH channel (-L)
  B->>C: B dials C:80
  C-->>B: response
  B-->>You: back through SSH

Mermaid — -R remote forward

sequenceDiagram
  participant You as A your laptop
  participant B as B bastion
  participant Svc as A service :8080

  Note over B: Listener on B :18080
  Note over Svc: Your lab HTTP on A
  B->>B: curl 127.0.0.1:18080
  B->>You: SSH channel (-R)
  You->>Svc: A dials 127.0.0.1:8080
  Svc-->>You: response
  You-->>B: back through SSH

Mermaid — side-by-side mental model

flowchart LR
  subgraph L["-L pull to me"]
    A1["A listens :8080"] --> SSH1["SSH"] --> B1["B dials C:80"]
  end
  subgraph R["-R push to them"]
    B2["B listens :18080"] --> SSH2["SSH"] --> A2["A dials my :8080"]
  end

FAQ / common mistakes (from class Q&A)

Use this after the friend annotation. Kill these myths before anyone types ssh.

Myth / mix-up Truth
"-L opens a port on the bastion" False. -L opens the listener on A (your laptop). B only dials the destination after you hit your local port.
"-L 8080:127.0.0.1:80 means C:8080 shows up as my port 80" False. Left side = your listen port (8080). Right side = destination host:port as B sees it (127.0.0.1:80 on B, or C_IP:80).
"I used 127.0.0.1 but never wrote C's IP — so the tunnel is broken" Not broken. Destination is resolved from B. 127.0.0.1 means B's loopback. If the service is on host C, put C's IP/hostname there instead.
"The service on C sees my laptop's IP" No. C (or the service on B) sees the connection coming from the bastion (B).
"-R means I must run SSH on the target" Usually false. With A→B SSH, you still type -R on A. Listener appears on B. Only if B SSHes back to you do roles flip.
"-D needs a target host:port like -L" False. -D only sets a local SOCKS port. Each app picks destinations through B. The app must speak SOCKS (or use a SOCKS-aware wrapper).

Port order cheat (say it aloud)

-L [bind:]LOCAL_PORT:DEST_HOST:DEST_PORT
         ^ you listen here     ^ B dials this

Example friends often mistype mentally:

# YOUR listen :8080  →  B dials its own :80
ssh -N -L 127.0.0.1:8080:127.0.0.1:80 user@B

# YOUR listen :8080  →  B dials C:80  (put C's address)
ssh -N -L 127.0.0.1:8080:10.10.10.50:80 user@B

Bind defaults (class safety)

Mode Safer class bind Why
-L / -D Prefix 127.0.0.1: Listener stays on your laptop loopback
-R Prefix 127.0.0.1: on the remote side Avoids a wide-open listen on B; do not enable GatewayPorts for class

One-sentence each (checkpoint)

Practitioner

Goal: Friends can pick -L / -R / -D for a new scenario without opening a terminal.

Time: ~15 minutes. No SSH yet.

Draw once

[A student] ----SSH----> [B bastion] ....?.... [C internal service]

Fill in for each flag: who listens? who dials C (or A's service)?

Drill questions (say answers out loud)

  1. "I need the internal web on C:80 in my browser." → -L (or -D if many ports unknown).
  2. "A callback / webhook on B must hit a tiny HTTP server on my laptop." → -R.
  3. "I will run several tools against hosts only B can reach; ports unclear." → -D.
  4. "I already know exactly one db.internal:5432." → Prefer -L over -D (narrower).

Rules of thumb

Prefer When
-L One destination, known port
-D Tooling / browsing through B; many destinations
-R Listener must live on B
Later (out of scope here) ligolo / chisel / ssh -J multi-hop once forwards click

Checkpoint

Each friend: explain the three flags in one sentence each, no notes.

Cite: peachcyber SSH note [S-PC-01]; OpenSSH ssh(1) [S-OSS-01].

Deep dive

Compare jump host (-J) vs forwarding: shell on private host vs TCP to one service — save for later modules [S-PC-01 | medium | derived].

Check

Each friend: three one-sentence explanations + drill answers aloud.