Port Forwarding


SSH

Local Port Forwarding

Open a tunnel from the client to a server. AKA trying to point your web browser at a private web server.

Format:

ssh -L <local_port>:<remote_addr>:<remote_port> <server>

If you want to access something on the remote server itself, use localhost as the remote_addr

Examples

Port forward a postgres database running on the remote:

ssh -L 5432:localhost:5432 myuser@myserver

Access a private database from an admin host:

ssh -L 5432:database.rds.amazonaws.com:5432 myuser@admin-host

Remote Port Forwarding

Format:

ssh -R <remote_port>:<local_addr>:<local_port> <server>

Open a tunnel from the server to a client. AKA trying to share a local database with an application on the server

!> [!NOTE]

sshd must be configured with GatewayPorts yes in order to accept incoming connections.

Examples

Port forward a local database instance to the server:

ssh -R 5432:localhost:5432 myuser@myserver

Allow access to an internal website using your computer as a proxy:

ssh -R 8080:jira.mycorp.com:80 myuser@myserver

Dynamic Port Forwarding

Creates a SOCKS compatible proxy that operates on Layer 7, meaning it is not constrained by protocols

Format:

ssh -D <local_port> <server>

Using a SOCKS proxy depends on your application configuration. E.g. Firefox has proxy settings.

Linux/macOS support setting these environment variables:

ssh -D 8080 myuser@myserver
export http_proxy="socks5://127.0.0.1:8080"
export https_proxy="socks5://127.0.0.1:8080"

.ssh/config

Local Forwarding

Format:

LocalForward <local_port> <remote_addr>:<remote_port>

Examples:

Host server01
    HostName myserver01.internal.company.com
    User user
    LocalForward 5432 localhost:5432
    LocalForward 8080 privateserver.internal.company.com:80

Remote Forwarding

Format:

RemoteForward <remote_port> <local_addr>:<local_port>

Examples:

Host server01
    HostName myserver01.internal.company.com
    User user
    RemoteForward 5432 localhost:5432
    RemoteForward 8080 jira.internal.company.com:80

Dynamic Forwarding

Host my-proxy
    HostName my-proxy.internal.company.com
    User user
    DynamicForward 8080

Kubernetes

AWS Session Manager

socat

Socket concatenation. Allows making pipes between addresses.

Addresses

Addresses in socat have three components:

  • address type
  • zero or more required address parameters
  • zero or more address options

Types

TCP4

Format:

TCP4:<addr>:<port>

UDP_RECVFROM

Sets up a UDP listener to receive traffic and potentially respond.

Format:

UDP_RECVFROM:<port>

TCP4-LISTEN

Sets up a TCP4 listener to receive traffic and potentially respond.

Format:

TCP4-LISTEN:localhost:8080

GOPEN

Generic open of a file. If an address has a slash in it and no type specified, it is assumed to be this type.

Format:

GOPEN:/tmp/readdata
  • CREATE
  • EXEC
  • STDIN
  • STDOUT
  • STDIO - also aliased to -
  • PIPE
  • PTY
  • UDP4

Option Groups

The options available to the different address types are dependent on what option groups that type is in.

Sockets

Includes TCP4, TCP4-LISTEN, UDP, UDP_RECVFROM, GOPEN

Open

Includes GOPEN, PIPE

Single vs Dual Addresses

Single Addresses

Single addresses are the more common type of address. In them, the address is both the source and the sink for that part of the socat command.

For example, the following command listens on port 8080 and sends all traffic received to www.example.com

socat TCP4-LISTEN:8080 TCP4:www.example.com:80
flowchart LR
  TCP4-LISTEN
  TCP4
  TCP4-LISTEN <--> TCP4

Unidirectional Mode

You can enable unidirectional channels with the -u cli option:

socat -u GOPEN:/usr/share/example.txt STDOUT
flowchart LR
  GOPEN
  STDOUT
  GOPEN --> STDOUT

To reverse the direction, use -U

socat -U GOPEN:/usr/share/example.txt STDIN
flowchart RL
  GOPEN
  STDIN
  STDIN --> GOPEN

Dual Addresses

Dual addresses contain two separate address definitions: one for reading and the other for writing.

Dual addresses are denoted by double exclamation points, which may require escaping in terminals:

<read_addr>\!\!<write_addr>

The following example uses the readline utility to consume some text from the user, transform it using a shell command, and then write the results to a file:

socat -d -d   READLINE\!\!OPEN:file.txt,creat,trunc   SYSTEM:'read stdin; echo $stdin'
---
config:
  flowchart:
    curve: cardinal
---
flowchart TB
  subgraph ADDR1
    direction TB
    READLINE
    OPEN
    READLINE ~~~~ OPEN
  end
    direction TB
    subgraph ADDR2
    SYSTEM
  end
  READLINE --> SYSTEM
  SYSTEM --> OPEN

Lifecycle

  1. Initialization - parses CLI options and sets up logging
  2. Opening - opens address 1 and then address 2. Opening addresses is usually a blocking operation and might require authentication.
  3. Transfer - reads and writes from one end to the other (using Linux select)
  4. Closing - when one bytestream sends an EOF, socat will try to close the write part of the other bytestream. After some delay socat will forcibly close ones that don’t close gracefully.

References