Skip to content
/ gofwd Public

A cross-platform TCP port forwarder with Duo 2FA and Geo-IP integration

License

Notifications You must be signed in to change notification settings

jftuga/gofwd

Repository files navigation

gofwd

Description

gofwd is a cross-platform TCP port forwarder with Duo 2FA and Geographic IP integration. Its use case is to help protect services when using a VPN is not possible. Before a connection is forwarded, the remote IP address is geographically checked against city, region (state), and/or country. Distance (in miles) can also be used. If this condition is satisfied, a Duo 2FA request can then be sent to a mobile device. The connection is only forwarded after Duo has verified the user.

Stand-alone, single-file executables for Windows, MacOS, and Linux can be downloaded from Releases.

Use case

The standard Duo 2FA Windows RDP implementation issues the the second factor request after a RDP client has connected and issued a valid username / password combination. The RDP port is always open to the Internet, which is a potential security issue.

gofwd uses Duo 2FA before forwarding the RDP connection to an internal system. The big caveat with gofwd is that it only works well in single-user scenarios. However, being able to access your home lab remotely fits in well in this scenario.

gofwd can also be used to protect SSH such as an AWS EC2 instance or Digital Ocean Droplet.

Using both Remote Desktop to a home computer and remote SSH access work reliably well. On a home network, gofwd can be run on a Raspberry Pi that forwards the connection to a Windows 10 system once Duo authentication is successful. It can also run from within a Docker container for added security.

The Geo-IP feature is nice because it limits who can initiate a Duo 2FA request. If someone tries to connect to your RDP port but is not within the defined geo-ip fence, then a Duo 2FA will not be sent to your phone. Running on a non-standard port for Remote Desktop and SSH is recommended to limit the number of 2FA requests. You can also explicitly allow and deny networks with the -A and -D command-line options. These overrides will bypass the geo-ip fence and 2FA.

For example, you could use a 50 mile radius from your residence and you will probably not receive a Duo 2FA request from another person or bot. Be aware that some mobile operators might issue you an IP address that is further away than expected. The geo-ip fence can alternatively be defined based on city, region (state) and/or country or by using latitude, longitude coordinates. gofwd uses https://ipinfo.io/ to get this information in real time. Since ipinfo provides 1,000 free requests per day (from the same IP address), no API key is therefore used.

The overall elegance of this solution is that no additional software is needed. As long as you are within your predefined geo-ip location, have your phone, and know your hostname/ip address (and port number), then you will be able to access your system remotely.

Usage

usage: gofwd [<flags>]


Flags:
      --[no-]help           Show context-sensitive help (also try --help-long and --help-man).
  -i, --[no-]int            list local interface IP addresses
  -f, --from=FROM           from address:port - use '0.0.0.0' for all interfaces; use '_eth0' for the address portion to use this interface; also '_en0', '_Ethernet', etc.
  -t, --to=TO               to address:port - address portion can also be DNS name
      --[no-]examples       show command line example and then exit
      --[no-]version        show version and then exit
      --city=CITY           only accept incoming connections that originate from given city
      --region=REGION       only accept incoming connections that originate from given region (eg: state)
      --country=COUNTRY     only accept incoming connections that originate from given 2 letter country abbreviation
  -l, --loc=LOC             only accept from within a geographic radius; format: LATITUDE,LONGITUDE (use with --distance)
  -d, --distance=DISTANCE   only accept from within a given distance (in miles)
  -A, --allow=ALLOW         allow from a comma delimited list of CIDR networks, bypassing geo-ip, duo
  -D, --deny=DENY           deny from a comma delimited list of CIDR networks, disregarding geo-ip, duo
      --duo=DUO             path to duo ini config file and duo username; format: filename:user (see --examples)
      --duo-cache-time=120  number of seconds to cache a successful Duo authentication (default is 120)
  -p, --[no-]private        allow RFC1918 private addresses for the incoming (connecting) IP

Examples

