{"id":25411719,"url":"https://github.com/koho/nat2","last_synced_at":"2026-02-09T14:32:48.486Z","repository":{"id":258643591,"uuid":"874332605","full_name":"koho/nat2","owner":"koho","description":"Expose your local service to Internet in full cone NAT network.","archived":false,"fork":false,"pushed_at":"2024-12-08T08:19:33.000Z","size":153,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-14T10:54:01.414Z","etag":null,"topics":["full-cone-nat","hole-punching","nat","upnp"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/koho.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-17T16:30:59.000Z","updated_at":"2024-12-12T01:12:25.000Z","dependencies_parsed_at":"2024-12-08T08:20:25.524Z","dependency_job_id":null,"html_url":"https://github.com/koho/nat2","commit_stats":null,"previous_names":["koho/nat2"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/koho/nat2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koho%2Fnat2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koho%2Fnat2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koho%2Fnat2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koho%2Fnat2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/koho","download_url":"https://codeload.github.com/koho/nat2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/koho%2Fnat2/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268331010,"owners_count":24233158,"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","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["full-cone-nat","hole-punching","nat","upnp"],"created_at":"2025-02-16T10:19:21.937Z","updated_at":"2026-02-09T14:32:45.383Z","avatar_url":"https://github.com/koho.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nat2\r\n\r\nnat2 simply means \"nat to\". It is a tool that helps you expose local services to the Internet in a Full-Cone NAT\r\nnetwork. Moreover, you can bind the mapped address automatically to your DNS provider or send it via HTTP request.\r\n\r\n## Features\r\n\r\n* Maintain the mapped address automatically.\r\n* Bind the mapped address and port to DNS record.\r\n* Support both TCP and UDP.\r\n* HTTP hook.\r\n* UPnP.\r\n\r\n## Mapping\r\n\r\nA mapping consists of two parts. The first part is called local endpoint url. The url scheme must be one\r\nof `tcp`, `udp`, `tcp+upnp`, or `udp+upnp`.\r\nThe url host is an IPv4 address and the port must be present. For example, a valid endpoint url is `tcp://0.0.0.0:6666`.\r\nThe usage of this address:port pair is depend on UPnP state. When UPnP is active, the address:port pair is called the\r\nforwarding address, which is the address of the local service that you want to open to the Internet.\r\nWhen UPnP is disabled, the address:port pair is called the listen address. You must manually add port forwarding rules\r\nin the gateway for the mapping to work properly.\r\nThe second part is called the watcher list, which is a list of tasks to be executed when the mapping is opened. Each\r\nwatcher is configured by the following JSON object.\r\n\r\n| Field    | Type   | Description                                                                                                |\r\n|----------|--------|------------------------------------------------------------------------------------------------------------|\r\n| name     | string | The existing name of the watcher.                                                                          |\r\n| value    | string | Value could contain placeholder `{ip}` and `{port}` which will be replaced with real value in the watcher. |\r\n| domain   | string | Domain name.                                                                                               |\r\n| type     | string | Record type.                                                                                               |\r\n| priority | int    | Record priority. This field is required for record type SVCB, HTTPS and MX.                                |\r\n| rid      | string | DNS record id. This field disables the automatic creation of dns records.                                  |\r\n| ttl      | int    | TTL to use for dns records.                                                                                |\r\n| proxied  | bool   | Whether the record is proxied by Cloudflare.                                                               |\r\n\r\n```json\r\n{\r\n  \"map\": {\r\n    \"tcp://0.0.0.0:6666\": [\r\n      {\r\n        \"name\": \"ddns\",\r\n        \"domain\": \"test.example.com\",\r\n        \"type\": \"HTTPS\",\r\n        \"value\": \". alpn=\\\"h2\\\" ipv4hint=\\\"{ip}\\\" port=\\\"{port}\\\"\",\r\n        \"priority\": 1\r\n      }\r\n    ]\r\n  }\r\n}\r\n```\r\n\r\n## Watcher\r\n\r\nA watcher watches the update of mapped address. The watcher get notified when the mapped address is updated, and then it\r\ncan perform specific task.\r\nYou can define multiple watchers at the same time, just give them different name.\r\n\r\n### DNSPod\r\n\r\nDNSPod is a managed DNS provider. You can bind your mapped address to DNS record automatically using your secret id and\r\nsecret key from DNSPod.\r\n\r\n```json\r\n{\r\n  \"dnspod\": {\r\n    \"personal\": {\r\n      \"secret_id\": \"\",\r\n      \"secret_key\": \"\"\r\n    },\r\n    \"company\": {\r\n      \"secret_id\": \"\",\r\n      \"secret_key\": \"\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### AliDNS\r\n\r\nAlibaba DNS is a managed DNS provider.\r\n\r\n| Field      | Type   | Description                                                                                                         |\r\n|------------|--------|---------------------------------------------------------------------------------------------------------------------|\r\n| url        | string | The request URL may vary by region. See https://api.aliyun.com/product/Alidns. Default is https://dns.aliyuncs.com. |\r\n| secret_id  | string | Similar to username.                                                                                                |\r\n| secret_key | string | Similar to password.                                                                                                |\r\n\r\n```json\r\n{\r\n  \"alidns\": {\r\n    \"example\": {\r\n      \"secret_id\": \"\",\r\n      \"secret_key\": \"\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### Cloudflare\r\n\r\nCloudflare DNS is a managed DNS provider.\r\n\r\n| Field | Type   | Description                                                                                 |\r\n|-------|--------|---------------------------------------------------------------------------------------------|\r\n| token | string | API token. See https://developers.cloudflare.com/fundamentals/api/get-started/create-token. |\r\n\r\n```json\r\n{\r\n  \"cf\": {\r\n    \"example\": {\r\n      \"token\": \"\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### HTTP\r\n\r\nHTTP request is a common solution for sending event. The request is fully configurable.\r\n\r\n| Field   | Type               | Description                                                                                                                                                        |\r\n|---------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|\r\n| url     | string             | Request url could contain placeholder `{ip}` and `{port}` which will be replaced with real value before sending the request.                                       |\r\n| method  | string             | Request method.                                                                                                                                                    |\r\n| body    | string             | Request body could be JSON string, plain text, etc... Placeholder `{ip}` and `{port}` are supported. Note that this value could be overridden by watcher metadata. |\r\n| headers | map\u003cstring,string\u003e | Request headers. For example, `Content-Type` should be set based on the content in the `body`.                                                                     |\r\n\r\n```json\r\n{\r\n  \"http\": {\r\n    \"api\": {\r\n      \"url\": \"https://api.example.com\",\r\n      \"method\": \"POST\",\r\n      \"body\": \"{\\\"content\\\":\\\"{ip}:{port}\\\"}\",\r\n      \"headers\": {\r\n        \"Content-Type\": \"application/json; charset=utf-8\"\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### Script\r\n\r\nRun a script or program.\r\n\r\n| Field | Type     | Description                                                                                                                                     |\r\n|-------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------|\r\n| path  | string   | Path to executable file.                                                                                                                        |\r\n| args  | []string | Arguments to pass to the program. If the `value` field in watcher metadata is not empty, it will be passed to the program as the last argument. |\r\n\r\nFor example, we have a python script named `test.py`:\r\n\r\n```python\r\nimport sys\r\nassert sys.argv[1] == \"x.x.x.x:22274\"\r\n```\r\n\r\nAnd our config file:\r\n\r\n```json\r\n{\r\n  \"map\": {\r\n    \"udp://0.0.0.0:5555\": [\r\n      {\r\n        \"name\": \"example\",\r\n        \"value\": \"{ip}:{port}\"\r\n      }\r\n    ]\r\n  },\r\n  \"script\": {\r\n    \"example\": {\r\n      \"path\": \"python\",\r\n      \"args\": [\r\n        \"test.py\"\r\n      ]\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n## Global options\r\n\r\n### TCP mapping\r\n\r\n| Field         | Type     | Description                                                                                                                                    |\r\n|---------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------|\r\n| stun          | []string | TCP STUN server address:port pairs. The server must support STUN over TCP protocol. It selects hosts based on round-robin ordering.            |\r\n| keepalive     | string   | Internet connectivity check url. Only HTTP protocol is supported. We will periodically fetch this url to maintain a long-lived TCP connection. |\r\n| interval      | int      | The interval in seconds between fetching the keepalive url.                                                                                    |\r\n| stun_interval | int      | The interval in seconds between sending binding request messages.                                                                              |\r\n\r\nThe following config is the default value:\r\n\r\n```json\r\n{\r\n  \"tcp\": {\r\n    \"stun\": [\r\n      \"turn.cloud-rtc.com:80\"\r\n    ],\r\n    \"keepalive\": \"http://www.baidu.com\",\r\n    \"interval\": 50,\r\n    \"stun_interval\": 300\r\n  }\r\n}\r\n```\r\n\r\n### UDP mapping\r\n\r\n| Field    | Type     | Description                                                                         |\r\n|----------|----------|-------------------------------------------------------------------------------------|\r\n| stun     | []string | UDP STUN server address:port pairs. It selects hosts based on round-robin ordering. |\r\n| interval | int      | The interval in seconds between sending binding request messages.                   |\r\n\r\nThe following config is the default value:\r\n\r\n```json\r\n{\r\n  \"udp\": {\r\n    \"stun\": [\r\n      \"stun.chat.bilibili.com:3478\",\r\n      \"stun.douyucdn.cn:18000\",\r\n      \"stun.hitv.com:3478\",\r\n      \"stun.miwifi.com:3478\"\r\n    ],\r\n    \"interval\": 20\r\n  }\r\n}\r\n```\r\n\r\n### UPnP\r\n\r\nWhether to use UPnP feature. Default is true. You can also use scheme `tcp+upnp://` or `udp+upnp://` to enable UPnP for\r\nspecific mapping.\r\n\r\nThe following config is the default value:\r\n\r\n```json\r\n{\r\n  \"upnp\": true\r\n}\r\n```\r\n\r\nIf UPnP is not available in your local network. You must turn off this option and manually add port forwarding rules in\r\nthe gateway for the mapping to work properly. For example, we have a TCP mapping.\r\n\r\n```json\r\n{\r\n  \"map\": {\r\n    \"tcp://0.0.0.0:50001\": []\r\n  },\r\n  \"upnp\": false\r\n}\r\n```\r\n\r\nIn the gateway, add a port forwarding rule.\r\n\r\n```shell\r\nsudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 50001 -j DNAT --to-destination 192.168.1.55:443\r\n```\r\n\r\nNow the endpoint 192.168.1.55:443 should be accessible via public mapped address.\r\n\r\n## Run\r\n\r\nThe default config file path is `config.json` in the current directory. You can also use\r\nargument `-c /path/to/your/config` to specify the config file path.\r\n\r\nFor example, run the service with the following command:\r\n\r\n```shell\r\nnat2 -c config.json\r\n```\r\n\r\nIf you want to see more logs, turn on debug mode using `--debug` flag.\r\n\r\n```shell\r\nnat2 --debug -c config.json\r\n```\r\n\r\n## Lookup domain\r\n\r\nYour can find your mapped address using `dig` or https://www.nslookup.io/svcb-lookup/.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkoho%2Fnat2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkoho%2Fnat2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkoho%2Fnat2/lists"}