# A userspace tunnel between two hosts mapping ports on client machine to addresses reachable from server machine

[![Linux build status](https://travis-ci.org/tcp-warp/tcp-warp.svg)](https://travis-ci.org/tcp-warp/tcp-warp)
[![Windows build status](https://ci.appveyor.com/api/projects/status/github/tcp-warp/tcp-warp?svg=true)](https://ci.appveyor.com/project/tcp-warp/tcp-warp)
[![Crates.io](https://img.shields.io/crates/v/tcp-warp.svg)](https://crates.io/crates/tcp-warp)
[![Crates.io](https://img.shields.io/crates/v/tcp-warp.svg)](https://crates.io/crates/tcp-warp-cli)
[![Packaging status](https://repology.org/badge/tiny-repos/tcp-warp.svg)](https://repology.org/project/tcp-warp/badges)

## Legal

Dual-licensed under `MIT` or the [UNLICENSE](http://unlicense.org/).

## Features

1. A userspace tunnel to connect ports on client network with connections available on server side.
1. Uses only single port.
1. Client push of addresses to connect from server.

## Installation

With [cargo](https://www.rust-lang.org/learn/get-started):

```bash
cargo install tcp-warp-cli
```

## Usage

To create a tunnel we need to start a server listening on some port and then connect to it with a client.

### Docker usage for server part

```bash
docker run --rm -d -p 18000:18000 tcpwarp/tcpwarp
```

or with custom listen port (ex: 18234):

```bash
docker run --rm -d -p 18234:18234 tcpwarp/tcpwarp tcp-warp server --listen=0.0.0.0:18234
```

### Simple local running port remapper

1. Start server:

    ```bash
    tcp-warp server --listen 0.0.0.0:18000
    ```

1. Start client:

    ```bash
    tcp-warp client -c 8080:towel.blinkenlights.nl:23 --tunnel 127.0.0.1:18000
    ```

1. Enjoy the show:

    ```bash
    nc 127.0.0.1 8080
    ```

1. This example uses default listen and connect interfaces. In a real life scenario you need at least provide -t / --tunnel parameter to client:

    ```bash
    tcp-warp client -t host:port ...
    ```

Both client and server have address on which they listen for incoming connections and client additionally have parameter to specify connection address.

Next we look at more specific example.

### Use case: running Docker on machine without Docker daemon installed with Docker daemon behind SSH

Background:

- client: client machine runs on Windows, has Windows version of `tcp-warp` and Docker CLI installed. Client cannot run Docker daemon.
- public: master node accessible with SSH from which Docker daemon node can be accessed.
- docker: docker daemon node accessible with SSH.

Target:

Run Docker over tcp transport, allowing `client` to build and run containers. Environment should be available for each developer independent of other.

Solution:

Run on `docker` machine Docker-in-Docker container (`dind`) using tcp host protocol. Use `DOCKER_HOST` environment variable on `client` to connect to `dind`. `dind` is bindet to host port on `docker` host and forwarded via `public` with SSH port-forwarding.

The sequence of commands can be following:

#### Initial sequence (installation)

1. Go to `docker` node and start required containers:

    ```bash
    user@client $ ssh user1@public
    user1@public $ ssh user2@docker
    user2@docker $ docker run --rm --privileged -p 2375:2375 -p 18000:18000 -d --name some-docker docker:dind dockerd --host=tcp://0.0.0.0:2375
    user2@docker $ DOCKER_HOST=tcp://127.0.0.1:2375 docker run --rm -p 18000:18000 -d --name some-docker-tcp-warp tcpwarp/tcpwarp
    ```

1. Disconnect from `docker` and `public` nodes.

#### Normal sequence (usage)

1. Connect to `public` node with `ssh` and forward port for `tcp-warp`:

    ```bash
    ssh -L 18000:docker:18000 user1@public
    ```

1. Connect to Docker daemon with `tcp-warp client` on `client` machine:

    ```bash
    tcp-warp client -c 10001:172.18.0.1:2375
    ```

    `172.18.0.1` here is the address of host node in `dind`.

1. Export DOCKER_HOST environment variable on `client` machine:

    ```bash
    export DOCKER_HOST=tcp://127.0.0.1:10001
    ```

1. Run docker commands from `client`:

    ```bash
    docker ps
    docker run hello-world
    docker run -it alpine ash
    ```

#### Additional services

We can start additional services and relaunch `tcp-warp client` with additional `-c` for these services.

Simple example with `whoami` service:

1. Create network to use for hostname resolution. Start `whoami` service with all above steps done. Connect tcp-warp container to new network:

    ```bash
    docker network create our-network
    docker run --rm -d --net our-network --name whoami containous/whoami
    docker network connect our-network some-docker-tcp-warp
    ```

1. Stop `tcp-warp client`. Start it with additional port mapping for `whoami` service:

    ```bash
    tcp-warp client -c 10001:172.18.0.1:2375 -c 8080:whoami:80
    ```

1. Test `whoami` service:

    ```bash
    $ curl http://localhost:8080/
    Hostname: 9fe704cf0e87
    IP: 127.0.0.1
    IP: 172.18.0.3
    IP: 172.19.0.3
    RemoteAddr: 172.19.0.2:44612
    GET / HTTP/1.1
    Host: localhost:8080
    User-Agent: curl/7.64.1
    Accept: */*
    ```