+-------------------------------------------------------------------+-----------------------------------------------------------------------------+
|                              EXAMPLE                              |                                   COMMAND                                   |
+-------------------------------------------------------------------+-----------------------------------------------------------------------------+
| get the local IP address *(run this first)*, eg: 1.2.3.4          | gofwd -i                                                                    |
| forward from a bastion host to an internal server                 | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22                                       |
| allow only if the remote IP is within 50 miles of this host       | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22 -d 50                                 |
| allow only if remote IP is located in Denver, CO                  | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22 -city Denver -region Colorado         |
| allow only if remote IP is located in Canada                      | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22 -country CA                           |
| allow only if remote IP is located within 75 miles of Atlanta, GA | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22 -l 33.756529,-84.400996 -d 75         |
|     to get Latitude, Longitude use https://www.latlong.net/       |                                                                             |
| allow only for a successful two-factor duo auth for 'testuser'    | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22 --duo duo.ini:testuser                |
| allow only after both Geo IP and Duo are verified                 | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22 --region Texas --duo duo.ini:testuser |
| forward from any interface on port 22, allow RFC1918 to connect   | gofwd -f 0.0.0.0:22 -t 192.168.1.1:22 -p                                    |
| forward from IP address bounded to eth0, allow RFC1918 to connect | gofwd -f _eth0:22 -t 192.168.1.1:2 -p                                       |
| forward from IP address bounded to eno1, allow RFC1918 to connect | gofwd -f _eno1:80 -t example.com:80 -p                                      |
+-------------------------------------------------------------------+-----------------------------------------------------------------------------+

Two Factor Authentication (2FA) via Duo

Basic Setup

  • https://duo.com/
  • gofwd will only work with a single Duo user; therefore, only one person will be able to access the resource residing behind gofwd.
    • Multiple gofwd instantiations can be used for different users.
    • The .ini configuration file supports multiple users (see below).
  • You will need to create a Duo account. The free tier supports 10 users.
  • Create a user and set their status to Require two-factor authentication. This is the default.
    • You should also add an email address and phone number.
  • Install the Duo app on to your mobile device.

Application Setup

  • On the Duo website, click on Applications.
  • Protect an Application
  • Select Partner Auth API
  • Under Settings, give your application a name such as gofwd ssh or gofwd rdp.
  • Create a duo.ini file with the user name as an ini section heading (the one that you just created under Basic Setup)
    • Use the Integration Key, Secret Key, and API HostName to configure your .ini file.

Running with Duo

  • Add the --duo command line option
    • See the Examples section to see how to run gofwd with duo authentication enabled

Docker

Example Helper Scripts

Static Compilation - Docker Only

  • Your version of gofwd will need to be statically compiled:
Platform Command
windows go build -tags netgo -ldflags "-extldflags -static"
linux/bsd go build -tags netgo -ldflags '-extldflags "-static" -s -w'
linux CGO_ENABLED=0 go build -ldflags='-s -w'
macos go build -ldflags '-s -extldflags "-sectcreate __TEXT __info_plist Info.plist"'
android go build -ldflags -s

NOTE: I have not been able to test all of these

Docker Example

docker run -d --restart unless-stopped -p 4567:4567
    -v /home/ec2-user/duo.ini:/duo.ini \
    jftuga:gofwd:v050.1 -f 0.0.0.0:4567 -t 192.168.1.1:22 \
    --duo /duo.ini:jftuga -l 39.858706,-104.670732 -d 80
Explanation Parameter
detach and run Docker in daemon mode -d
restart container (on error) unless explicitly stopped --restart unless-stopped
redirect external TCP port to internal TCP port -p 4567:4567
ini file is located on the host here: /home/ec2-user/duo.ini -v /home/ec2-user/duo.ini:/duo.ini
ini file is mounted inside the container here: /duo.ini -v /home/ec2-user/duo.ini:/duo.ini
container name and tag jftuga:gofwd:v050.1
external service is 0.0.0.0 on port 4567 -f 0.0.0.0:4567
internal service is 192.168.1.1 on port 22 -t 192.168.1.1:22
duo config file is mounted within the container --duo /duo.ini:jftuga
duo user name --duo /duo.ini:jftuga
location: use coordinates for Denver, CO -l 39.858706,-104.670732
distance: 80 miles from Denver -d 80

Note: if you are running in a NAT environment, such as AWS, then you will need to include the -p option to allow RFC1918 private IPv4 addresses.

chroot environment

Acknowledgments

Other Go code used:

Future Work

About

A cross-platform TCP port forwarder with Duo 2FA and Geo-IP integration

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages