{"id":13682187,"url":"https://github.com/jftuga/gofwd","last_synced_at":"2025-07-26T17:32:18.627Z","repository":{"id":57624083,"uuid":"254720092","full_name":"jftuga/gofwd","owner":"jftuga","description":"A cross-platform TCP port forwarder with Duo 2FA and Geo-IP integration","archived":false,"fork":false,"pushed_at":"2023-10-09T14:09:38.000Z","size":227,"stargazers_count":46,"open_issues_count":3,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-12T01:35:21.760Z","etag":null,"topics":["command-line","duo","forwarding","geoip","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jftuga.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-04-10T19:35:23.000Z","updated_at":"2024-07-24T13:32:10.000Z","dependencies_parsed_at":"2024-01-14T15:40:05.471Z","dependency_job_id":null,"html_url":"https://github.com/jftuga/gofwd","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fgofwd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fgofwd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fgofwd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fgofwd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jftuga","download_url":"https://codeload.github.com/jftuga/gofwd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227700391,"owners_count":17806365,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line","duo","forwarding","geoip","golang"],"created_at":"2024-08-02T13:01:41.945Z","updated_at":"2024-12-02T09:18:56.233Z","avatar_url":"https://github.com/jftuga.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# gofwd\n\n\n## Description\n\n`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.\n\nStand-alone, single-file executables for Windows, MacOS, and Linux can be downloaded from [Releases](https://github.com/jftuga/gofwd/releases).\n\n\n## Use case\n\nThe 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.\n\n`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.\n\n`gofwd` can also be used to protect SSH such as an AWS EC2 instance or Digital Ocean Droplet.\n\nUsing 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.\n\nThe 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.\n\nFor 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\nipinfo provides 1,000 free requests per day (from the same IP address), no API\nkey is therefore used.**\n\n**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.**\n\n## Usage\n\n```\nusage: gofwd [\u003cflags\u003e]\n\n\nFlags:\n      --[no-]help           Show context-sensitive help (also try --help-long and --help-man).\n  -i, --[no-]int            list local interface IP addresses\n  -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.\n  -t, --to=TO               to address:port - address portion can also be DNS name\n      --[no-]examples       show command line example and then exit\n      --[no-]version        show version and then exit\n      --city=CITY           only accept incoming connections that originate from given city\n      --region=REGION       only accept incoming connections that originate from given region (eg: state)\n      --country=COUNTRY     only accept incoming connections that originate from given 2 letter country abbreviation\n  -l, --loc=LOC             only accept from within a geographic radius; format: LATITUDE,LONGITUDE (use with --distance)\n  -d, --distance=DISTANCE   only accept from within a given distance (in miles)\n  -A, --allow=ALLOW         allow from a comma delimited list of CIDR networks, bypassing geo-ip, duo\n  -D, --deny=DENY           deny from a comma delimited list of CIDR networks, disregarding geo-ip, duo\n      --duo=DUO             path to duo ini config file and duo username; format: filename:user (see --examples)\n      --duo-cache-time=120  number of seconds to cache a successful Duo authentication (default is 120)\n  -p, --[no-]private        allow RFC1918 private addresses for the incoming (connecting) IP\n```\n\n\n## Examples\n\n```\n+-------------------------------------------------------------------+-----------------------------------------------------------------------------+\n|                              EXAMPLE                              |                                   COMMAND                                   |\n+-------------------------------------------------------------------+-----------------------------------------------------------------------------+\n| get the local IP address *(run this first)*, eg: 1.2.3.4          | gofwd -i                                                                    |\n| forward from a bastion host to an internal server                 | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22                                       |\n| 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                                 |\n| 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         |\n| allow only if remote IP is located in Canada                      | gofwd -f 1.2.3.4:22 -t 192.168.1.1:22 -country CA                           |\n| 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         |\n|     to get Latitude, Longitude use https://www.latlong.net/       |                                                                             |\n| 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                |\n| 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 |\n| 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                                    |\n| forward from IP address bounded to eth0, allow RFC1918 to connect | gofwd -f _eth0:22 -t 192.168.1.1:2 -p                                       |\n| forward from IP address bounded to eno1, allow RFC1918 to connect | gofwd -f _eno1:80 -t example.com:80 -p                                      |\n+-------------------------------------------------------------------+-----------------------------------------------------------------------------+\n```\n\n\n## Two Factor Authentication (2FA) via Duo\n\n### Basic Setup\n* https://duo.com/\n* `gofwd` will only work with a single Duo user; therefore, only one person will be able to access the resource residing behind `gofwd`.\n* * Multiple `gofwd` instantiations can be used for different users.\n* * The .ini configuration file supports multiple users *(see below)*.\n* You will need to create a Duo account.  The free tier supports 10 users.\n* Create a user and set their status to `Require two-factor authentication`. This is the default.\n* * You should also add an email address and phone number.\n* Install the Duo app on to your mobile device.\n\n### Application Setup\n* On the Duo website, click on Applications.\n* Protect an Application\n* Select `Partner Auth API`\n* Under `Settings`, give your application a name such as `gofwd ssh` or `gofwd rdp`.\n* Create a `duo.ini` file with the **user name** as an ini section heading (the one that you just created under *Basic Setup*)\n* * Use the **Integration Key**, **Secret Key**, and **API HostName** to configure your .ini file.\n* * Example: [duo-example.ini](https://github.com/jftuga/gofwd/blob/master/duo-example.ini)\n\n### Running with Duo\n* Add the ``--duo`` command line option\n* * See the *Examples* section to see how to run `gofwd` with duo authentication enabled\n\n## Docker\n\n### Example Helper Scripts\n* To build an image: [docker_build_image.sh](https://github.com/jftuga/gofwd/blob/master/docker_build_image.sh)\n* To run the built image: [docker_start_gofwd.sh](https://github.com/jftuga/gofwd/blob/master/docker_start_gofwd.sh) *(Edit first)*\n* * A `FROM` address of `0.0.0.0` should make `gofwd` listen on any interface.\n* To use `gofwd.exe` in Docker under Windows, consider using the [Microsoft Windows Nano Server](https://hub.docker.com/_/microsoft-windows-nanoserver) for containers.\n* To use `gofwd` in Docker under Linux, consider starting with [Scratch](https://hub.docker.com/_/scratch) for the container.\n\n### Static Compilation - Docker Only\n* Your version of `gofwd` will need to be statically compiled:\n\n| Platform  | Command\n------------|--------\n| windows   | go build -tags netgo -ldflags \"-extldflags -static\"\n| linux/bsd | go build -tags netgo -ldflags '-extldflags \"-static\" -s -w'\n| linux     | CGO_ENABLED=0 go build -ldflags='-s -w'\n| macos     | go build -ldflags '-s -extldflags \"-sectcreate __TEXT __info_plist Info.plist\"'\n| android   | go build -ldflags -s\n\n**NOTE:** *I have not been able to test all of these*\n\n## Docker Example\n```\ndocker run -d --restart unless-stopped -p 4567:4567\n    -v /home/ec2-user/duo.ini:/duo.ini \\\n    jftuga:gofwd:v050.1 -f 0.0.0.0:4567 -t 192.168.1.1:22 \\\n    --duo /duo.ini:jftuga -l 39.858706,-104.670732 -d 80\n```\n\n| Explanation | Parameter |\n--------------|------------\n| detach and run Docker in daemon mode | -d\n| restart container (on error) unless explicitly stopped | --restart unless-stopped\n| redirect external TCP port to internal TCP port | -p 4567:4567\n| ini file is located on the host here: `/home/ec2-user/duo.ini` | -v `/home/ec2-user/duo.ini`:/duo.ini\n| ini file is mounted inside the container here: `/duo.ini` | -v /home/ec2-user/duo.ini:/`duo.ini`\n| container name and tag | jftuga:gofwd:v050.1\n| external service is `0.0.0.0` on port `4567` | -f 0.0.0.0:4567 \n| internal service is `192.168.1.1` on port `22` | -t 192.168.1.1:22\n| duo config file is mounted within the container | --duo `/duo.ini`:jftuga\n| duo user name | --duo /duo.ini:`jftuga`\n| location: use coordinates for Denver, CO | -l 39.858706,-104.670732\n| distance: `80 miles` from Denver | -d 80\n\n\n**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.\n\n\n## chroot environment\n* Please review [chroot_start_gofwd.sh](https://github.com/jftuga/gofwd/blob/master/chroot_start_gofwd.sh)\n\n\n## Acknowledgments\n* Some code was adopted from [The little forwarder that could](https://github.com/kintoandar/fwd/)\n* `gofwd`uses https://ipinfo.io/ to get Geo IP information in real time\n* * They provide 1,000 free, non-authenticated requests per day. \n\nOther Go code used:\n\n* Logging: https://go.uber.org/zap\n* Command line arguments: https://gopkg.in/alecthomas/kingpin.v2\n* Output tables: https://github.com/olekukonko/tablewriter\n* Ini file: https://gopkg.in/ini.v1\n* Network interfaces: https://github.com/jftuga/nics\n* IP info: https://github.com/jftuga/ipinfo\n* Duo API: https://github.com/duosecurity/duo_api_golang/authapi\n\n## Future Work\n* [Run the Docker daemon as a non-root user - Rootless Mode](https://docs.docker.com/engine/security/rootless/)\n* [Docker Tips: Running a Container With a Non Root User](https://medium.com/better-programming/running-a-container-with-a-non-root-user-e35830d1f42a)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjftuga%2Fgofwd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjftuga%2Fgofwd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjftuga%2Fgofwd/lists"}