Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cfb0a2d4a | |||
| 4fdbcb051a | |||
| 47c6006bb7 | |||
| dcfd0f77ad | |||
| 78fb779010 | |||
| b4544c2b48 | |||
| 37e3a101b1 | |||
| 45a1074377 | |||
| 1b9af19e20 | |||
| bdc0f5022d | |||
| 4f991061dd | |||
| e5aef76256 | |||
| 6acc54d2bc | |||
| ab6e08dd13 | |||
| e09066858c | |||
| 842ce93a60 | |||
| ce26105986 | |||
| cc95358385 | |||
| cc04a09ed7 | |||
| ae47d53f0c | |||
| e0ff09f323 | |||
| 10707fd2c5 | |||
| 9bdd2af14c | |||
| 228ef8b158 | |||
| d820131d2c | |||
| 054715a600 | |||
| 3f560180b7 | |||
| f62dbbdae0 | |||
| edecc4ba01 | |||
| 58c0e289c2 | |||
| 6d8edc4bc7 | |||
| a44cdf1c7c | |||
| 6b8a6283a4 | |||
| 94151965bb | |||
| e8ca490db1 | |||
| fe7470ea44 | |||
| 21d52244cb | |||
| c0c58026a8 | |||
| 0fe863c889 | |||
| 4e5d88f64c | |||
| 1559f6a912 | |||
| 766024be27 | |||
| 5ba181b118 | |||
| 76fc9f4a90 | |||
| 8ca6af7c86 | |||
| 45e14a7fb1 | |||
| a38917cb9b | |||
| cf8a399089 | |||
| ba01820586 | |||
| 8c799b2976 | |||
| de4fb6291c | |||
| 81fd37e5c0 | |||
| 219f3af967 | |||
| aea7442525 | |||
| 1525aed657 | |||
| 943b5fa8bc | |||
| 71e0c025c6 | |||
| 239c6c701b | |||
| 91d0b7bdad | |||
| 99b28b2b6f | |||
| 5627ada57e | |||
| 4e1228fff0 | |||
| 04be5624fa | |||
| a6fe1b1de7 | |||
| c5971d0e9d | |||
| 06dd74ba34 | |||
| c6a0256b03 | |||
| d04b61a88b | |||
| 70a119ac58 | |||
| e2fe3a60a6 | |||
| 71301ee0cc | |||
| aba6c9d4ac | |||
| c617bbb240 | |||
| 1f8144eb11 | |||
| 694135c81b | |||
| e815f08505 | |||
| f402da8e60 | |||
| 34a500d0a2 | |||
| ef52f25564 | |||
| 010b013094 | |||
| c503a5f0e8 | |||
| 781afd3522 | |||
| 58083df0b0 | |||
| 4e8d29d0c5 | |||
| 66797efa80 | |||
| 5a26fa262e | |||
| 73a34935ae | |||
| a8086675d9 | |||
| 0453345d65 | |||
| b56d9505e6 | |||
| bdacc72003 | |||
| 9eca9efd82 | |||
| cc74d218fc | |||
| dea8a287e6 | |||
| fc5d310935 | |||
| 4848d081d0 | |||
| b3452ede77 |
@@ -23,7 +23,7 @@ jobs:
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
@@ -54,6 +54,6 @@ jobs:
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
|
||||
- name: Typecheck with tsc
|
||||
run: yarn tsc
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
import { Callout } from 'nextra/components';
|
||||
import { Tabs } from 'nextra/components';
|
||||
import { Steps } from 'nextra/components';
|
||||
import { AccordionTemplate } from 'components/accordion-template.tsx';
|
||||
|
||||
export const ManagerIPOutput = () => (
|
||||
<div>
|
||||
Correct <code>./network-tunnel-manager.sh fetch_and_display_ipv6</code> output
|
||||
</div>
|
||||
);
|
||||
|
||||
export const ManagerTablesOutput = () => (
|
||||
<div>
|
||||
Correct <code>./network-tunnel-manager.sh check_nymtun_iptables</code> output
|
||||
</div>
|
||||
);
|
||||
|
||||
export const ShowTun = () => (
|
||||
<div>
|
||||
Correct <code>ip addr show nymtun0</code> output
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
<Callout>
|
||||
We recommend operators to configure their `nym-node` with the full routing configuration.
|
||||
|
||||
However, most of the time the packets sent through the Mixnet are IPv4 based. The IPv6 packets are still pretty rare and therefore it's not mandatory from operational point of view to have this configuration implemented if you running only `mixnode` mode.
|
||||
|
||||
If you preparing to run a `nym-node` with all modes enabled in the future, this setup is required.
|
||||
</Callout>
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
Networking configuration across different ISPs and various operation systems does not have a generic solution. If the provided configuration setup doesn't solve your problem check out [IPv6 troubleshooting](/operators/troubleshooting/vps-isp.mdx#ipv6-troubleshooting) page. Be aware that you may have to do more research, customised adjustments or contact your ISP to change settings for your VPS.
|
||||
</ Callout>
|
||||
|
||||
**Network Tunnel Manager ([`network-tunnel-manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh), NTM) is currently the one tool hadling the configuration of `nym-node` hosting server, according to the required design (node's [functionality](/operators/nodes/nym-node/setup#functionality-mode), WireGuard setup etc).**
|
||||
|
||||
**NTM cand administrate these areas:**
|
||||
|
||||
* IPv4 and IPv6 routing to the internet
|
||||
|
||||
* The `nymtun0` interface (Mixnet / 5-hop): dynamically managed by the `exit-gateway` service. When the service is stopped, `nymtun0` disappears, and when started, `nymtun0` is recreated.
|
||||
|
||||
* The `nymwg` interface (WG / 2-hop): used for creating a secure wireguard tunnel as part of the Nym Network configuration.
|
||||
|
||||
* `iptables` rules specific to `nymwg` to ensure proper routing and forwarding through the wireguard tunnel. The `nymwg` interface needs to be correctly configured and active for the related commands to function properly. This includes applying or removing iptables rules and running connectivity tests through the `nymwg` tunnel.
|
||||
|
||||
* WireGuard exit policy: Mixnet uses a common [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt), to apply the same for WG, the operators need to set that one up on their server using `iptables` rules.
|
||||
|
||||
* Testing and validating all above
|
||||
|
||||
**Before starting with the following configuration, make sure you have the [latest `nym-node` binary](https://github.com/nymtech/nym/releases) installed and your [VPS setup](../preliminary-steps/vps-setup.mdx) finished properly!**
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
**Run the following steps as root!**
|
||||
</ Callout>
|
||||
|
||||
**Choose configuration command according your setup**
|
||||
|
||||
<div>
|
||||
<Tabs items={[
|
||||
<strong>New <code>nym-node</ code> full configuration</strong>,
|
||||
<strong>Existing <code>nym-node</ code> full configuration</strong>,
|
||||
<strong>Step-by-step or Pprtial configuration</strong>
|
||||
]} defaultIndex={0}>
|
||||
<Tabs.Tab>
|
||||
This design is meant for operators setting up a new node on a fresh machine and it will result with a complete server readiness for routing as Entry Gateway and Exit Gateway in both Mixnet and WireGuard mode.
|
||||
|
||||
<Steps>
|
||||
###### 1. Download `network-tunnel-manager.sh`, make executable and run with `--help` command:
|
||||
|
||||
```sh
|
||||
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \
|
||||
chmod +x network-tunnel-manager.sh && \
|
||||
./network-tunnel-manager.sh --help
|
||||
```
|
||||
|
||||
###### 2. Make sure your `nym-node` service is up and running and bonded
|
||||
|
||||
- **If you setting up a new node and not upgrading an existing one, keep it running and [bond](/operators/nodes/nym-node/bonding.mdx) your node now! Then come back here and follow the rest of the configuration.**
|
||||
|
||||
###### 3. Execute complete network configuration:
|
||||
```sh
|
||||
./network-tunnel-manager.sh complete_networking_setup
|
||||
```
|
||||
</ Steps>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab>
|
||||
This is meant for operators configuring an existing and bonded node and it will result with a complete server readiness for routing as Entry Gateway and Exit Gateway in both Mixnet and WireGuard mode.
|
||||
|
||||
<Steps>
|
||||
###### 1. Download `network-tunnel-manager.sh`, make executable and run with `--help` command:
|
||||
|
||||
```sh
|
||||
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \
|
||||
chmod +x network-tunnel-manager.sh && \
|
||||
./network-tunnel-manager.sh --help
|
||||
```
|
||||
|
||||
###### 2. Execute complete network configuration:
|
||||
```sh
|
||||
./network-tunnel-manager.sh complete_networking_setup
|
||||
```
|
||||
</ Steps>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab>
|
||||
<Steps>
|
||||
This design is meant for operators who want to do their server configuration step by step or choose only some parts of the setup.
|
||||
|
||||
###### 1. Download `network-tunnel-manager.sh`, make executable and run with `--help` command:
|
||||
|
||||
```sh
|
||||
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \
|
||||
chmod +x network-tunnel-manager.sh && \
|
||||
./network-tunnel-manager.sh --help
|
||||
```
|
||||
|
||||
###### 2. Make sure your `nym-node` service is up and running and bonded
|
||||
|
||||
- **If you setting up a new node and not upgrading an existing one, keep it running and [bond](/operators/nodes/nym-node/bonding.mdx) your node now! Then come back here and follow the rest of the configuration.**
|
||||
|
||||
###### 3. Choose steps according your need
|
||||
|
||||
> You should be certain in your selection when configuring only various parts of the server.
|
||||
|
||||
###### Setup IP tables rules
|
||||
|
||||
- Delete IP tables rules for IPv4 and IPv6 and apply new ones:
|
||||
```sh
|
||||
./network-tunnel-manager.sh remove_duplicate_rules nymtun0
|
||||
|
||||
./network-tunnel-manager.sh apply_iptables_rules
|
||||
```
|
||||
|
||||
- The process may prompt you if you want to save current IPv4 and IPv6 rules, choose yes.
|
||||
|
||||

|
||||
|
||||
- At this point you should see a `global ipv6` address.
|
||||
```sh
|
||||
./network-tunnel-manager.sh fetch_and_display_ipv6
|
||||
```
|
||||
<br />
|
||||
<AccordionTemplate name={<ManagerTablesOutput/>}>
|
||||
```sh
|
||||
iptables-persistent is already installed.
|
||||
Using IPv6 address: 2001:db8:a160::1/112 #the address will be different for you
|
||||
operation fetch_ipv6_address_nym_tun completed successfully.
|
||||
```
|
||||
</AccordionTemplate>
|
||||
|
||||
###### Check Nymtun IP tables:
|
||||
|
||||
```sh
|
||||
./network-tunnel-manager.sh check_nymtun_iptables
|
||||
```
|
||||
|
||||
- If there's no process running it wouldn't return anything.
|
||||
- In case you see `nymtun0` but not active, this is probably because you are setting up a new (never bonded) node and not upgrading an existing one.
|
||||
|
||||
<br />
|
||||
<AccordionTemplate name={<ManagerIPOutput/>}>
|
||||
```sh
|
||||
iptables-persistent is already installed.
|
||||
network Device: eth0
|
||||
---------------------------------------
|
||||
|
||||
inspecting IPv4 firewall rules...
|
||||
Chain FORWARD (policy DROP 0 packets, 0 bytes)
|
||||
0 0 ufw-reject-forward all -- * * 0.0.0.0/0 0.0.0.0/0
|
||||
0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0
|
||||
0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0
|
||||
0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0
|
||||
0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
|
||||
---------------------------------------
|
||||
|
||||
inspecting IPv6 firewall rules...
|
||||
Chain FORWARD (policy DROP 0 packets, 0 bytes)
|
||||
0 0 ufw6-reject-forward all * * ::/0 ::/0
|
||||
0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0
|
||||
0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0
|
||||
0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0
|
||||
operation check_nymtun_iptables completed successfully.
|
||||
```
|
||||
</AccordionTemplate>
|
||||
|
||||
###### Remove old and apply new rules for wireguad routing
|
||||
|
||||
```sh
|
||||
../network-tunnel-manager.sh remove_duplicate_rules nymwg
|
||||
|
||||
./network-tunnel-manager.sh apply_iptables_rules_wg
|
||||
```
|
||||
|
||||
###### Apply rules to configure DNS routing and allow ICMP piung test for node probing (network testing)
|
||||
|
||||
```sh
|
||||
./network-tunnel-manager.sh configure_dns_and_icmp_wg
|
||||
```
|
||||
###### Adjust and validate IP forwarding
|
||||
|
||||
```sh
|
||||
./network-tunnel-manager.sh adjust_ip_forwarding
|
||||
|
||||
./network-tunnel-manager.sh check_ipv6_ipv4_forwarding
|
||||
```
|
||||
|
||||
###### Check `nymtun0` interface and test routing configuration
|
||||
|
||||
```sh
|
||||
ip addr show nymtun0
|
||||
```
|
||||
|
||||
<br />
|
||||
<AccordionTemplate name={<ShowTun/>}>
|
||||
```sh
|
||||
# your addresses will be different
|
||||
8: nymtun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1420 qdisc fq_codel state UNKNOWN group default qlen 500
|
||||
link/none
|
||||
inet 10.0.0.1/16 scope global nymtun0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fc00::1/112 scope global
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::ad08:d167:5700:8c7c/64 scope link stable-privacy
|
||||
valid_lft forever preferred_lft forever`
|
||||
```
|
||||
</AccordionTemplate>
|
||||
|
||||
- Validate your IPv6 and IPv4 networking by running a joke test via Mixnet:
|
||||
```sh
|
||||
./network-tunnel-manager.sh joke_through_the_mixnet
|
||||
```
|
||||
|
||||
- Validate your tunneling by running a joke test via WG:
|
||||
```sh
|
||||
../network-tunnel-manager.sh joke_through_wg_tunnel
|
||||
```
|
||||
|
||||
###### Enable wireguard
|
||||
|
||||
Now you can run your node with the `--wireguard-enabled true` flag or add it to your [systemd service config](#systemd). Restart your `nym-node` or [systemd](#2-following-steps-for-nym-nodes-running-as-systemd-service) service (recommended):
|
||||
|
||||
```sh
|
||||
systemctl daemon-reload && service nym-node restart
|
||||
```
|
||||
- Optionally, you can check if the node is running correctly by monitoring the service logs:
|
||||
|
||||
```sh
|
||||
journalctl -u nym-node.service -f -n 100
|
||||
```
|
||||
</ Steps>
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
Note that the functionality the node runs in is decided by [arguments on the node itself / in node's `config.toml`](/operators/nodes/nym-node/setup#functionality-mode), this tool only prepares the server.
|
||||
</ Callout>
|
||||
|
||||
Make sure that you get the validation of all connectivity. If there are still any problems, please refer to [troubleshooting section](/operators/troubleshooting/vps-isp.mdx#incorrect-gateway-network-check).
|
||||
@@ -0,0 +1,68 @@
|
||||
import { Callout } from 'nextra/components';
|
||||
import { Tabs } from 'nextra/components';
|
||||
import { Steps } from 'nextra/components';
|
||||
import { AccordionTemplate } from 'components/accordion-template.tsx';
|
||||
import ExitPolicyInstallOutput from 'components/operators/snippets/wg-exit-policy-install-output.mdx';
|
||||
import ExitPolicyStatusOutput from 'components/operators/snippets/wg-exit-policy-status-output.mdx';
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
**In case you had used `network-tunnel-manager.sh` with the command `complete_networking_setup`, your WireGuard exit policy is already setup. You can test it in the next chapter.**
|
||||
</ Callout>
|
||||
|
||||
Nym Node running as Exit Gateway has contains multiple modules, one of them is Nym Network Requester(NR), routing TCP traffic to the internet. To make sure that the node is not just an open proxy, NR checks agains [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) following these conditions (in this exact order):
|
||||
|
||||
1. Do we explicitly block those IP addresses regardless of ports?
|
||||
2. Do we allow those specific ports regardless of IPs?
|
||||
3. Do block EVERYTHING else!
|
||||
|
||||
The exit policy is same for all NRs, the content is shaped by an offchain governance of Nym Node operators on our [forum](https://forum.nym.com/t/poll-a-new-nym-exit-policy-for-exit-gateways-and-the-nym-mixnet-is-inbound/464).
|
||||
|
||||
There is a caveat though. NR is only routing TCP streams and therefore any other type of routing than Mixnet is *not* filtered thorugh the exit policy. To ensure that Nym Nodes follow the same exit policy when routing IP packets through WireGuard and don't act as open proxies, the operators have to set up these rules via IP tables rules.
|
||||
|
||||
**For all routing configuration we provide one tool [`network-tunnel-manager.sh` (NTM)](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh). This tool manages WireGuard exit policy as well.**
|
||||
|
||||
In case you haven't run `network-tunnel-manager.sh` with the command `complete_networking_setup` you need to use NTM for WireGuard exit policy configuration.
|
||||
|
||||
**Folow these steps**
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
**Run the following steps as root!**
|
||||
</ Callout>
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Download `network-tunnel-manager.sh`, make executable and run with `--help` command:
|
||||
|
||||
```sh
|
||||
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \
|
||||
chmod +x network-tunnel-manager.sh && \
|
||||
./network-tunnel-manager.sh --help
|
||||
```
|
||||
|
||||
###### 2. Install exit policy
|
||||
|
||||
- Clear old rules and configure new ones:
|
||||
```sh
|
||||
./network-tunnel-manager.sh exit_policy_clear
|
||||
./network-tunnel-manager.sh exit_policy_install
|
||||
```
|
||||
- The output should look like this:
|
||||
<AccordionTemplate name="Cosole output">
|
||||
<ExitPolicyInstallOutput />
|
||||
</ AccordionTemplate>
|
||||
|
||||
|
||||
###### 3. Check status of your configuration
|
||||
```sh
|
||||
./network-tunnel-manager.sh exit_policy_status
|
||||
```
|
||||
|
||||
- The output should look like this:
|
||||
<AccordionTemplate name="Cosole output">
|
||||
<ExitPolicyStatusOutput />
|
||||
</ AccordionTemplate>
|
||||
</ Steps>
|
||||
|
||||
Now your WireGuard routing (2-hop) should have same rotuing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet) mode of NymVPN.
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Tabs } from 'nextra/components';
|
||||
import { Steps } from 'nextra/components';
|
||||
|
||||
import ExitPolicyTestServer from 'components/operators/snippets/wg-exit-policy-testing-from-server.mdx';
|
||||
import ExitPolicyTestOutside from 'components/operators/snippets/wg-exit-policy-testing-from-outside.mdx';
|
||||
|
||||
**For all routing configuration we provide one tool [`network-tunnel-manager.sh` (NTM)](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh). This tool manages WireGuard tests all configurations, including WireGuard exit policy as well.**
|
||||
|
||||
|
||||
You can use NTM to validate the application of the IP tables routes on your `nym-node` by checking it from the server side as well as from the outside.
|
||||
|
||||
<div>
|
||||
<Tabs items={[
|
||||
<strong>From the server</strong>,
|
||||
<strong>From the outside - using NymVPN</strong>
|
||||
]} defaultIndex={0}>
|
||||
<Tabs.Tab><ExitPolicyTestServer /></Tabs.Tab>
|
||||
<Tabs.Tab><ExitPolicyTestOutside /></Tabs.Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
|
||||
If all works , your node has successfully implemented WireGuard exit policy with the same routing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet) for TCP routing.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+22
-2
@@ -1,9 +1,29 @@
|
||||
import { Steps } from 'nextra/components';
|
||||
|
||||
Here are a few ways you can ensre your WireGuard exit policy is working correctly from the outside.
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Using NymVPN
|
||||
|
||||
- Connect to NymVPN and use your node as an Exit Gateway in dVPN (2-hop) mode
|
||||
|
||||
- While connected to NymVPN, navigate to [`portquiz.net:12345`](http://portquiz.net:12345) and see if you can load the page
|
||||
|
||||
- It shouldn't load, but if you navigate to some of the accepted ports, like[`portquiz.net:443`](http://portquiz.net:443) it should all work
|
||||
|
||||
###### 2. Testing from your local terminal
|
||||
|
||||
- Install these dependencies on your local machine:
|
||||
```shell
|
||||
sudo apt install tcpdump
|
||||
|
||||
sudo tcpdump -i nymwg -n
|
||||
```
|
||||
- Connect to [NymVPN](https://nym.com) and select your node as an Exit Gateway (after running the exit policy [manager script](#wireguard-exit-policy-configuration))
|
||||
- Connect to [NymVPN](https://nym.com) and select your node as an Exit Gateway
|
||||
|
||||
- Run the `tcpdump` command before registering
|
||||
- Have the output of the `echo $BLOCKED_IP` from your node and try to go into your browser or a registered client and try to connect - It will not resolve.
|
||||
|
||||
- Have the output of the `echo $BLOCKED_IP` from your node and try to go into your browser or a registered client and try to connect - It should not resolve
|
||||
|
||||
</ Steps>
|
||||
+31
-3
@@ -1,11 +1,39 @@
|
||||
Run this command to define variable `BLOCKED_IP` and try to `ping` it:
|
||||
import { Steps } from 'nextra/components';
|
||||
import { AccordionTemplate } from 'components/accordion-template.tsx';
|
||||
import ExitPolicyTestOutput from 'components/operators/snippets/wg-exit-policy-test-output.mdx';
|
||||
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Make sure to have the latest NTM:
|
||||
```sh
|
||||
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \
|
||||
chmod +x network-tunnel-manager.sh && \
|
||||
./network-tunnel-manager.sh --help
|
||||
```
|
||||
|
||||
###### 2. Run tests with NTM
|
||||
```sh
|
||||
./network-tunnel-manager.sh exit_policy_test_connectivity
|
||||
./network-tunnel-manager.sh exit_policy_tests
|
||||
```
|
||||
|
||||
- The output should look like this:
|
||||
<AccordionTemplate name="Cosole output">
|
||||
<ExitPolicyTestOutput />
|
||||
</ AccordionTemplate>
|
||||
|
||||
###### 3. Optionally you can do some manual sanity checks
|
||||
- Run this command to define variable `BLOCKED_IP` and try to `ping` it:
|
||||
```shell
|
||||
BLOCKED_IP=$(grep "ExitPolicy reject" /etc/nym/exit-policy.txt | head -1 | sed -E 's/ExitPolicy reject ([^:]+):.*/\1/' | sed 's/\/.*$//')
|
||||
|
||||
ping -c 3 $BLOCKED_IP
|
||||
```
|
||||
You should see `100% packet loss` as an outcome.
|
||||
- You should see `100% packet loss` as an outcome.
|
||||
```shell
|
||||
telnet $BLOCKED_IP 80
|
||||
```
|
||||
You should see `telnet: Unable to connect to remote host: Connection timed out`.
|
||||
- You should see `telnet: Unable to connect to remote host: Connection timed out`.
|
||||
|
||||
</ Steps>
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.77%
|
||||
0.79%
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
37.305
|
||||
36.446
|
||||
|
||||
@@ -1 +1 @@
|
||||
Monday, November 10th 2025, 13:30:27 UTC
|
||||
Thursday, November 20th 2025, 12:33:19 UTC
|
||||
|
||||
@@ -1108,22 +1108,22 @@ const config = {
|
||||
form-action 'self';
|
||||
frame-ancestors 'none';
|
||||
upgrade-insecure-requests;
|
||||
connect-src 'self' https://github.com *.vercel.app *.nymtech.net *.nymvpn.com *.nymte.ch *.nyx.network *.nym.com https://nym.com nymvpn.com https://nymvpn.com *.nymtech.cc;
|
||||
connect-src 'self' wss: https://github.com *.vercel.app *.nymtech.net *.nymvpn.com *.nymte.ch *.nyx.network *.nym.com https://nym.com nymvpn.com https://nymvpn.com *.nymtech.cc;
|
||||
frame-src 'self' https://vercel.live *.vercel.app *.nym.com https://nym.com;
|
||||
worker-src 'self' blob: https://vercel.live *.vercel.app *.nym.com https://nym.com;
|
||||
`;
|
||||
return [
|
||||
{
|
||||
source: '/(.*)',
|
||||
source: "/(.*)",
|
||||
headers: [
|
||||
{
|
||||
key: 'Content-Security-Policy',
|
||||
key: "Content-Security-Policy",
|
||||
value: csp.replace(/\s{2,}/g, " ").trim(),
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
||||
@@ -3,34 +3,11 @@ import { Tabs } from 'nextra/components';
|
||||
import { VarInfo } from 'components/variable-info.tsx';
|
||||
import { Steps } from 'nextra/components';
|
||||
import { AccordionTemplate } from 'components/accordion-template.tsx';
|
||||
import ExitPolicyInstallOutput from 'components/operators/snippets/wg-exit-policy-install-output.mdx';
|
||||
import ExitPolicyStatusOutput from 'components/operators/snippets/wg-exit-policy-status-output.mdx';
|
||||
import ExitPolicyTestOutput from 'components/operators/snippets/wg-exit-policy-test-output.mdx';
|
||||
import ExitPolicyTestServer from 'components/operators/snippets/wg-exit-policy-testing-from-server.mdx';
|
||||
import ExitPolicyTestOutside from 'components/operators/snippets/wg-exit-policy-testing-from-outside.mdx';
|
||||
import WGExitPolicyConf from 'components/operators/snippets/wg-exit-policy-conf.mdx';
|
||||
import WGExitPolicyTest from 'components/operators/snippets/wg-exit-policy-test.mdx';
|
||||
import RoutingConf from 'components/operators/snippets/routing-conf.mdx';
|
||||
import QuicDeploymentSteps from 'components/operators/snippets/quic-bridge-deployment-script-setup.mdx';
|
||||
|
||||
|
||||
export const ManagerIPOutput = () => (
|
||||
<div>
|
||||
Correct <code>./network_tunnel_manager.sh fetch_and_display_ipv6</code> output
|
||||
</div>
|
||||
);
|
||||
|
||||
export const ManagerTablesOutput = () => (
|
||||
<div>
|
||||
Correct <code>./network_tunnel_manager.sh check_nymtun_iptables</code> output
|
||||
</div>
|
||||
);
|
||||
|
||||
export const ShowTun = () => (
|
||||
<div>
|
||||
Correct <code>ip addr show nymtun0</code> output
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
|
||||
# Nym Node Configuration
|
||||
|
||||
<VarInfo />
|
||||
@@ -222,9 +199,11 @@ This lets your operating system know it's ok to reload the service configuration
|
||||
</Steps>
|
||||
|
||||
|
||||
## Connectivity Test and Configuration
|
||||
## Routing Configuration
|
||||
|
||||
During our ongoing testing events we found out, that after introducing IP Packet Router (IPR) and [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) on embedded Network Requester (NR) by default, only a fragment of Gateways routes correctly through IPv4 and IPv6. We built a useful monitor to check out your Gateway (`nym-node --mode exit-gateway`) at [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/).
|
||||
<RoutingConf />
|
||||
|
||||
### Quick IPv6 Check
|
||||
|
||||
IPv6 routing is not only a case for gateways. Imagine a rare occasion when you run a `mixnode` without IPv6 enabled and a client will sent IPv6 packets through the Mixnet through such route:
|
||||
```ascii
|
||||
@@ -232,19 +211,6 @@ IPv6 routing is not only a case for gateways. Imagine a rare occasion when you r
|
||||
```
|
||||
In this (unusual) case your `mixnode` will not be able to route the packets. The node will drop the packets and its performance would go down. For that reason it's beneficial to have IPv6 enabled when running a `mixnode` functionality.
|
||||
|
||||
<Callout>
|
||||
We recommend operators to configure their `nym-node` with the full routing configuration.
|
||||
|
||||
However, most of the time the packets sent through the Mixnet are IPv4 based. The IPv6 packets are still pretty rare and therefore it's not mandatory from operational point of view to have this configuration implemented if you running only `mixnode` mode.
|
||||
|
||||
If you preparing to run a `nym-node` with all modes enabled in the future, this setup is required.
|
||||
</Callout>
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
For everyone participating in Delegation Program or Service Grant program, this setup is a requirement!
|
||||
</Callout>
|
||||
|
||||
### Quick IPv6 Check
|
||||
|
||||
You can always check IPv6 address and connectivity by using some of these methods:
|
||||
<br />
|
||||
@@ -273,267 +239,13 @@ telnet -6 ipv6.telnetmyip.com
|
||||
Make sure to keep your IPv4 address enabled while setting up IPv6, as the majority of routing goes through that one!
|
||||
</Callout>
|
||||
|
||||
### Routing Configuration
|
||||
|
||||
While we're working on Rust implementation to have these settings as a part of the binary build, to solve these connectivity requirements in the meantime we wrote a script [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) to support operators to configure their servers and address all the connectivity requirements.
|
||||
|
||||
Networking configuration across different ISPs and various operation systems does not have a generic solution. If the provided configuration setup doesn't solve your problem check out [IPv6 troubleshooting](../../troubleshooting/vps-isp.mdx#ipv6-troubleshooting) page. Be aware that you may have to do more research, customised adjustments or contact your ISP to change settings for your VPS.
|
||||
|
||||
The `nymtun0` interface is dynamically managed by the `exit-gateway` service. When the service is stopped, `nymtun0` disappears, and when started, `nymtun0` is recreated.
|
||||
|
||||
The `nymwg` interface is used for creating a secure wireguard tunnel as part of the Nym Network configuration. Similar to `nymtun0`, the script manages iptables rules specific to `nymwg` to ensure proper routing and forwarding through the wireguard tunnel. The `nymwg` interface needs to be correctly configured and active for the related commands to function properly. This includes applying or removing iptables rules and running connectivity tests through the `nymwg` tunnel.
|
||||
|
||||
The script should be used in a context where `nym-node` is running to fully utilise its capabilities, particularly for fetching IPv6 addresses or applying network rules that depend on the `nymtun0` and `nymwg` interfaces and to establish a WireGuard tunnel.
|
||||
|
||||
**Before starting with the following configuration, make sure you have the [latest `nym-node` binary](https://github.com/nymtech/nym/releases) installed and your [VPS setup](../preliminary-steps/vps-setup.mdx) finished properly!**
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Download `network_tunnel_manager.sh`, make executable and run:
|
||||
|
||||
```sh
|
||||
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/network_tunnel_manager.sh -o network_tunnel_manager.sh && \
|
||||
chmod +x network_tunnel_manager.sh && \
|
||||
./network_tunnel_manager.sh
|
||||
```
|
||||
|
||||
###### 2. Make sure your `nym-node` service is up and running and bond
|
||||
|
||||
- **If you setting up a new node and not upgrading an existing one, keep it running and [bond](bonding.mdx) your node now**. Then come back here and follow the rest of the configuration.
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
**Run the following steps as root or with `sudo` prefix!**
|
||||
</Callout>
|
||||
|
||||
|
||||
###### 3. Setup IP tables rules
|
||||
|
||||
- Delete IP tables rules for IPv4 and IPv6 and apply new ones:
|
||||
```sh
|
||||
./network_tunnel_manager.sh remove_duplicate_rules nymtun0
|
||||
|
||||
./network_tunnel_manager.sh apply_iptables_rules
|
||||
```
|
||||
|
||||
- The process may prompt you if you want to save current IPv4 and IPv6 rules, choose yes.
|
||||
|
||||

|
||||
|
||||
- At this point you should see a `global ipv6` address.
|
||||
```sh
|
||||
./network_tunnel_manager.sh fetch_and_display_ipv6
|
||||
```
|
||||
<br />
|
||||
<AccordionTemplate name={<ManagerTablesOutput/>}>
|
||||
```sh
|
||||
iptables-persistent is already installed.
|
||||
Using IPv6 address: 2001:db8:a160::1/112 #the address will be different for you
|
||||
operation fetch_ipv6_address_nym_tun completed successfully.
|
||||
```
|
||||
</AccordionTemplate>
|
||||
|
||||
###### 4. Check Nymtun IP tables:
|
||||
|
||||
```sh
|
||||
./network_tunnel_manager.sh check_nymtun_iptables
|
||||
```
|
||||
|
||||
- If there's no process running it wouldn't return anything.
|
||||
- In case you see `nymtun0` but not active, this is probably because you are setting up a new (never bonded) node and not upgrading an existing one.
|
||||
|
||||
<br />
|
||||
<AccordionTemplate name={<ManagerIPOutput/>}>
|
||||
```sh
|
||||
iptables-persistent is already installed.
|
||||
network Device: eth0
|
||||
---------------------------------------
|
||||
|
||||
inspecting IPv4 firewall rules...
|
||||
Chain FORWARD (policy DROP 0 packets, 0 bytes)
|
||||
0 0 ufw-reject-forward all -- * * 0.0.0.0/0 0.0.0.0/0
|
||||
0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0
|
||||
0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0
|
||||
0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0
|
||||
0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
|
||||
---------------------------------------
|
||||
|
||||
inspecting IPv6 firewall rules...
|
||||
Chain FORWARD (policy DROP 0 packets, 0 bytes)
|
||||
0 0 ufw6-reject-forward all * * ::/0 ::/0
|
||||
0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0
|
||||
0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0
|
||||
0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED
|
||||
0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0
|
||||
operation check_nymtun_iptables completed successfully.
|
||||
```
|
||||
</AccordionTemplate>
|
||||
|
||||
###### 5. Remove old and apply new rules for wireguad routing
|
||||
|
||||
```sh
|
||||
/network_tunnel_manager.sh remove_duplicate_rules nymwg
|
||||
|
||||
./network_tunnel_manager.sh apply_iptables_rules_wg
|
||||
```
|
||||
|
||||
###### 6. Apply rules to configure DNS routing and allow ICMP piung test for node probing (network testing)
|
||||
|
||||
```sh
|
||||
./network_tunnel_manager.sh configure_dns_and_icmp_wg
|
||||
```
|
||||
###### 7. Adjust and validate IP forwarding
|
||||
|
||||
```sh
|
||||
./network_tunnel_manager.sh adjust_ip_forwarding
|
||||
|
||||
./network_tunnel_manager.sh check_ipv6_ipv4_forwarding
|
||||
```
|
||||
|
||||
###### 8. Check `nymtun0` interface and test routing configuration
|
||||
|
||||
```sh
|
||||
ip addr show nymtun0
|
||||
```
|
||||
|
||||
<br />
|
||||
<AccordionTemplate name={<ShowTun/>}>
|
||||
```sh
|
||||
# your addresses will be different
|
||||
8: nymtun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1420 qdisc fq_codel state UNKNOWN group default qlen 500
|
||||
link/none
|
||||
inet 10.0.0.1/16 scope global nymtun0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fc00::1/112 scope global
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::ad08:d167:5700:8c7c/64 scope link stable-privacy
|
||||
valid_lft forever preferred_lft forever`
|
||||
```
|
||||
</AccordionTemplate>
|
||||
|
||||
- Validate your IPv6 and IPv4 networking by running a joke test via Mixnet:
|
||||
```sh
|
||||
./network_tunnel_manager.sh joke_through_the_mixnet
|
||||
```
|
||||
|
||||
- Validate your tunneling by running a joke test via WG:
|
||||
```sh
|
||||
./network_tunnel_manager.sh joke_through_wg_tunnel
|
||||
```
|
||||
|
||||
- **Note:** WireGuard will return only IPv4 joke, not IPv6. WG IPv6 is under development. Running IPR joke through the mixnet with `./network_tunnel_manager.sh joke_through_the_mixnet` should work with both IPv4 and IPv6!
|
||||
|
||||
|
||||
###### 9. Enable wireguard
|
||||
|
||||
Now you can run your node with the `--wireguard-enabled true` flag or add it to your [systemd service config](#systemd). Restart your `nym-node` or [systemd](#2-following-steps-for-nym-nodes-running-as-systemd-service) service (recommended):
|
||||
|
||||
```sh
|
||||
systemctl daemon-reload && service nym-node restart
|
||||
```
|
||||
- Optionally, you can check if the node is running correctly by monitoring the service logs:
|
||||
|
||||
```sh
|
||||
journalctl -u nym-node.service -f -n 100
|
||||
```
|
||||
</Steps>
|
||||
|
||||
Make sure that you get the validation of all connectivity. If there are still any problems, please refer to [troubleshooting section](../../troubleshooting/vps-isp.mdx#incorrect-gateway-network-check).
|
||||
|
||||
## Wireguard Exit Policy Configuration
|
||||
|
||||
Nym Node running as Exit Gateway has contains multiple modules, one of them is Nym Network Requester(NR), routing TCP traffic to the internet. To make sure that the node is not just an open proxy, NR checks agains [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) following these conditions (in this exact order):
|
||||
|
||||
1. Do we explicitly block those IP addresses regardless of ports?
|
||||
2. Do we allow those specific ports regardless of IPs?
|
||||
3. Do block EVERYTHING else!
|
||||
|
||||
The exit policy is same for all NRs, the content is shaped by an offchain governance of Nym Node operators on our [forum](https://forum.nym.com/t/poll-a-new-nym-exit-policy-for-exit-gateways-and-the-nym-mixnet-is-inbound/464).
|
||||
|
||||
There is a caveat though. NR is only routing TCP streams and therefore any other type of routing is *not* filtered thorugh the exit policy. To ensure that Nym Nodes follow the same exit policy when routing IP packets through wireguard and don't act as open proxies, the operators have to set up these rules via IP tables rules.
|
||||
|
||||
**Follow these steps, using a [setup script](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh) and [testing scripts](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/exit-policy-tests.sh) written by Nym quality assurance team, to setup exit policy for wireguard:**
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Download the scripts and make executable
|
||||
|
||||
- SSH to your node
|
||||
- Create a folder `~/nym-binaries` and navigate there
|
||||
```sh
|
||||
mkdir $HOME/nym-binaries
|
||||
cd $HOME/nym-binaries
|
||||
```
|
||||
- Download the scripts
|
||||
```sh
|
||||
wget https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh
|
||||
|
||||
wget https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/exit-policy-tests.sh
|
||||
```
|
||||
- Make executable
|
||||
```sh
|
||||
chmod +x wireguard-exit-policy-manager.sh exit-policy-tests.sh
|
||||
```
|
||||
|
||||
###### 2. Install `wireguard-exit-policy-manager.sh`
|
||||
```sh
|
||||
./wireguard-exit-policy-manager.sh install
|
||||
```
|
||||
- The output should look like this:
|
||||
<AccordionTemplate name="Cosole output">
|
||||
<ExitPolicyInstallOutput />
|
||||
</ AccordionTemplate>
|
||||
|
||||
|
||||
###### 3. Run `wireguard-exit-policy-manager.sh`
|
||||
```sh
|
||||
./wireguard-exit-policy-manager.sh status
|
||||
```
|
||||
|
||||
- The output should look like this:
|
||||
<AccordionTemplate name="Cosole output">
|
||||
<ExitPolicyStatusOutput />
|
||||
</ AccordionTemplate>
|
||||
|
||||
###### 4. Test with `exit-policy-tests.sh`
|
||||
|
||||
```sh
|
||||
./exit-policy-tests.sh
|
||||
```
|
||||
|
||||
- The output should look like this:
|
||||
<AccordionTemplate name="Cosole output">
|
||||
<ExitPolicyTestOutput />
|
||||
</ AccordionTemplate>
|
||||
|
||||
###### 5. In case of problems, you can clear the exit policy rule
|
||||
```sh
|
||||
./wireguard-exit-policy-manager.sh clear
|
||||
|
||||
./wireguard-exit-policy-manager.sh status
|
||||
```
|
||||
</ Steps>
|
||||
|
||||
Now your wireguart routing should have same rotuing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet) mode of NymVPN.
|
||||
<WGExitPolicyConf />
|
||||
|
||||
### Testing Wireguard Exit Policy
|
||||
|
||||
You can validate the application of the IP tables routes on your `nym-node` by checking it from the server side as well as from the outside.
|
||||
|
||||
<div>
|
||||
<Tabs items={[
|
||||
<strong>From the server</strong>,
|
||||
<strong>From the outside - using NymVPN</strong>
|
||||
]} defaultIndex={0}>
|
||||
<Tabs.Tab><ExitPolicyTestServer /></Tabs.Tab>
|
||||
<Tabs.Tab><ExitPolicyTestOutside /></Tabs.Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
Your node has successfully implemented wireguard exit policy with the same routing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet).
|
||||
<WGExitPolicyTest />
|
||||
|
||||
## QUIC Transport Bridge Deployment
|
||||
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
network_device=$(ip route show default | awk '/default/ {print $5}')
|
||||
tunnel_interface="nymtun0"
|
||||
wg_tunnel_interface="nymwg"
|
||||
|
||||
if ! dpkg -s iptables-persistent >/dev/null 2>&1; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y iptables-persistent
|
||||
else
|
||||
echo "iptables-persistent is already installed."
|
||||
fi
|
||||
|
||||
fetch_ipv6_address() {
|
||||
local interface=$1
|
||||
ipv6_global_address=$(ip -6 addr show "$interface" scope global | grep inet6 | awk '{print $2}' | head -n 1)
|
||||
|
||||
if [[ -z "$ipv6_global_address" ]]; then
|
||||
echo "no globally routable IPv6 address found on $interface. Please configure IPv6 or check your network settings."
|
||||
exit 1
|
||||
else
|
||||
echo "using IPv6 address: $ipv6_global_address"
|
||||
fi
|
||||
}
|
||||
|
||||
fetch_and_display_ipv6() {
|
||||
ipv6_address=$(ip -6 addr show "$network_device" scope global | grep inet6 | awk '{print $2}')
|
||||
if [[ -z "$ipv6_address" ]]; then
|
||||
echo "no global IPv6 address found on $network_device."
|
||||
else
|
||||
echo "IPv6 address on $network_device: $ipv6_address"
|
||||
fi
|
||||
}
|
||||
|
||||
remove_duplicate_rules() {
|
||||
local interface=$1
|
||||
local script_name=$(basename "$0")
|
||||
|
||||
if [[ -z "$interface" ]]; then
|
||||
echo "error: no interface specified. please enter the interface (nymwg or nymtun0):"
|
||||
read -r interface
|
||||
fi
|
||||
|
||||
if [[ "$interface" != "nymwg" && "$interface" != "nymtun0" ]]; then
|
||||
echo "error: invalid interface '$interface'. allowed values are 'nymwg' or 'nymtun0'." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "removing duplicate rules for $interface..."
|
||||
|
||||
iptables-save | grep "$interface" | while read -r line; do
|
||||
sudo iptables -D ${line#-A } || echo "Failed to delete rule: $line"
|
||||
done
|
||||
|
||||
ip6tables-save | grep "$interface" | while read -r line; do
|
||||
sudo ip6tables -D ${line#-A } || echo "Failed to delete rule: $line"
|
||||
done
|
||||
|
||||
echo "duplicates removed for $interface."
|
||||
echo "!!-important-!! you need to now reapply the iptables rules for $interface."
|
||||
if [ "$interface" == "nymwg" ]; then
|
||||
echo "run: ./$script_name apply_iptables_rules_wg"
|
||||
else
|
||||
echo "run: ./$script_name apply_iptables_rules"
|
||||
fi
|
||||
}
|
||||
|
||||
adjust_ip_forwarding() {
|
||||
ipv6_forwarding_setting="net.ipv6.conf.all.forwarding=1"
|
||||
ipv4_forwarding_setting="net.ipv4.ip_forward=1"
|
||||
|
||||
# remove duplicate entries for these settings from the file
|
||||
sudo sed -i "/^net.ipv6.conf.all.forwarding=/d" /etc/sysctl.conf
|
||||
sudo sed -i "/^net.ipv4.ip_forward=/d" /etc/sysctl.conf
|
||||
|
||||
echo "$ipv6_forwarding_setting" | sudo tee -a /etc/sysctl.conf
|
||||
echo "$ipv4_forwarding_setting" | sudo tee -a /etc/sysctl.conf
|
||||
|
||||
sudo sysctl -p /etc/sysctl.conf
|
||||
|
||||
}
|
||||
|
||||
apply_iptables_rules() {
|
||||
local interface=$1
|
||||
echo "applying IPtables rules for $interface..."
|
||||
sleep 2
|
||||
|
||||
sudo iptables -t nat -A POSTROUTING -o "$network_device" -j MASQUERADE
|
||||
sudo iptables -A FORWARD -i "$interface" -o "$network_device" -j ACCEPT
|
||||
sudo iptables -A FORWARD -i "$network_device" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
|
||||
sudo ip6tables -t nat -A POSTROUTING -o "$network_device" -j MASQUERADE
|
||||
sudo ip6tables -A FORWARD -i "$interface" -o "$network_device" -j ACCEPT
|
||||
sudo ip6tables -A FORWARD -i "$network_device" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
|
||||
sudo iptables-save | sudo tee /etc/iptables/rules.v4
|
||||
sudo ip6tables-save | sudo tee /etc/iptables/rules.v6
|
||||
}
|
||||
|
||||
check_tunnel_iptables() {
|
||||
local interface=$1
|
||||
echo "inspecting IPtables rules for $interface..."
|
||||
echo "---------------------------------------"
|
||||
echo "IPv4 rules:"
|
||||
iptables -L FORWARD -v -n | awk -v dev="$interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw-reject-forward"'
|
||||
echo "---------------------------------------"
|
||||
echo "IPv6 rules:"
|
||||
ip6tables -L FORWARD -v -n | awk -v dev="$interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw6-reject-forward"'
|
||||
}
|
||||
|
||||
check_ipv6_ipv4_forwarding() {
|
||||
result_ipv4=$(cat /proc/sys/net/ipv4/ip_forward)
|
||||
result_ipv6=$(cat /proc/sys/net/ipv6/conf/all/forwarding)
|
||||
echo "IPv4 forwarding is $([ "$result_ipv4" == "1" ] && echo "enabled" || echo "not enabled")."
|
||||
echo "IPv6 forwarding is $([ "$result_ipv6" == "1" ] && echo "enabled" || echo "not enabled")."
|
||||
}
|
||||
|
||||
check_ip_routing() {
|
||||
echo "IPv4 routing table:"
|
||||
ip route
|
||||
echo "---------------------------------------"
|
||||
echo "IPv6 routing table:"
|
||||
ip -6 route
|
||||
}
|
||||
|
||||
perform_pings() {
|
||||
echo "performing IPv4 ping to google.com..."
|
||||
ping -c 4 google.com
|
||||
echo "---------------------------------------"
|
||||
echo "performing IPv6 ping to google.com..."
|
||||
ping6 -c 4 google.com
|
||||
}
|
||||
|
||||
joke_through_tunnel() {
|
||||
local interface=$1
|
||||
local green="\033[0;32m"
|
||||
local reset="\033[0m"
|
||||
local red="\033[0;31m"
|
||||
local yellow="\033[0;33m"
|
||||
|
||||
sleep 1
|
||||
echo
|
||||
echo -e "${yellow}checking tunnel connectivity and fetching a joke for $interface...${reset}"
|
||||
echo -e "${yellow}if these test succeeds, it confirms your machine can reach the outside world via IPv4 and IPv6.${reset}"
|
||||
echo -e "${yellow}however, probes and external clients may experience different connectivity to your nym-node.${reset}"
|
||||
|
||||
ipv4_address=$(ip addr show "$interface" | awk '/inet / {print $2}' | cut -d'/' -f1)
|
||||
ipv6_address=$(ip addr show "$interface" | awk '/inet6 / && $2 !~ /^fe80/ {print $2}' | cut -d'/' -f1)
|
||||
|
||||
if [[ -z "$ipv4_address" && -z "$ipv6_address" ]]; then
|
||||
echo -e "${red}no IP address found on $interface. unable to fetch a joke.${reset}"
|
||||
echo -e "${red}please verify your tunnel configuration and ensure the interface is up.${reset}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -n "$ipv4_address" ]]; then
|
||||
echo
|
||||
echo -e "------------------------------------"
|
||||
echo -e "detected IPv4 address: $ipv4_address"
|
||||
echo -e "testing IPv4 connectivity..."
|
||||
echo
|
||||
|
||||
if ping -c 1 -I "$ipv4_address" google.com >/dev/null 2>&1; then
|
||||
echo -e "${green}IPv4 connectivity is working. fetching a joke...${reset}"
|
||||
joke=$(curl -s -H "Accept: application/json" --interface "$ipv4_address" https://icanhazdadjoke.com/ | jq -r .joke)
|
||||
[[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}IPv4 joke: $joke${reset}" || echo -e "failed to fetch a joke via IPv4."
|
||||
else
|
||||
echo -e "${red}IPv4 connectivity is not working for $interface. verify your routing and NAT settings.${reset}"
|
||||
fi
|
||||
else
|
||||
echo -e "${red}no IPv4 address found on $interface. unable to fetch a joke via IPv4.${reset}"
|
||||
fi
|
||||
|
||||
if [[ -n "$ipv6_address" ]]; then
|
||||
echo
|
||||
echo -e "------------------------------------"
|
||||
echo -e "detected IPv6 address: $ipv6_address"
|
||||
echo -e "testing IPv6 connectivity..."
|
||||
echo
|
||||
|
||||
if ping6 -c 1 -I "$ipv6_address" google.com >/dev/null 2>&1; then
|
||||
echo -e "${green}IPv6 connectivity is working. fetching a joke...${reset}"
|
||||
joke=$(curl -s -H "Accept: application/json" --interface "$ipv6_address" https://icanhazdadjoke.com/ | jq -r .joke)
|
||||
[[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}IPv6 joke: $joke${reset}" || echo -e "${red}failed to fetch a joke via IPv6.${reset}"
|
||||
else
|
||||
echo -e "${red}IPv6 connectivity is not working for $interface. verify your routing and NAT settings.${reset}"
|
||||
fi
|
||||
else
|
||||
echo -e "${red}no IPv6 address found on $interface. unable to fetch a joke via IPv6.${reset}"
|
||||
fi
|
||||
|
||||
echo -e "${green}joke fetching processes completed for $interface.${reset}"
|
||||
echo -e "------------------------------------"
|
||||
|
||||
sleep 3
|
||||
echo
|
||||
echo
|
||||
echo -e "${yellow}### connectivity testing recommendations ###${reset}"
|
||||
echo -e "${yellow}- use the following command to test WebSocket connectivity from an external client:${reset}"
|
||||
echo -e "${yellow} wscat -c wss://<your-ip-address/ hostname>:9001 ${reset}"
|
||||
echo -e "${yellow}- test UDP connectivity on port 51822 (commonly used for nym wireguard) ${reset}"
|
||||
echo -e "${yellow} from another machine, use tools like nc or socat to send UDP packets ${reset}"
|
||||
echo -e "${yellow} echo 'test message' | nc -u <your-ip-address> 51822 ${reset}"
|
||||
echo -e "${yellow}if connectivity issues persist, ensure port forwarding and firewall rules are correctly configured ${reset}"
|
||||
echo
|
||||
}
|
||||
|
||||
|
||||
configure_dns_and_icmp_wg() {
|
||||
echo "allowing icmp (ping)..."
|
||||
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
|
||||
sudo iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
|
||||
|
||||
echo "allowing dns over udp (port 53)..."
|
||||
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
|
||||
|
||||
echo "allowing dns over tcp (port 53)..."
|
||||
sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT
|
||||
|
||||
echo "saving iptables rules..."
|
||||
sudo iptables-save >/etc/iptables/rules.v4
|
||||
|
||||
echo "dns and icmp configuration completed."
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
fetch_ipv6_address_nym_tun)
|
||||
fetch_ipv6_address "$tunnel_interface"
|
||||
;;
|
||||
fetch_and_display_ipv6)
|
||||
fetch_and_display_ipv6
|
||||
;;
|
||||
apply_iptables_rules)
|
||||
apply_iptables_rules "$tunnel_interface"
|
||||
;;
|
||||
apply_iptables_rules_wg)
|
||||
apply_iptables_rules "$wg_tunnel_interface"
|
||||
;;
|
||||
check_nymtun_iptables)
|
||||
check_tunnel_iptables "$tunnel_interface"
|
||||
;;
|
||||
check_nym_wg_tun)
|
||||
check_tunnel_iptables "$wg_tunnel_interface"
|
||||
;;
|
||||
check_ipv6_ipv4_forwarding)
|
||||
check_ipv6_ipv4_forwarding
|
||||
;;
|
||||
check_ip_routing)
|
||||
check_ip_routing
|
||||
;;
|
||||
perform_pings)
|
||||
perform_pings
|
||||
;;
|
||||
joke_through_the_mixnet)
|
||||
joke_through_tunnel "$tunnel_interface"
|
||||
;;
|
||||
joke_through_wg_tunnel)
|
||||
joke_through_tunnel "$wg_tunnel_interface"
|
||||
;;
|
||||
configure_dns_and_icmp_wg)
|
||||
configure_dns_and_icmp_wg
|
||||
;;
|
||||
adjust_ip_forwarding)
|
||||
adjust_ip_forwarding
|
||||
;;
|
||||
remove_duplicate_rules)
|
||||
remove_duplicate_rules "$2"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 [command]"
|
||||
echo "Commands:"
|
||||
echo " fetch_ipv6_address_nym_tun - Fetch IPv6 for nymtun0."
|
||||
echo " fetch_and_display_ipv6 - Show IPv6 on default device."
|
||||
echo " apply_iptables_rules - Apply IPtables rules for nymtun0."
|
||||
echo " apply_iptables_rules_wg - Apply IPtables rules for nymwg."
|
||||
echo " check_nymtun_iptables - Check IPtables for nymtun0."
|
||||
echo " check_nym_wg_tun - Check IPtables for nymwg."
|
||||
echo " check_ipv6_ipv4_forwarding - Check IPv4 and IPv6 forwarding."
|
||||
echo " check_ip_routing - Display IP routing tables."
|
||||
echo " perform_pings - Test IPv4 and IPv6 connectivity."
|
||||
echo " joke_through_the_mixnet - Fetch a joke via nymtun0."
|
||||
echo " joke_through_wg_tunnel - Fetch a joke via nymwg."
|
||||
echo " configure_dns_and_icmp_wg - Allows icmp ping tests for probes alongside configuring dns"
|
||||
echo " adjust_ip_forwarding - Enable IPV6 and IPV4 forwarding"
|
||||
echo " remove_duplicate_rules <interface> - Remove duplicate iptables rules. Valid interfaces: nymwg, nymtun0"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "operation $1 completed successfully."
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
__version__ = "1.1.0"
|
||||
__version__ = "1.2.0"
|
||||
__default_branch__ = "develop"
|
||||
|
||||
import os
|
||||
@@ -22,17 +22,25 @@ class NodeSetupCLI:
|
||||
def __init__(self, args):
|
||||
self.branch = args.dev
|
||||
self.welcome_message = self.print_welcome_message()
|
||||
self.mode = self.prompt_mode()
|
||||
self.mode = self._get_or_prompt_mode(args)
|
||||
self.prereqs_install_sh = self.fetch_script("nym-node-prereqs-install.sh")
|
||||
self.env_vars_install_sh = self.fetch_script("setup-env-vars.sh")
|
||||
self.node_install_sh = self.fetch_script("nym-node-install.sh")
|
||||
self.service_config_sh = self.fetch_script("setup-systemd-service-file.sh")
|
||||
self.start_node_systemd_service_sh = self.fetch_script("start-node-systemd-service.sh")
|
||||
self.landing_page_html = self._check_gwx_mode() and self.fetch_script("landing-page.html")
|
||||
self.nginx_proxy_wss_sh = self._check_gwx_mode() and self.fetch_script("nginx_proxy_wss_sh")
|
||||
self.tunnel_manager_sh = self._check_gwx_mode() and self.fetch_script("network_tunnel_manager.sh")
|
||||
self.wg_ip_tables_manager_sh = self._check_gwx_mode() and self.fetch_script("wireguard-exit-policy-manager.sh")
|
||||
self.wg_ip_tables_test_sh = self._check_gwx_mode() and self.fetch_script("exit-policy-tests.sh")
|
||||
self.is_gwx = self.mode == "exit-gateway"
|
||||
if self.is_gwx:
|
||||
self.landing_page_html = self.fetch_script("landing-page.html")
|
||||
self.nginx_proxy_wss_sh = self.fetch_script("nginx_proxy_wss_sh")
|
||||
self.tunnel_manager_sh = self.fetch_script("network_tunnel_manager.sh")
|
||||
self.quic_bridge_deployment_sh = self.fetch_script("quic_bridge_deployment.sh")
|
||||
else:
|
||||
self.landing_page_html = None
|
||||
self.nginx_proxy_wss_sh = None
|
||||
self.tunnel_manager_sh = None
|
||||
self.wg_ip_tables_manager_sh = None
|
||||
self.wg_ip_tables_test_sh = None
|
||||
self.quic_bridge_deployment_sh = None
|
||||
|
||||
|
||||
def print_welcome_message(self):
|
||||
"""Welcome user, warns for needed pre-reqs and asks for confimation"""
|
||||
@@ -45,7 +53,7 @@ class NodeSetupCLI:
|
||||
self.print_character("=", 41)
|
||||
msg = \
|
||||
"Before you begin, make sure that:\n"\
|
||||
"1. You run this setup on Debian based Linux (ie Ubuntu)\n"\
|
||||
"1. You run this setup on Debian based Linux (ie Ubuntu 22.04 LTS)\n"\
|
||||
"2. You run this installation program from a root shell\n"\
|
||||
"3. You meet minimal requirements: https://nym.com/docs/operators/nodes\n"\
|
||||
"4. You accept Operators Terms & Conditions: https://nym.com/operators-validators-terms\n"\
|
||||
@@ -59,43 +67,103 @@ class NodeSetupCLI:
|
||||
else:
|
||||
print("Without confirming the points above, we cannot continue.")
|
||||
exit(1)
|
||||
|
||||
def ensure_env_values(self, args):
|
||||
"""Collect env vars from args or prompt interactively, then save to env.sh."""
|
||||
env_file = Path("env.sh")
|
||||
fields = [
|
||||
("hostname", "HOSTNAME", "Enter hostname (if you don't use a DNS, press enter): "),
|
||||
("location", "LOCATION", "Enter node location (country code or name): "),
|
||||
("email", "EMAIL", "Enter your email: "),
|
||||
("moniker", "MONIKER", "Enter node public moniker (visible in explorer & NymVPN app): "),
|
||||
("description", "DESCRIPTION", "Enter short node public description: "),
|
||||
]
|
||||
|
||||
def prompt_mode(self):
|
||||
"""Ask user to insert node functionality and save it in python and bash envs"""
|
||||
existing = self._read_env_file(env_file)
|
||||
updated = {}
|
||||
|
||||
for arg_name, key, prompt in fields:
|
||||
cli_val = getattr(args, arg_name, None)
|
||||
value = cli_val.strip() if cli_val else existing.get(key) or input(prompt).strip()
|
||||
updated[key] = value
|
||||
os.environ[key] = value
|
||||
|
||||
# autodetect PUBLIC_IP if not already set
|
||||
if not os.environ.get("PUBLIC_IP"):
|
||||
try:
|
||||
ip = subprocess.run(["curl", "-fsS4", "https://ifconfig.me"],
|
||||
capture_output=True, text=True, timeout=5)
|
||||
if ip.returncode == 0 and ip.stdout.strip():
|
||||
updated["PUBLIC_IP"] = ip.stdout.strip()
|
||||
os.environ["PUBLIC_IP"] = ip.stdout.strip()
|
||||
except subprocess.TimeoutExpired:
|
||||
print("[WARN] Timeout expired while trying to fetch public IP with curl.")
|
||||
except FileNotFoundError:
|
||||
print("[WARN] 'curl' command not found. Please install curl or set PUBLIC_IP manually.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"[WARN] Error while running curl to fetch public IP: {e}")
|
||||
|
||||
# write all collected variables to env.sh in one go
|
||||
self._upsert_env_vars(updated, env_file)
|
||||
|
||||
print(f"[OK] Updated env.sh with {len(updated)} entries.")
|
||||
|
||||
|
||||
|
||||
|
||||
def _upsert_env_vars(self, updates: dict, env_file: Path = Path("env.sh")):
|
||||
existing = self._read_env_file(env_file)
|
||||
existing.update(updates)
|
||||
with env_file.open("w") as f:
|
||||
for k, v in existing.items():
|
||||
f.write(f'export {k}="{v}"\n')
|
||||
os.environ.update(updates)
|
||||
|
||||
def _read_env_file(self, env_file: Path) -> dict:
|
||||
env = {}
|
||||
if env_file.exists():
|
||||
for line in env_file.read_text().splitlines():
|
||||
if line.startswith("export ") and "=" in line:
|
||||
k, v = line.replace("export ", "", 1).split("=", 1)
|
||||
env[k.strip()] = v.strip().strip('"')
|
||||
return env
|
||||
|
||||
def _get_or_prompt_mode(self, args):
|
||||
"""Resolve MODE from --mode, env.sh, os.environ, or prompt; persist to env.sh."""
|
||||
|
||||
env_file = Path("env.sh")
|
||||
|
||||
# CLI arg
|
||||
mode = getattr(args, "mode", None)
|
||||
if mode:
|
||||
mode = mode.strip().lower()
|
||||
self._upsert_env_vars({"MODE": mode})
|
||||
print(f"Mode set to '{mode}' from CLI argument.")
|
||||
return mode
|
||||
|
||||
# env.sh (replaces manual read)
|
||||
existing = self._read_env_file(env_file)
|
||||
mode = existing.get("MODE")
|
||||
if mode:
|
||||
os.environ["MODE"] = mode
|
||||
return mode
|
||||
|
||||
# process env
|
||||
if os.environ.get("MODE"):
|
||||
return os.environ["MODE"]
|
||||
|
||||
# prompt
|
||||
mode = input(
|
||||
"\nEnter the mode you want to run nym-node in: "
|
||||
"\n1. mixnode "
|
||||
"\n2. entry-gateway "
|
||||
"\n3. exit-gateway (works as entry-gateway as well) "
|
||||
"\nPress 1, 2 or 3 and enter:\n"
|
||||
).strip()
|
||||
|
||||
if mode in ("1", "mixnode"):
|
||||
mode = "mixnode"
|
||||
elif mode in ("2", "entry-gateway"):
|
||||
mode = "entry-gateway"
|
||||
elif mode in ("3", "exit-gateway"):
|
||||
mode = "exit-gateway"
|
||||
else:
|
||||
print("Only numbers 1, 2 or 3 are accepted.")
|
||||
"\nEnter node mode (mixnode / entry-gateway / exit-gateway): "
|
||||
).strip().lower()
|
||||
if mode not in ("mixnode", "entry-gateway", "exit-gateway"):
|
||||
print("Invalid mode. Must be one of: mixnode, entry-gateway, exit-gateway.")
|
||||
raise SystemExit(1)
|
||||
|
||||
# save mode for this Python instance
|
||||
self.mode = mode
|
||||
os.environ["MODE"] = mode
|
||||
|
||||
# persist to env.sh so other scripts can source it
|
||||
env_file = Path("env.sh")
|
||||
with env_file.open("a") as f:
|
||||
f.write(f'export MODE="{mode}"\n')
|
||||
|
||||
# source env.sh so future bash subprocesses see it immediately
|
||||
subprocess.run("source ./env.sh", shell=True, executable="/bin/bash")
|
||||
|
||||
self._upsert_env_vars({"MODE": mode})
|
||||
print(f"Mode set to '{mode}' — stored in env.sh and sourced for immediate use.")
|
||||
return mode
|
||||
|
||||
|
||||
def fetch_script(self, script_name):
|
||||
"""Fetches needed scripts according to a defined mode"""
|
||||
# print header only the first time
|
||||
@@ -119,16 +187,15 @@ class NodeSetupCLI:
|
||||
github_raw_nymtech_nym_scripts_url = f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/{self.branch}/scripts/"
|
||||
scripts_urls = {
|
||||
"nym-node-prereqs-install.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/nym-node-prereqs-install.sh",
|
||||
"setup-env-vars.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-env-vars.sh",
|
||||
"nym-node-install.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/nym-node-install.sh",
|
||||
"setup-systemd-service-file.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-systemd-service-file.sh",
|
||||
"start-node-systemd-service.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/start-node-systemd-service.sh",
|
||||
"nginx_proxy_wss_sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-nginx-proxy-wss.sh",
|
||||
"landing-page.html": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/landing-page.html",
|
||||
"network_tunnel_manager.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/network_tunnel_manager.sh",
|
||||
"wireguard-exit-policy-manager.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh",
|
||||
"exit-policy-tests.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/exit-policy-tests.sh",
|
||||
"network_tunnel_manager.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/network-tunnel-manager.sh",
|
||||
"quic_bridge_deployment.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/quic_bridge_deployment.sh"
|
||||
}
|
||||
|
||||
return scripts_urls[script_init_name]
|
||||
|
||||
def run_script(
|
||||
@@ -200,62 +267,61 @@ class NodeSetupCLI:
|
||||
|
||||
def _check_gwx_mode(self):
|
||||
"""Helper: Several fns run only for GWx - this fn checks this condition"""
|
||||
if self.mode == "exit-gateway":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return self.mode == "exit-gateway"
|
||||
|
||||
def check_wg_enabled(self):
|
||||
"""Checks if Wireguard is enabled and if not, prompts user if they want to enable it, stores it to env.sh"""
|
||||
def check_wg_enabled(self, args=None):
|
||||
"""Determine if WireGuard is enabled; precedence: CLI > env > env.sh > prompt. Persist normalized value."""
|
||||
|
||||
env_file = os.path.join(os.getcwd(), "env.sh")
|
||||
|
||||
env_file = os.path.abspath(os.path.join(os.getcwd(), "env.sh"))
|
||||
def norm(v):
|
||||
return "true" if str(v).strip().lower() == "true" else "false"
|
||||
|
||||
def norm(v): # -> "true" or "false"
|
||||
return "true" if str(v).strip().lower() in ("1", "true", "yes", "y") else "false"
|
||||
val = None
|
||||
|
||||
# precedence: process env → env.sh → prompt
|
||||
val = os.environ.get("WIREGUARD")
|
||||
# CLI argument
|
||||
if args and getattr(args, "wireguard", None) is not None:
|
||||
val = norm(getattr(args, "wireguard"))
|
||||
print(f"[INFO] WireGuard mode provided via CLI: {val}")
|
||||
|
||||
if val is None and os.path.isfile(env_file):
|
||||
try:
|
||||
with open(env_file, "r", encoding="utf-8") as f:
|
||||
m = re.search(r'^\s*export\s+WIREGUARD\s*=\s*"?([^"\n]+)"?', f.read(), re.M)
|
||||
if m:
|
||||
val = m.group(1)
|
||||
except Exception:
|
||||
pass
|
||||
# Environment variable
|
||||
val = val or os.environ.get("WIREGUARD")
|
||||
|
||||
# env.sh file
|
||||
if val is None:
|
||||
envs = self._read_env_file(Path(env_file))
|
||||
val = envs.get("WIREGUARD")
|
||||
|
||||
# Prompt
|
||||
if val is None:
|
||||
ans = input(
|
||||
"\nWireGuard is not configured.\n"
|
||||
"Nodes routing WireGuard can be listed as both entry and exit in the app.\n"
|
||||
"Enable WireGuard support? (y/n): "
|
||||
"Enable WireGuard support? (Y/n): "
|
||||
).strip().lower()
|
||||
val = "true" if ans in ("y", "yes") else "false"
|
||||
val = "true" if ans in ("", "y", "yes") else "false"
|
||||
|
||||
val = norm(val)
|
||||
os.environ["WIREGUARD"] = val
|
||||
|
||||
# persist to env.sh (replace or append)
|
||||
# Persist to env.sh
|
||||
try:
|
||||
text = ""
|
||||
if os.path.isfile(env_file):
|
||||
with open(env_file, "r", encoding="utf-8") as f:
|
||||
with open(env_file, encoding="utf-8") as f:
|
||||
text = f.read()
|
||||
if re.search(r'^\s*export\s+WIREGUARD\s*=.*$', text, re.M):
|
||||
text = re.sub(r'^\s*export\s+WIREGUARD\s*=.*$', f'export WIREGUARD="{val}"', text, flags=re.M)
|
||||
else:
|
||||
if text and not text.endswith("\n"):
|
||||
text += "\n"
|
||||
text += f'export WIREGUARD="{val}"\n'
|
||||
text = (text.rstrip("\n") + "\n" if text else "") + f'export WIREGUARD="{val}"\n'
|
||||
with open(env_file, "w", encoding="utf-8") as f:
|
||||
f.write(text)
|
||||
print(f'WIREGUARD={val} saved to {env_file}')
|
||||
except Exception as e:
|
||||
except OSError as e:
|
||||
print(f"Warning: could not write {env_file}: {e}")
|
||||
|
||||
return (val == "true")
|
||||
return val == "true"
|
||||
|
||||
|
||||
def run_bash_command(self, command, args=None, *, env=None, cwd=None, check=True):
|
||||
"""
|
||||
@@ -316,10 +382,17 @@ class NodeSetupCLI:
|
||||
"Setting up Wireguard IP tables to match Nym exit policy for mixnet, stored at: https://nymtech.net/.wellknown/network-requester/exit-policy.txt"
|
||||
"\nThis may take a while, follow the steps below and don't kill the process..."
|
||||
)
|
||||
self.run_script(self.wg_ip_tables_manager_sh, args=["install"])
|
||||
self.run_script(self.wg_ip_tables_manager_sh, args=["status"])
|
||||
self.run_script(self.wg_ip_tables_test_sh)
|
||||
self.run_script(self.tunnel_manager_sh, args=["exit_policy_install"])
|
||||
|
||||
def quic_bridge_deploy(self):
|
||||
"""Setup QUIC bridge and configuration using external script"""
|
||||
print("\n* * * Installing and configuring QUIC bridges * * *")
|
||||
answer = input("\nDo you want to install, setup and run QUIC bridge? (Y/n) ").strip().lower()
|
||||
|
||||
if answer in ("", "y", "yes"):
|
||||
self.run_script(self.quic_bridge_deployment_sh, args=["full_bridge_setup"])
|
||||
else:
|
||||
print("Skipping QUIC bridge setup.")
|
||||
|
||||
def run_nym_node_as_service(self):
|
||||
"""Starts /etc/systemd/system/nym-node.service based on prompt using external script"""
|
||||
@@ -347,8 +420,8 @@ class NodeSetupCLI:
|
||||
|
||||
if is_active:
|
||||
while True:
|
||||
ans = input(f"{service} is already running. Restart it now? (y/n):\n").strip().lower()
|
||||
if ans == "y":
|
||||
ans = input(f"{service} is already running. Restart it now? (Y/n):\n").strip().lower()
|
||||
if ans in ("", "Y", "y"):
|
||||
self.run_script(self.start_node_systemd_service_sh, args=["restart-poll"], env=run_env)
|
||||
return
|
||||
elif ans == "n":
|
||||
@@ -358,8 +431,8 @@ class NodeSetupCLI:
|
||||
print("Invalid input. Please press 'y' or 'n' and press enter.")
|
||||
else:
|
||||
while True:
|
||||
ans = input(f"{service} is not running. Start it now? (y/n):\n").strip().lower()
|
||||
if ans == "y":
|
||||
ans = input(f"{service} is not running. Start it now? (Y/n):\n").strip().lower()
|
||||
if ans in ("", "Y", "y"):
|
||||
self.run_script(self.start_node_systemd_service_sh, args=["start-poll"], env=run_env)
|
||||
return
|
||||
elif ans == "n":
|
||||
@@ -510,8 +583,12 @@ class NodeSetupCLI:
|
||||
|
||||
def run_node_installation(self,args):
|
||||
"""Main function called by argparser command install running full node install flow"""
|
||||
self.ensure_env_values(args)
|
||||
# Pass uplink override to all helper scripts if provided
|
||||
if getattr(args, "uplink_dev", None):
|
||||
os.environ["UPLINK_DEV"] = args.uplink_dev
|
||||
os.environ["NETWORK_DEVICE"] = args.uplink_dev
|
||||
self.run_script(self.prereqs_install_sh)
|
||||
self.run_script(self.env_vars_install_sh)
|
||||
self.run_script(self.node_install_sh)
|
||||
self.run_script(self.service_config_sh)
|
||||
self._check_gwx_mode() and self.run_script(self.nginx_proxy_wss_sh)
|
||||
@@ -521,7 +598,7 @@ class NodeSetupCLI:
|
||||
self.run_tunnel_manager_setup()
|
||||
if self.check_wg_enabled():
|
||||
self.setup_test_wg_ip_tables()
|
||||
self.setup_test_wg_ip_tables()
|
||||
self.quic_bridge_deploy()
|
||||
|
||||
|
||||
|
||||
@@ -537,7 +614,7 @@ class ArgParser:
|
||||
version=f"nym-node-cli {__version__}"
|
||||
)
|
||||
parent.add_argument("-d", "--dev", metavar="BRANCH",
|
||||
help="Define github branch",
|
||||
help="Define github branch (default: develop)",
|
||||
type=str,
|
||||
default=argparse.SUPPRESS)
|
||||
parent.add_argument("-v", "--verbose", action="store_true",
|
||||
@@ -553,11 +630,38 @@ class ArgParser:
|
||||
subparsers = parser.add_subparsers(dest="command", help="subcommands")
|
||||
subparsers.required = True
|
||||
|
||||
p_install = subparsers.add_parser(
|
||||
install_parser = subparsers.add_parser(
|
||||
"install", parents=[parent],
|
||||
help="Starts nym-node installation setup CLI",
|
||||
aliases=["i", "I"], add_help=True
|
||||
)
|
||||
install_parser.add_argument(
|
||||
"--mode",
|
||||
choices=["mixnode", "entry-gateway", "exit-gateway"],
|
||||
help="Node mode: 'mixnode', 'entry-gateway', or 'exit-gateway'",
|
||||
)
|
||||
install_parser.add_argument(
|
||||
"--wireguard-enabled",
|
||||
choices=["true", "false"],
|
||||
help="WireGuard functionality switch: true / false"
|
||||
)
|
||||
install_parser.add_argument("--hostname", help="Node domain / hostname")
|
||||
install_parser.add_argument("--location", help="Node location (country code or name)")
|
||||
install_parser.add_argument("--email", help="Contact email for the node operator")
|
||||
install_parser.add_argument("--moniker", help="Public moniker displayed in explorer & NymVPN app")
|
||||
install_parser.add_argument("--description", help="Short public description of the node")
|
||||
install_parser.add_argument("--public-ip", help="External IPv4 address (autodetected if omitted)")
|
||||
install_parser.add_argument("--nym-node-binary", help="URL for nym-node binary (autodetected if omitted)")
|
||||
install_parser.add_argument("--uplink-dev", help="Override uplink interface used for NAT/FORWARD (e.g., 'eth0'; autodetected if omitted)")
|
||||
|
||||
# generic fallback
|
||||
install_parser.add_argument(
|
||||
"--env",
|
||||
action="append",
|
||||
metavar="KEY=VALUE",
|
||||
help="(Optional) Extra ENV VARS, e.g. --env CUSTOM_KEY=value",
|
||||
)
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -34,8 +34,9 @@ check_existing_config() {
|
||||
|
||||
if [[ "${resp}" =~ ^([Rr][Ee][Ss][Ee][Tt])$ ]]; then
|
||||
echo
|
||||
read -r -p "We are going to remove the existing node with configuration $NODE_CONFIG_DIR and replace it with a fresh one, do you want to back up the old one first? (y/n) " backup_ans
|
||||
if [[ "${backup_ans}" =~ ^[Yy]$ ]]; then
|
||||
echo "We are going to remove the existing node with configuration $NODE_CONFIG_DIR and replace it with a fresh one."
|
||||
read -r -p "back up the old one first? (Y/n) " backup_ans
|
||||
if [[ -z "${backup_ans}" || "${backup_ans}" =~ ^[Yy]$ ]]; then
|
||||
ts="$(date +%Y%m%d-%H%M%S)"
|
||||
backup_dir="$HOME/.nym/backup/$(basename "$NODE_CONFIG_DIR")-$ts"
|
||||
echo "Backing up to: $backup_dir"
|
||||
@@ -181,24 +182,27 @@ fi
|
||||
|
||||
NYM_NODE="$HOME/nym-binaries/nym-node"
|
||||
|
||||
# if binary already exists, ask to overwrite; if yes, remove first
|
||||
# if binary already exists, ask to overwrite; if yes, remove first; if no, skip download
|
||||
if [[ -e "${NYM_NODE}" ]]; then
|
||||
echo
|
||||
echo -e "\n* * * A nym-node binary already exists at: ${NYM_NODE}"
|
||||
read -r -p "Overwrite with the latest release? (y/n): " ow_ans
|
||||
if [[ "${ow_ans}" =~ ^[Yy]$ ]]; then
|
||||
echo "Removing existing binary to avoid 'text file busy'..."
|
||||
rm -f "${NYM_NODE}"
|
||||
else
|
||||
echo "Keeping existing binary."
|
||||
fi
|
||||
fi
|
||||
read -r -p "Overwrite with the latest release? (Y/n): " ow_ans
|
||||
|
||||
download_nym_node "$LATEST_TAG_URL" "$NYM_NODE"
|
||||
if [[ -z "${ow_ans}" || "${ow_ans}" =~ ^[Yy]$ ]]; then
|
||||
echo "Removing existing binary..."
|
||||
rm -f "${NYM_NODE}"
|
||||
download_nym_node "$LATEST_TAG_URL" "$NYM_NODE"
|
||||
else
|
||||
echo "Keeping existing binary. Skipping download."
|
||||
fi
|
||||
|
||||
else
|
||||
# binary does not exist → must download
|
||||
download_nym_node "$LATEST_TAG_URL" "$NYM_NODE"
|
||||
fi
|
||||
|
||||
echo -e "\n * * * Making binary executable * * *"
|
||||
chmod +x "${NYM_NODE}"
|
||||
|
||||
echo "---------------------------------------------------"
|
||||
echo "Nym node binary downloaded:"
|
||||
"${NYM_NODE}" --version || true
|
||||
@@ -225,17 +229,18 @@ WIREGUARD="${WIREGUARD:-}"
|
||||
if [[ ( "$MODE" == "entry-gateway" || "$MODE" == "exit-gateway" ) && ( -n "${ASK_WG:-}" || -z "$WIREGUARD" ) ]]; then
|
||||
echo
|
||||
echo "Gateways can also route WireGuard in NymVPN."
|
||||
echo "Enabling it means your node may be listed as both entry and exit in the app."
|
||||
# show current default in the prompt if present
|
||||
def_hint=""
|
||||
[[ -n "${WIREGUARD}" ]] && def_hint=" [current: ${WIREGUARD}]"
|
||||
read -r -p "Enable WireGuard support? (y/n)${def_hint}: " answer || true
|
||||
case "${answer:-}" in
|
||||
[Yy]* ) WIREGUARD="true" ;;
|
||||
[Nn]* ) WIREGUARD="false" ;;
|
||||
* ) : ;; # keep existing value if user just pressed enter
|
||||
esac
|
||||
|
||||
read -r -p "Enable WireGuard support? (Y/n)${def_hint}: " answer || true
|
||||
|
||||
if [[ -z "${answer}" || "${answer}" =~ ^[Yy]$ ]]; then
|
||||
WIREGUARD="true"
|
||||
elif [[ "${answer}" =~ ^[Nn]$ ]]; then
|
||||
WIREGUARD="false"
|
||||
fi
|
||||
fi
|
||||
|
||||
# final default only if still empty
|
||||
WIREGUARD="${WIREGUARD:-false}"
|
||||
|
||||
|
||||
@@ -1,29 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
# update, upgrade & install dependencies
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "This script must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# update, upgrade and install dependencies
|
||||
echo -e "\n* * * Installing needed prerequisities * * *"
|
||||
|
||||
apt update -y && apt --fix-broken install
|
||||
apt upgrade
|
||||
apt install apt ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git ntp ntpdate neovim tree tmux tig nginx -y
|
||||
apt install ufw --fix-missing
|
||||
|
||||
|
||||
|
||||
# enable & setup firewall
|
||||
echo -e "\n* * * Setting up firewall using ufw * * * "
|
||||
echo "Please enable the firewall in the next prompt for node proper routing!"
|
||||
echo
|
||||
ufw enable
|
||||
ufw allow 22/tcp # SSH - you're in control of these ports
|
||||
ufw allow 80/tcp # HTTP
|
||||
ufw allow 443/tcp # HTTPS
|
||||
ufw allow 1789/tcp # Nym specific
|
||||
ufw allow 1790/tcp # Nym specific
|
||||
ufw allow 8080/tcp # Nym specific - nym-node-api
|
||||
ufw allow 9000/tcp # Nym Specific - clients port
|
||||
ufw allow 9001/tcp # Nym specific - wss port
|
||||
ufw allow 51822/udp # WireGuard
|
||||
ufw allow 'Nginx Full' && \
|
||||
ufw reload && \
|
||||
ufw status
|
||||
|
||||
@@ -47,7 +47,17 @@ NYM_ETC_BRIDGES="$NYM_ETC_DIR/bridges.toml"
|
||||
NYM_ETC_CLIENT_PARAMS_DEFAULT="$NYM_ETC_DIR/client_bridge_params.json"
|
||||
SERVICE_FILE="/etc/systemd/system/nym-bridge.service"
|
||||
|
||||
NET_DEV="$(ip route show default 2>/dev/null | awk '/default/ {print $5}' || true)"
|
||||
NET_DEV="${UPLINK_DEV:-}"
|
||||
if [[ -z "$NET_DEV" ]]; then
|
||||
NET_DEV="$(ip -o route show default 2>/dev/null | awk '{print $5}' | head -n1)"
|
||||
[[ -z "$NET_DEV" ]] && NET_DEV="$(ip -o route show default table all 2>/dev/null | awk '{print $5}' | head -n1)"
|
||||
fi
|
||||
if [[ -z "$NET_DEV" ]]; then
|
||||
echo -e "${RED}Cannot determine uplink interface. Set UPLINK_DEV.${RESET}" | tee -a "$LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
echo "Using uplink device: $NET_DEV"
|
||||
|
||||
WG_IFACE="nymwg"
|
||||
|
||||
# Root check
|
||||
@@ -65,6 +75,17 @@ err() { echo -e "${RED}$1${RESET}"; }
|
||||
info() { echo -e "${CYAN}$1${RESET}"; }
|
||||
press_enter() { read -r -p "$1"; }
|
||||
|
||||
# Disable pauses and interactive prompts for noninteractive mode
|
||||
if [[ "${NONINTERACTIVE:-0}" == "1" ]]; then
|
||||
# all pauses become no-ops
|
||||
press_enter() { :; }
|
||||
|
||||
# silence any "enter path:" prompts
|
||||
echo_prompt() { :; }
|
||||
else
|
||||
echo_prompt() { echo -n "$1"; }
|
||||
fi
|
||||
|
||||
# Helper: detect dpkg dependency failure for libc6>=2.34
|
||||
deb_depends_libc_too_old() {
|
||||
local v
|
||||
@@ -176,13 +197,31 @@ verify_bridge_prerequisites() {
|
||||
}
|
||||
|
||||
adjust_ip_forwarding() {
|
||||
title "Adjusting IP Forwarding"
|
||||
sed -i '/^net\.ipv4\.ip_forward=/d' /etc/sysctl.conf
|
||||
sed -i '/^net\.ipv6\.conf\.all\.forwarding=/d' /etc/sysctl.conf
|
||||
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
|
||||
echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf
|
||||
sysctl -p /etc/sysctl.conf
|
||||
ok "IPv4/IPv6 forwarding enabled."
|
||||
title "Checking IP forwarding"
|
||||
local v4 v6
|
||||
v4="$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null || echo 0)"
|
||||
v6="$(cat /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || echo 0)"
|
||||
|
||||
if [[ "$v4" == "1" ]]; then
|
||||
ok "IPv4 forwarding is enabled."
|
||||
else
|
||||
warn "IPv4 forwarding is not enabled."
|
||||
fi
|
||||
|
||||
if [[ "$v6" == "1" ]]; then
|
||||
ok "IPv6 forwarding is enabled."
|
||||
else
|
||||
warn "IPv6 forwarding is not enabled."
|
||||
fi
|
||||
|
||||
if [[ "$v4" != "1" || "$v6" != "1" ]]; then
|
||||
echo
|
||||
echo "To enable forwarding and routing consistently, run the network tunnel manager script as root."
|
||||
echo "For example:"
|
||||
echo " ./network-tunnel-manager.sh complete_networking_configuration"
|
||||
echo "or:"
|
||||
echo " ./network-tunnel-manager.sh adjust_ip_forwarding"
|
||||
fi
|
||||
}
|
||||
|
||||
# Install nym-bridge
|
||||
@@ -377,6 +416,11 @@ User=root
|
||||
ExecStart=$BRIDGE_BIN --config $NYM_ETC_BRIDGES
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
LimitNOFILE=65535
|
||||
ProtectSystem=full
|
||||
ProtectHome=yes
|
||||
PrivateTmp=yes
|
||||
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -390,21 +434,40 @@ EOF
|
||||
|
||||
# IPTABLES & helpers
|
||||
apply_bridge_iptables_rules() {
|
||||
title "Applying iptables rules"
|
||||
iptables -I INPUT -i "$WG_IFACE" -j ACCEPT || true
|
||||
ip6tables -I INPUT -i "$WG_IFACE" -j ACCEPT || true
|
||||
iptables -t nat -A POSTROUTING -o "$NET_DEV" -j MASQUERADE || true
|
||||
ip6tables -t nat -A POSTROUTING -o "$NET_DEV" -j MASQUERADE || true
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
ip6tables-save > /etc/iptables/rules.v6
|
||||
ok "iptables rules applied."
|
||||
title "Checking iptables rules for bridge routing"
|
||||
|
||||
echo "Inspecting current iptables state for interface ${WG_IFACE} and uplink ${NET_DEV}."
|
||||
echo
|
||||
|
||||
echo "IPv4 FORWARD:"
|
||||
iptables -L FORWARD -n -v 2>/dev/null | sed -n '1,20p' || echo "iptables not available."
|
||||
echo
|
||||
echo "IPv4 NAT POSTROUTING:"
|
||||
iptables -t nat -L POSTROUTING -n -v 2>/dev/null | sed -n '1,20p' || true
|
||||
echo
|
||||
echo "IPv6 FORWARD:"
|
||||
ip6tables -L FORWARD -n -v 2>/dev/null | sed -n '1,20p' || true
|
||||
echo
|
||||
echo "IPv6 NAT POSTROUTING:"
|
||||
ip6tables -t nat -L POSTROUTING -n -v 2>/dev/null | sed -n '1,20p' || true
|
||||
|
||||
echo
|
||||
echo "This script no longer changes iptables. To configure routing and NAT for nym, use the network tunnel manager script."
|
||||
echo "For example (run as root):"
|
||||
echo " ./network-tunnel-manager.sh complete_networking_configuration"
|
||||
}
|
||||
|
||||
configure_dns_and_icmp() {
|
||||
title "Allow ICMP and DNS"
|
||||
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT || true
|
||||
ip6tables -A INPUT -p ipv6-icmp -j ACCEPT || true
|
||||
ok "ICMP and DNS rules applied."
|
||||
title "Checking ICMP and DNS firewall rules"
|
||||
|
||||
echo "IPv4 INPUT rules related to ICMP and DNS:"
|
||||
iptables -L INPUT -n -v 2>/dev/null | grep -E 'icmp|dpt:53' || echo "no matching IPv4 rules shown."
|
||||
echo
|
||||
echo "IPv6 INPUT rules related to ICMP and DNS:"
|
||||
ip6tables -L INPUT -n -v 2>/dev/null | grep -E 'icmp|dpt:53' || echo "no matching IPv6 rules shown."
|
||||
|
||||
echo
|
||||
echo "If ping or DNS are blocked for bridge traffic, adjust your firewall using the network tunnel manager script or your chosen firewall tool."
|
||||
}
|
||||
|
||||
# Full interactive setup
|
||||
@@ -429,6 +492,8 @@ full_bridge_setup() {
|
||||
echo ""
|
||||
echo "Step 2/6: Installing bridge binary..."
|
||||
install_bridge_binary
|
||||
echo "[Bridge Install] $(date '+%F %T') $( $BRIDGE_BIN --version 2>/dev/null || echo 'nym-bridge (unknown)')" \
|
||||
>> /var/log/nym-bridge-version.log
|
||||
press_enter "Press Enter to continue..."
|
||||
|
||||
echo ""
|
||||
@@ -447,7 +512,7 @@ full_bridge_setup() {
|
||||
press_enter "Press Enter to continue..."
|
||||
|
||||
echo ""
|
||||
echo "Step 6/6: Configuring network rules (optional but recommended)..."
|
||||
echo "Step 6/6: Checking network rules and forwarding status..."
|
||||
adjust_ip_forwarding
|
||||
apply_bridge_iptables_rules
|
||||
configure_dns_and_icmp
|
||||
|
||||
@@ -39,16 +39,6 @@ while true; do
|
||||
esac
|
||||
done
|
||||
|
||||
# try to get the latest binary URL (non-fatal if missing)
|
||||
LATEST_BINARY=$(
|
||||
curl -fsSL https://github.com/nymtech/nym/releases/latest \
|
||||
| grep -Eo 'href="/nymtech/nym/releases/download/[^"]+/nym-node"' \
|
||||
| head -n1 \
|
||||
| cut -d'"' -f2
|
||||
)
|
||||
if [[ -z "${LATEST_BINARY:-}" ]]; then
|
||||
echo "WARNING: Could not determine latest nym-node binary URL right now. The installer will resolve it later."
|
||||
fi
|
||||
|
||||
PUBLIC_IP=$(curl -fsS -4 https://ifconfig.me || true)
|
||||
PUBLIC_IP=${PUBLIC_IP:-""}
|
||||
|
||||
@@ -1,315 +1,136 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# load env (prefer absolute ENV_FILE injected by Python CLI; fallback to ./env.sh)
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "This script must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# load env
|
||||
if [[ -n "${ENV_FILE:-}" && -f "${ENV_FILE}" ]]; then
|
||||
set -a; . "${ENV_FILE}"; set +a
|
||||
elif [[ -f "./env.sh" ]]; then
|
||||
set -a; . ./env.sh; set +a
|
||||
fi
|
||||
|
||||
: "${HOSTNAME:?HOSTNAME not set in env.sh}"
|
||||
: "${EMAIL:?EMAIL not set in env.sh}"
|
||||
: "${HOSTNAME:?HOSTNAME not set}"
|
||||
: "${EMAIL:?EMAIL not set}"
|
||||
|
||||
export SYSTEMD_PAGER=""
|
||||
export SYSTEMD_COLORS="0"
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# sanity check
|
||||
if [[ "${HOSTNAME}" == "localhost" || "${HOSTNAME}" == "127.0.0.1" || "${HOSTNAME}" == "ubuntu" ]]; then
|
||||
echo "ERROR: HOSTNAME cannot be 'localhost'. Use a public FQDN." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n* * * Starting nginx configuration for landing page, reverse proxy and WSS * * *"
|
||||
|
||||
# set paths & ports vars
|
||||
WEBROOT="/var/www/${HOSTNAME}"
|
||||
LE_ACME_DIR="/var/www/letsencrypt"
|
||||
SITES_AVAIL="/etc/nginx/sites-available"
|
||||
SITES_EN="/etc/nginx/sites-enabled"
|
||||
BASE_HTTP="${SITES_AVAIL}/${HOSTNAME}" # :80 vhost
|
||||
BASE_HTTPS="${SITES_AVAIL}/${HOSTNAME}-ssl" # :443 vhost (we’ll write it ourselves)
|
||||
WSS_AVAIL="${SITES_AVAIL}/wss-config-nym"
|
||||
BACKUP_DIR="/etc/nginx/sites-backups"
|
||||
|
||||
NYM_PORT_HTTP="${NYM_PORT_HTTP:-8080}"
|
||||
NYM_PORT_WSS="${NYM_PORT_WSS:-9000}"
|
||||
WSS_LISTEN_PORT="${WSS_LISTEN_PORT:-9001}"
|
||||
HTTP_CONF="${SITES_AVAIL}/${HOSTNAME}"
|
||||
WSS_CONF="${SITES_AVAIL}/wss-config-nym"
|
||||
|
||||
mkdir -p "${WEBROOT}" "${LE_ACME_DIR}" "${BACKUP_DIR}" "${SITES_AVAIL}" "${SITES_EN}"
|
||||
echo
|
||||
echo "* * * Starting nginx configuration for landing page, reverse proxy and WSS * * *"
|
||||
|
||||
# helpers
|
||||
neat_backup() {
|
||||
local file="$1"; [[ -f "$file" ]] || return 0
|
||||
local sha_now; sha_now="$(sha256sum "$file" | awk '{print $1}')" || return 0
|
||||
local tag; tag="$(basename "$file")"
|
||||
local latest="${BACKUP_DIR}/${tag}.latest"
|
||||
if [[ -f "$latest" ]]; then
|
||||
local sha_prev; sha_prev="$(awk '{print $1}' "$latest")"
|
||||
[[ "$sha_now" == "$sha_prev" ]] && return 0
|
||||
fi
|
||||
cp -a "$file" "${BACKUP_DIR}/${tag}.bak.$(date +%s)"
|
||||
echo "$sha_now ${tag}" > "$latest"
|
||||
ls -1t "${BACKUP_DIR}/${tag}.bak."* 2>/dev/null | tail -n +6 | xargs -r rm -f
|
||||
}
|
||||
###############################################################################
|
||||
# step 1: ensure landing page exists (local fetch -> github -> template)
|
||||
###############################################################################
|
||||
|
||||
ensure_enabled() {
|
||||
local src="$1"; local name; name="$(basename "$src")"
|
||||
ln -sf "$src" "${SITES_EN}/${name}"
|
||||
}
|
||||
mkdir -p "${WEBROOT}"
|
||||
|
||||
cert_ok() {
|
||||
[[ -s "/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem" && -s "/etc/letsencrypt/live/${HOSTNAME}/privkey.pem" ]]
|
||||
}
|
||||
SCRIPT_DIR="$(dirname "${ENV_FILE:-./env.sh}")"
|
||||
LOCAL_FETCHED_PAGE="${SCRIPT_DIR}/landing-page.html"
|
||||
|
||||
fetch_landing_html() {
|
||||
local url="https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/landing-page.html"
|
||||
mkdir -p "${WEBROOT}"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$url" -o "${WEBROOT}/index.html" || true
|
||||
else
|
||||
wget -qO "${WEBROOT}/index.html" "$url" || true
|
||||
fi
|
||||
|
||||
if [[ ! -s "${WEBROOT}/index.html" ]]; then
|
||||
cat > "${WEBROOT}/index.html" <<'HTML'
|
||||
if [[ -s "${LOCAL_FETCHED_PAGE}" ]]; then
|
||||
cp "${LOCAL_FETCHED_PAGE}" "${WEBROOT}/index.html"
|
||||
elif curl -fsSL \
|
||||
https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html \
|
||||
-o "${WEBROOT}/index.html"; then
|
||||
:
|
||||
else
|
||||
cat > "${WEBROOT}/index.html" <<EOF
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Nym Exit Gateway</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
padding: 2em;
|
||||
background-color: #111;
|
||||
color: #0ff;
|
||||
}
|
||||
h1 {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Nym Exit Gateway</h1>
|
||||
<p>This is a Nym Exit Gateway. The operator of this router has no access to any of the data routing through that due to encryption design.</p>
|
||||
<html>
|
||||
<head><title>nym node</title></head>
|
||||
<body style="font-family:sans-serif;text-align:center;padding:2em;">
|
||||
<h1>nym exit gateway</h1>
|
||||
<p>this is a nym exit gateway.</p>
|
||||
<p>Operator contact: <a href="mailto:${EMAIL}">${EMAIL}</a></p>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
fi
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
inject_email() {
|
||||
local file="${WEBROOT}/index.html"
|
||||
[[ -n "${EMAIL:-}" && -s "$file" ]] || return 0
|
||||
|
||||
# Escape characters that would break sed replacement
|
||||
local esc_email
|
||||
esc_email="$(printf '%s' "$EMAIL" | sed -e 's/[&/\]/\\&/g')"
|
||||
|
||||
# try to update existing meta (case-insensitive on the name attr)
|
||||
if grep -qiE '<meta[^>]+name=["'"'"']contact:email["'"'"']' "$file"; then
|
||||
sed -i -E \
|
||||
"s|(<meta[^>]+name=[\"']contact:email[\"'][^>]*content=\")[^\"]*(\"[^>]*>)|\1${esc_email}\2|I" \
|
||||
"$file" || true
|
||||
return 0
|
||||
fi
|
||||
|
||||
# insert before </head> if present (case-insensitive)
|
||||
if grep -qi '</head>' "$file"; then
|
||||
awk -v email="$EMAIL" '
|
||||
BEGIN{IGNORECASE=1}
|
||||
/<\/head>/ && !done {
|
||||
print " <meta name=\"contact:email\" content=\"" email "\">"
|
||||
done=1
|
||||
}
|
||||
{ print }
|
||||
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# fallback: append at end
|
||||
printf '\n<meta name="contact:email" content="%s">\n' "$EMAIL" >> "$file" || true
|
||||
}
|
||||
|
||||
fetch_logo() {
|
||||
local logo_url="https://raw.githubusercontent.com/nymtech/websites/refs/heads/main/www/nym.com/public/images/Nym_meta_Image.png?token=GHSAT0AAAAAACEERII7URYRTFACZ4F2OWZ42GMCPBQ"
|
||||
mkdir -p "${WEBROOT}/images"
|
||||
if [[ ! -s "${WEBROOT}/images/nym_logo.png" ]]; then
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$logo_url" -o "${WEBROOT}/images/nym_logo.png" || true
|
||||
else
|
||||
wget -qO "${WEBROOT}/images/nym_logo.png" "$logo_url" || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
reload_nginx() { nginx -t && systemctl reload nginx; }
|
||||
|
||||
# landing page (idempotent)
|
||||
fetch_landing_html
|
||||
inject_email
|
||||
fetch_logo
|
||||
echo "Landing page at ${WEBROOT}/index.html"
|
||||
|
||||
# disable default and stale SSL configs
|
||||
###############################################################################
|
||||
# step 2: remove default site and old configs, restart nginx
|
||||
###############################################################################
|
||||
|
||||
echo "Cleaning existing nginx configuration"
|
||||
|
||||
# remove default nginx site
|
||||
[[ -L "${SITES_EN}/default" ]] && unlink "${SITES_EN}/default" || true
|
||||
for f in "${SITES_EN}"/*; do
|
||||
[[ -L "$f" ]] || continue
|
||||
if grep -q "/etc/letsencrypt/live/localhost" "$f"; then
|
||||
echo "Disabling vhost referencing localhost cert: $f"; unlink "$f"
|
||||
fi
|
||||
done
|
||||
for f in "${SITES_EN}"/*; do
|
||||
[[ -L "$f" ]] || continue
|
||||
if grep -qE 'listen\s+.*443' "$f"; then
|
||||
cert=$(awk '/ssl_certificate[ \t]+/ {print $2}' "$f" | tr -d ';' | head -n1)
|
||||
key=$(awk '/ssl_certificate_key[ \t]+/ {print $2}' "$f" | tr -d ';' | head -n1)
|
||||
if [[ -n "${cert:-}" && ! -s "$cert" ]] || [[ -n "${key:-}" && ! -s "$key" ]]; then
|
||||
echo "Disabling SSL vhost with missing cert/key: $f"; unlink "$f"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# HTTP :80 vhost (ACME-safe, proxy to :8080)
|
||||
neat_backup "${BASE_HTTP}"
|
||||
cat > "${BASE_HTTP}" <<EOF
|
||||
# optional: remove default available config if present
|
||||
rm -f /etc/nginx/sites-available/default || true
|
||||
|
||||
# remove old vhosts for this domain
|
||||
rm -f "${SITES_EN}/${HOSTNAME}" || true
|
||||
rm -f "${SITES_EN}/${HOSTNAME}-ssl" || true
|
||||
rm -f "${SITES_EN}/wss-config-nym" || true
|
||||
|
||||
rm -f "${HTTP_CONF}" || true
|
||||
rm -f "${WSS_CONF}" || true
|
||||
|
||||
systemctl restart nginx || systemctl start nginx
|
||||
|
||||
###############################################################################
|
||||
# step 3: create basic HTTP config like manual flow (80 -> 8080)
|
||||
###############################################################################
|
||||
|
||||
cat > "${HTTP_CONF}" <<EOF
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name ${HOSTNAME};
|
||||
|
||||
# ACME challenge path (HTTP only)
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root ${LE_ACME_DIR};
|
||||
default_type "text/plain";
|
||||
}
|
||||
|
||||
root ${WEBROOT};
|
||||
index index.html;
|
||||
|
||||
location = /favicon.ico { return 204; access_log off; log_not_found off; }
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ @app;
|
||||
}
|
||||
|
||||
location @app {
|
||||
proxy_pass http://127.0.0.1:${NYM_PORT_HTTP};
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ensure_enabled "${BASE_HTTP}"
|
||||
reload_nginx
|
||||
systemctl status nginx --no-pager | sed -n '1,6p' || true
|
||||
|
||||
# ACME preflight (informative)
|
||||
echo -e "\n* * * ACME preflight checks * * *"
|
||||
if ! curl -fsSL https://acme-v02.api.letsencrypt.org/directory >/dev/null; then
|
||||
echo "WARNING: Can't reach Let's Encrypt directory. We'll still keep HTTP up." >&2
|
||||
fi
|
||||
THIS_IP="$(curl -fsS -4 https://ifconfig.me || true)"
|
||||
DNS_IP="$(getent ahostsv4 "${HOSTNAME}" 2>/dev/null | awk '{print $1; exit}')"
|
||||
echo "Public IPv4: ${THIS_IP:-unknown} DNS A(${HOSTNAME}): ${DNS_IP:-unresolved}"
|
||||
if [[ -n "${THIS_IP:-}" && -n "${DNS_IP:-}" && "${THIS_IP}" != "${DNS_IP}" ]]; then
|
||||
echo "WARNING: DNS for ${HOSTNAME} does not match this server's public IPv4."
|
||||
fi
|
||||
timedatectl show -p NTPSynchronized --value 2>/dev/null | grep -qi yes || timedatectl set-ntp true || true
|
||||
ln -sf "${HTTP_CONF}" "${SITES_EN}/${HOSTNAME}"
|
||||
|
||||
# install certbot if missing
|
||||
if ! command -v certbot >/dev/null 2>&1; then
|
||||
if command -v snap >/dev/null 2>&1; then
|
||||
snap install core || true; snap refresh core || true
|
||||
snap install --classic certbot; ln -sf /snap/bin/certbot /usr/bin/certbot
|
||||
else
|
||||
apt-get update -y >/dev/null 2>&1 || true
|
||||
apt-get install -y certbot >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
nginx -t
|
||||
systemctl daemon-reload
|
||||
systemctl restart nginx
|
||||
|
||||
# issue/renew via WEBROOT (no nginx auto-edit), non-fatal if it fails
|
||||
STAGING_FLAG=""; [[ "${CERTBOT_STAGING:-0}" == "1" ]] && STAGING_FLAG="--staging" && echo "Using Let's Encrypt STAGING."
|
||||
if ! cert_ok; then
|
||||
certbot certonly --non-interactive --agree-tos -m "${EMAIL}" -d "${HOSTNAME}" \
|
||||
--webroot -w "${LE_ACME_DIR}" ${STAGING_FLAG} || true
|
||||
fi
|
||||
###############################################################################
|
||||
# step 4: install certbot and obtain certificate (letsencrypt)
|
||||
###############################################################################
|
||||
|
||||
# create own 443 vhost (only if certs exist)
|
||||
if cert_ok; then
|
||||
neat_backup "${BASE_HTTPS}"
|
||||
cat > "${BASE_HTTPS}" <<EOF
|
||||
apt-get update -y >/dev/null 2>&1 || true
|
||||
apt-get install -y certbot python3-certbot-nginx >/dev/null 2>&1 || true
|
||||
|
||||
echo "Requesting Let's Encrypt certificate for ${HOSTNAME}"
|
||||
|
||||
certbot --nginx --non-interactive --agree-tos --redirect --reuse-key \
|
||||
-m "${EMAIL}" -d "${HOSTNAME}" || true
|
||||
|
||||
###############################################################################
|
||||
# step 5: create WSS 9001 config using certbot-generated certs
|
||||
###############################################################################
|
||||
|
||||
if [[ -s "/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem" ]]; then
|
||||
echo "Certificate detected, creating WSS config"
|
||||
|
||||
cat > "${WSS_CONF}" <<EOF
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name ${HOSTNAME};
|
||||
listen 9001 ssl http2;
|
||||
listen [::]:9001 ssl http2;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/${HOSTNAME}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/${HOSTNAME}/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
|
||||
root ${WEBROOT};
|
||||
index index.html;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
location = /favicon.ico { return 204; access_log off; log_not_found off; }
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ @app;
|
||||
}
|
||||
|
||||
location @app {
|
||||
proxy_pass http://127.0.0.1:${NYM_PORT_HTTP};
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ensure_enabled "${BASE_HTTPS}"
|
||||
|
||||
# optional: redirect HTTP->HTTPS (keeps ACME path in HTTP too via separate small server)
|
||||
neat_backup "${BASE_HTTP}"
|
||||
cat > "${BASE_HTTP}" <<EOF
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${HOSTNAME};
|
||||
|
||||
# Keep ACME reachable over HTTP:
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root ${LE_ACME_DIR};
|
||||
default_type "text/plain";
|
||||
}
|
||||
|
||||
# Redirect the rest to HTTPS
|
||||
location / {
|
||||
return 301 https://\$host\$request_uri;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ensure_enabled "${BASE_HTTP}"
|
||||
reload_nginx
|
||||
else
|
||||
echo "NOTE: Cert not present yet; HTTPS (443) will not listen. Only HTTP (80) is active."
|
||||
fi
|
||||
|
||||
# WSS TLS :9001 (only if certs exist)
|
||||
if cert_ok; then
|
||||
neat_backup "${WSS_AVAIL}"
|
||||
cat > "${WSS_AVAIL}" <<EOF
|
||||
server {
|
||||
listen ${WSS_LISTEN_PORT} ssl http2;
|
||||
listen [::]:${WSS_LISTEN_PORT} ssl http2;
|
||||
server_name ${HOSTNAME};
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/${HOSTNAME}/fullchain.pem;
|
||||
@@ -320,7 +141,11 @@ server {
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
location = /favicon.ico { return 204; access_log off; log_not_found off; }
|
||||
location /favicon.ico {
|
||||
return 204;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
location / {
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
@@ -333,20 +158,30 @@ server {
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header X-Forwarded-For \$remote_addr;
|
||||
|
||||
proxy_pass http://127.0.0.1:${NYM_PORT_WSS};
|
||||
proxy_pass http://localhost:9000;
|
||||
proxy_intercept_errors on;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ensure_enabled "${WSS_AVAIL}"
|
||||
reload_nginx
|
||||
|
||||
ln -sf "${WSS_CONF}" "${SITES_EN}/wss-config-nym"
|
||||
|
||||
nginx -t
|
||||
systemctl daemon-reload
|
||||
systemctl restart nginx
|
||||
else
|
||||
echo "Certificate missing, skipping WSS config"
|
||||
fi
|
||||
|
||||
echo -e "\nDone."
|
||||
if cert_ok; then
|
||||
echo "HTTP : http://${HOSTNAME}/ (redirects to HTTPS)"
|
||||
echo "TLS : https://${HOSTNAME}/ (served by nginx)"
|
||||
echo "WSS : wss://${HOSTNAME}:${WSS_LISTEN_PORT}/ (served by nginx)"
|
||||
###############################################################################
|
||||
# step 6: summary
|
||||
###############################################################################
|
||||
|
||||
echo "done."
|
||||
echo "http : http://${HOSTNAME}"
|
||||
if [[ -s "/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem" ]]; then
|
||||
echo "https : https://${HOSTNAME}"
|
||||
echo "wss : wss://${HOSTNAME}:9001"
|
||||
else
|
||||
echo "Only HTTP is active (no cert yet). Re-run after DNS/ACME is ready to enable HTTPS + WSS."
|
||||
echo "https not active yet (no cert)"
|
||||
fi
|
||||
|
||||
@@ -83,8 +83,8 @@ fi
|
||||
|
||||
# interactive path (manual runs)
|
||||
ensure_mode
|
||||
read -rp "Service file not found. Create it now? (y/n): " create_ans
|
||||
if [[ "${create_ans:-}" =~ ^[Yy]$ ]]; then
|
||||
read -rp "Service file not found. Create it now? (Y/n): " create_ans
|
||||
if [[ -z "${create_ans}" || "${create_ans}" =~ ^[Yy]$ ]]; then
|
||||
create_service_file
|
||||
else
|
||||
echo "Not creating the service file."
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Nym Exit Policy Verification Unit Tests
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
NYM_CHAIN="NYM-EXIT"
|
||||
WG_INTERFACE="nymwg"
|
||||
|
||||
check_port_range_rules() {
|
||||
local port_range="$1"
|
||||
local protocol="${2:-tcp}"
|
||||
local chain="${3:-$NYM_CHAIN}"
|
||||
|
||||
# Extract start and end ports
|
||||
local start_port=$(echo "$port_range" | cut -d'-' -f1)
|
||||
local end_port=$(echo "$port_range" | cut -d'-' -f2)
|
||||
|
||||
if iptables -t filter -C "$chain" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ Rule exists: $chain $protocol port range $start_port:$end_port${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}✗ Rule missing: $chain $protocol port range $start_port:$end_port${NC}"
|
||||
|
||||
echo -e "${YELLOW}Dumping all rules in $chain:${NC}"
|
||||
iptables -L "$chain" -n | grep "$protocol"
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Test port range rules
|
||||
test_port_range_rules() {
|
||||
echo -e "${YELLOW}Testing Port Range Rules...${NC}"
|
||||
|
||||
# Select the essential port ranges for testing
|
||||
local port_ranges=(
|
||||
"20-21:tcp:FTP"
|
||||
"80-81:tcp:HTTP"
|
||||
"2082-2083:tcp:CPanel"
|
||||
"5222-5223:tcp:XMPP"
|
||||
"27000-27050:tcp:Steam (sampling)"
|
||||
"989-990:tcp:FTP over TLS"
|
||||
"5000-5005:tcp:RTP/VoIP"
|
||||
"8087-8088:tcp:Simplify Media"
|
||||
"8232-8233:tcp:Zcash"
|
||||
"8332-8333:tcp:Bitcoin"
|
||||
"18080-18081:tcp:Monero"
|
||||
)
|
||||
|
||||
local total_failures=0
|
||||
|
||||
for range in "${port_ranges[@]}"; do
|
||||
IFS=':' read -r port_range protocol service <<< "$range"
|
||||
|
||||
# Extract start and end ports
|
||||
local start_port=$(echo "$port_range" | cut -d'-' -f1)
|
||||
local end_port=$(echo "$port_range" | cut -d'-' -f2)
|
||||
|
||||
echo -e "${YELLOW}Testing $service $protocol port range $port_range${NC}"
|
||||
|
||||
if iptables -t filter -C "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ Rule exists: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Rule missing: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}"
|
||||
((total_failures++))
|
||||
|
||||
echo -e "${YELLOW}Existing rules for protocol $protocol:${NC}"
|
||||
iptables -L "$NYM_CHAIN" -n | grep "$protocol"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $total_failures -eq 0 ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
test_critical_services() {
|
||||
echo -e "${YELLOW}Testing Critical Service Rules...${NC}"
|
||||
|
||||
local tcp_services=(
|
||||
22 # SSH
|
||||
53 # DNS
|
||||
443 # HTTPS
|
||||
853 # DNS over TLS
|
||||
1194 # OpenVPN
|
||||
)
|
||||
|
||||
local udp_services=(
|
||||
53 # DNS
|
||||
123 # NTP
|
||||
1194 # OpenVPN
|
||||
)
|
||||
|
||||
local failures=0
|
||||
|
||||
# Test TCP services
|
||||
for port in "${tcp_services[@]}"; do
|
||||
local rule_found=false
|
||||
|
||||
# First check for exact match
|
||||
if iptables -t filter -C "$NYM_CHAIN" -p tcp --dport "$port" -j ACCEPT 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ Rule exists: NYM-EXIT tcp port $port${NC}"
|
||||
rule_found=true
|
||||
else
|
||||
# If not found as exact port, search for it in port ranges
|
||||
# This checks if the port is covered by any range rule
|
||||
if iptables-save | grep -E "^-A $NYM_CHAIN.*tcp.*dpts:" | grep -qP "dpts:(\d+:)?$port(:|\d+)" || \
|
||||
iptables-save | grep -E "^-A $NYM_CHAIN.*tcp.*dpts:" | grep -qP "dpts:$port:"; then
|
||||
echo -e "${GREEN}✓ Rule exists: NYM-EXIT tcp port $port (covered by a range rule)${NC}"
|
||||
rule_found=true
|
||||
else
|
||||
echo -e "${RED}✗ Rule missing: NYM-EXIT tcp port $port${NC}"
|
||||
((failures++))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Test UDP services - similar approach
|
||||
for port in "${udp_services[@]}"; do
|
||||
local rule_found=false
|
||||
|
||||
if iptables -t filter -C "$NYM_CHAIN" -p udp --dport "$port" -j ACCEPT 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ Rule exists: NYM-EXIT udp port $port${NC}"
|
||||
rule_found=true
|
||||
else
|
||||
# If not found as exact port, search for it in port ranges
|
||||
if iptables-save | grep -E "^-A $NYM_CHAIN.*udp.*dpts:" | grep -qP "dpts:(\d+:)?$port(:|\d+)" || \
|
||||
iptables-save | grep -E "^-A $NYM_CHAIN.*udp.*dpts:" | grep -qP "dpts:$port:"; then
|
||||
echo -e "${GREEN}✓ Rule exists: NYM-EXIT udp port $port (covered by a range rule)${NC}"
|
||||
rule_found=true
|
||||
else
|
||||
echo -e "${RED}✗ Rule missing: NYM-EXIT udp port $port${NC}"
|
||||
((failures++))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${YELLOW}Relevant existing rules for HTTP (port 80):${NC}"
|
||||
iptables-save | grep -E "$NYM_CHAIN.*tcp" | grep -E "(dpt|dpts):.*80"
|
||||
|
||||
return $failures
|
||||
}
|
||||
|
||||
# Verify default reject rule exists
|
||||
test_default_reject_rule() {
|
||||
echo -e "${YELLOW}This test takes some time, do not quit the process${NC}"
|
||||
echo
|
||||
echo -e "${YELLOW}Testing Default Reject Rule...${NC}"
|
||||
|
||||
# Try different patterns to detect the reject rule
|
||||
if iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all.*anywhere.*anywhere.*reject-with"; then
|
||||
echo -e "${GREEN}✓ Default REJECT rule exists${NC}"
|
||||
return 0
|
||||
elif iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all -- .*everywhere.*everywhere"; then
|
||||
echo -e "${GREEN}✓ Default REJECT rule exists${NC}"
|
||||
return 0
|
||||
elif iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all.*0.0.0.0/0.*0.0.0.0/0"; then
|
||||
echo -e "${GREEN}✓ Default REJECT rule exists${NC}"
|
||||
return 0
|
||||
elif iptables -n -L "$NYM_CHAIN" | grep -qE "REJECT.*all.*0.0.0.0/0.*0.0.0.0/0"; then
|
||||
echo -e "${GREEN}✓ Default REJECT rule exists${NC}"
|
||||
return 0
|
||||
elif iptables -L "$NYM_CHAIN" | tail -1 | grep -q "REJECT"; then
|
||||
echo -e "${GREEN}✓ Default REJECT rule exists at the end of chain${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}✗ Default REJECT rule missing${NC}"
|
||||
# Display the last 3 rules in the chain for debugging
|
||||
echo -e "${YELLOW}Last 3 rules in the chain:${NC}"
|
||||
iptables -L "$NYM_CHAIN" | tail -3
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_all_tests() {
|
||||
local total_failures=0
|
||||
local total_tests=0
|
||||
local skip_default_reject=false
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--skip-default-reject)
|
||||
skip_default_reject=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unknown argument: $1${NC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local test_functions=(
|
||||
"test_port_range_rules"
|
||||
"test_critical_services"
|
||||
)
|
||||
|
||||
if [ "$skip_default_reject" = false ]; then
|
||||
test_functions+=("test_default_reject_rule")
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Running Nym Exit Policy Verification Tests...${NC}"
|
||||
|
||||
for test_func in "${test_functions[@]}"; do
|
||||
((total_tests++))
|
||||
$test_func
|
||||
if [ $? -ne 0 ]; then
|
||||
((total_failures++))
|
||||
echo -e "${RED}Test $test_func FAILED${NC}"
|
||||
else
|
||||
echo -e "${GREEN}Test $test_func PASSED${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "\n${YELLOW}Test Summary:${NC}"
|
||||
echo -e "Total Tests: $total_tests"
|
||||
echo -e "Failures: $total_failures"
|
||||
|
||||
if [ $total_failures -eq 0 ]; then
|
||||
echo -e "${GREEN}All Tests Passed Successfully!${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}Some Tests Failed. Please review the iptables configuration.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}This script must be run as root${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run the tests
|
||||
run_all_tests "$@"
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
validate_exit_policy() {
|
||||
echo "=== Nym Exit Policy Blocking Validation ==="
|
||||
|
||||
# Check iptables rules
|
||||
echo "Checking iptables NYM-EXIT chain:"
|
||||
sudo iptables -L NYM-EXIT -v -n
|
||||
|
||||
# Test IP ranges and individual IPs
|
||||
test_ips=(
|
||||
"5.188.10.0/24" # Blocked network range
|
||||
"31.132.36.50" # Specific blocked IP
|
||||
"37.9.42.100" # Another blocked IP
|
||||
)
|
||||
|
||||
for target in "${test_ips[@]}"; do
|
||||
echo -e "\n\e[33mTesting blocking for $target\e[0m"
|
||||
|
||||
# Multiple connection test methods
|
||||
methods=(
|
||||
"ping -c 4 -W 2"
|
||||
"curl -m 5 http://$target"
|
||||
"nc -z -w 5 $target 80"
|
||||
"telnet $target 80"
|
||||
)
|
||||
|
||||
for method in "${methods[@]}"; do
|
||||
echo -n "Testing with $method: "
|
||||
if sudo timeout 5 $method >/dev/null 2>&1; then
|
||||
echo -e "\e[31mFAILED: Connection succeeded (Blocking ineffective)\e[0m"
|
||||
else
|
||||
echo -e "\e[32mBLOCKED\e[0m"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# Run the test
|
||||
validate_exit_policy
|
||||
@@ -1,679 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Nym Wireguard Exit Policy Manager
|
||||
# Version: 1.0.0
|
||||
#
|
||||
# This script manages iptables rules for Nym Wireguard exit policies
|
||||
# Features:
|
||||
# - Implements the Nym exit policy from official documentation
|
||||
# - Makes rules persistent across reboots
|
||||
# - Provides commands to inspect and manage rules
|
||||
# - Groups rules logically for easier management
|
||||
# - Integrates with existing Nym node configuration
|
||||
#
|
||||
# Usage: ./nym-exit-policy.sh [command]
|
||||
|
||||
set -e
|
||||
|
||||
NETWORK_DEVICE=$(ip route show default | awk '/default/ {print $5}')
|
||||
WG_INTERFACE="nymwg"
|
||||
NYM_CHAIN="NYM-EXIT"
|
||||
POLICY_FILE="/etc/nym/exit-policy.txt"
|
||||
EXIT_POLICY_LOCATION="https://nymtech.net/.wellknown/network-requester/exit-policy.txt"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
add_port_rules() {
|
||||
local chain="$1"
|
||||
local port="$2"
|
||||
local protocol="${3:-tcp}"
|
||||
|
||||
# Check if the port contains a range
|
||||
if [[ "$port" == *"-"* ]]; then
|
||||
# Port range handling - add as a single rule with a range
|
||||
local start_port=$(echo "$port" | cut -d'-' -f1)
|
||||
local end_port=$(echo "$port" | cut -d'-' -f2)
|
||||
|
||||
if ! $chain -C "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then
|
||||
$chain -A "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT
|
||||
echo -e " ${GREEN}Added: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}"
|
||||
fi
|
||||
else
|
||||
# Single port handling
|
||||
if ! $chain -C "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT 2>/dev/null; then
|
||||
$chain -A "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT
|
||||
echo -e " ${GREEN}Added: $NYM_CHAIN $protocol port $port${NC}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
install_dependencies() {
|
||||
if ! dpkg -s iptables-persistent >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Installing iptables-persistent...${NC}"
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent
|
||||
echo -e "${GREEN}iptables-persistent installed.${NC}"
|
||||
else
|
||||
echo -e "${GREEN}iptables-persistent is already installed.${NC}"
|
||||
fi
|
||||
|
||||
# Check for other required dependencies
|
||||
for cmd in iptables ip6tables ip grep sed awk wget curl; do
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
echo -e "${YELLOW}Installing $cmd...${NC}"
|
||||
apt-get install -y "$cmd"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
configure_ip_forwarding() {
|
||||
echo -e "${YELLOW}Configuring IP forwarding...${NC}"
|
||||
|
||||
# Remove any existing forwarding settings to avoid duplicates
|
||||
sed -i "/^net.ipv6.conf.all.forwarding=/d" /etc/sysctl.conf
|
||||
sed -i "/^net.ipv4.ip_forward=/d" /etc/sysctl.conf
|
||||
|
||||
# Add forwarding settings
|
||||
echo "net.ipv6.conf.all.forwarding=1" | tee -a /etc/sysctl.conf
|
||||
echo "net.ipv4.ip_forward=1" | tee -a /etc/sysctl.conf
|
||||
|
||||
# Apply changes
|
||||
sysctl -p /etc/sysctl.conf
|
||||
|
||||
# Verify settings
|
||||
ipv4_forwarding=$(cat /proc/sys/net/ipv4/ip_forward)
|
||||
ipv6_forwarding=$(cat /proc/sys/net/ipv6/conf/all/forwarding)
|
||||
|
||||
if [ "$ipv4_forwarding" == "1" ] && [ "$ipv6_forwarding" == "1" ]; then
|
||||
echo -e "${GREEN}IP forwarding configured successfully.${NC}"
|
||||
else
|
||||
echo -e "${RED}Failed to configure IP forwarding.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
create_nym_chain() {
|
||||
echo -e "${YELLOW}Creating Nym exit policy chain...${NC}"
|
||||
|
||||
# Check if the chain already exists
|
||||
if iptables -L "$NYM_CHAIN" &>/dev/null; then
|
||||
echo -e "${YELLOW}Chain $NYM_CHAIN already exists. Flushing it...${NC}"
|
||||
iptables -F "$NYM_CHAIN"
|
||||
else
|
||||
echo -e "${YELLOW}Creating chain $NYM_CHAIN...${NC}"
|
||||
iptables -N "$NYM_CHAIN"
|
||||
fi
|
||||
|
||||
# Do the same for IPv6
|
||||
if ip6tables -L "$NYM_CHAIN" &>/dev/null; then
|
||||
echo -e "${YELLOW}Chain $NYM_CHAIN already exists in ip6tables. Flushing it...${NC}"
|
||||
ip6tables -F "$NYM_CHAIN"
|
||||
else
|
||||
echo -e "${YELLOW}Creating chain $NYM_CHAIN in ip6tables...${NC}"
|
||||
ip6tables -N "$NYM_CHAIN"
|
||||
fi
|
||||
|
||||
# Link it to the FORWARD chain if not already linked
|
||||
if ! iptables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then
|
||||
echo -e "${YELLOW}Linking $NYM_CHAIN to FORWARD chain...${NC}"
|
||||
iptables -A FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN"
|
||||
fi
|
||||
|
||||
# Link IPv6 chain
|
||||
if ! ip6tables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then
|
||||
echo -e "${YELLOW}Linking $NYM_CHAIN to IPv6 FORWARD chain...${NC}"
|
||||
ip6tables -A FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_nat_rules() {
|
||||
echo -e "${YELLOW}Setting up NAT rules...${NC}"
|
||||
|
||||
# Check if NAT rule for IPv4 exists
|
||||
if ! iptables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then
|
||||
iptables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE
|
||||
echo -e "${GREEN}Added IPv4 NAT rule.${NC}"
|
||||
else
|
||||
echo -e "${GREEN}IPv4 NAT rule already exists.${NC}"
|
||||
fi
|
||||
|
||||
# Check if NAT rule for IPv6 exists
|
||||
if ! ip6tables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then
|
||||
ip6tables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE
|
||||
echo -e "${GREEN}Added IPv6 NAT rule.${NC}"
|
||||
else
|
||||
echo -e "${GREEN}IPv6 NAT rule already exists.${NC}"
|
||||
fi
|
||||
|
||||
# Setup forwarding rules for Wireguard interface
|
||||
if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then
|
||||
iptables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv4 forwarding rule (WG → Internet).${NC}"
|
||||
fi
|
||||
|
||||
if ! iptables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then
|
||||
iptables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv4 forwarding rule (Internet → WG for established connections).${NC}"
|
||||
fi
|
||||
|
||||
# IPv6 forwarding rules
|
||||
if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then
|
||||
ip6tables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv6 forwarding rule (WG → Internet).${NC}"
|
||||
fi
|
||||
|
||||
if ! ip6tables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then
|
||||
ip6tables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv6 forwarding rule (Internet → WG for established connections).${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
configure_dns_and_icmp() {
|
||||
echo -e "${YELLOW}Configuring DNS and ICMP rules...${NC}"
|
||||
|
||||
# ICMP rules for ping
|
||||
if ! iptables -C INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null; then
|
||||
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv4 ICMP rule (allow ping requests).${NC}"
|
||||
fi
|
||||
|
||||
if ! iptables -C OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null; then
|
||||
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv4 ICMP rule (allow ping replies).${NC}"
|
||||
fi
|
||||
|
||||
# ICMPv6 rules for ping6
|
||||
if ! ip6tables -C INPUT -p ipv6-icmp -j ACCEPT 2>/dev/null; then
|
||||
ip6tables -A INPUT -p ipv6-icmp -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv6 ICMP rule (allow ping6).${NC}"
|
||||
fi
|
||||
|
||||
# DNS rules
|
||||
if ! iptables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null; then
|
||||
iptables -A INPUT -p udp --dport 53 -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv4 DNS rule (UDP).${NC}"
|
||||
fi
|
||||
|
||||
if ! iptables -C INPUT -p tcp --dport 53 -j ACCEPT 2>/dev/null; then
|
||||
iptables -A INPUT -p tcp --dport 53 -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv4 DNS rule (TCP).${NC}"
|
||||
fi
|
||||
|
||||
# IPv6 DNS rules
|
||||
if ! ip6tables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null; then
|
||||
ip6tables -A INPUT -p udp --dport 53 -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv6 DNS rule (UDP).${NC}"
|
||||
fi
|
||||
|
||||
if ! ip6tables -C INPUT -p tcp --dport 53 -j ACCEPT 2>/dev/null; then
|
||||
ip6tables -A INPUT -p tcp --dport 53 -j ACCEPT
|
||||
echo -e "${GREEN}Added IPv6 DNS rule (TCP).${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Apply Spamhaus blocklist from the Nym exit policy
|
||||
apply_spamhaus_blocklist() {
|
||||
echo -e "${YELLOW}Applying Spamhaus blocklist...${NC}"
|
||||
|
||||
# Create directory if not exists
|
||||
mkdir -p "$(dirname "$POLICY_FILE")"
|
||||
|
||||
# Try to download the policy file
|
||||
echo -e "${YELLOW}Downloading exit policy from $EXIT_POLICY_LOCATION${NC}"
|
||||
if ! wget -q "$EXIT_POLICY_LOCATION" -O "$POLICY_FILE" 2>/dev/null; then
|
||||
echo -e "${RED}Failed to download exit policy. Using minimal blocklist.${NC}"
|
||||
|
||||
# Create a minimal policy file with a few entries
|
||||
cat >"$POLICY_FILE" <<EOF
|
||||
ExitPolicy reject 5.188.10.0/23:*
|
||||
ExitPolicy reject 31.132.36.0/22:*
|
||||
ExitPolicy reject 37.9.42.0/24:*
|
||||
ExitPolicy reject 45.43.128.0/18:*
|
||||
ExitPolicy reject *:*
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Count and process rules
|
||||
total_rules=$(grep -c "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*")
|
||||
echo -e "${YELLOW}Processing $total_rules blocklist rules...${NC}"
|
||||
|
||||
# Extract and apply IP block rules
|
||||
grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" |
|
||||
while read -r line; do
|
||||
# Extract IP range
|
||||
ip_range=$(echo "$line" | sed -E 's/ExitPolicy reject ([^:]+):.*/\1/')
|
||||
|
||||
# Apply rule if it's a valid IP range
|
||||
if [[ -n "$ip_range" ]]; then
|
||||
# Skip if the rule already exists
|
||||
if ! iptables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then
|
||||
iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT
|
||||
fi
|
||||
|
||||
# Apply IPv6 rules for IPv6 addresses
|
||||
if [[ "$ip_range" == *":"* ]] && ! ip6tables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then
|
||||
ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${GREEN}Blocklist applied successfully.${NC}"
|
||||
}
|
||||
|
||||
add_default_reject_rule() {
|
||||
echo -e "${YELLOW}Adding default reject rule...${NC}"
|
||||
|
||||
# First remove any existing plain reject rules (without specific destinations)
|
||||
iptables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true
|
||||
iptables -D "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || true
|
||||
ip6tables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true
|
||||
ip6tables -D "$NYM_CHAIN" -j REJECT --reject-with icmp6-port-unreachable 2>/dev/null || true
|
||||
|
||||
# Add the default catch-all reject rule (must be the last rule in the chain)
|
||||
iptables -A "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable
|
||||
ip6tables -A "$NYM_CHAIN" -j REJECT --reject-with icmp6-port-unreachable
|
||||
|
||||
echo -e "${GREEN}Default reject rule added successfully.${NC}"
|
||||
}
|
||||
|
||||
apply_port_allowlist() {
|
||||
echo -e "${YELLOW}Applying allowed ports...${NC}"
|
||||
|
||||
# Dictionary of services and their ports
|
||||
declare -A PORT_MAPPINGS=(
|
||||
["FTP"]="20-21"
|
||||
["SSH"]="22"
|
||||
["WHOIS"]="43"
|
||||
["DNS"]="53"
|
||||
["Finger"]="79"
|
||||
["HTTP"]="80-81"
|
||||
["Kerberos"]="88"
|
||||
["POP3"]="110"
|
||||
["NTP"]="123"
|
||||
["IMAP"]="143"
|
||||
["IMAP3"]="220"
|
||||
["LDAP"]="389"
|
||||
["HTTPS"]="443"
|
||||
["SMBWindowsFileShare"]="445"
|
||||
["Kpasswd"]="464"
|
||||
["RTSP"]="554"
|
||||
["LDAPS"]="636"
|
||||
["SILC"]="706"
|
||||
["KerberosAdmin"]="749"
|
||||
["DNSOverTLS"]="853"
|
||||
["Rsync"]="873"
|
||||
["VMware"]="902-904"
|
||||
["RemoteHTTPS"]="981"
|
||||
["FTPOverTLS"]="989-990"
|
||||
["NetnewsAdmin"]="991"
|
||||
["TelnetOverTLS"]="992"
|
||||
["IMAPOverTLS"]="993"
|
||||
["POP3OverTLS"]="995"
|
||||
["OpenVPN"]="1194"
|
||||
["QTServerAdmin"]="1220"
|
||||
["PKTKRB"]="1293"
|
||||
["MSSQL"]="1433"
|
||||
["VLSILicenseManager"]="1500"
|
||||
["OracleDB"]="1521"
|
||||
["Sametime"]="1533"
|
||||
["GroupWise"]="1677"
|
||||
["PPTP"]="1723"
|
||||
["RTSPAlt"]="1755"
|
||||
["MSNP"]="1863"
|
||||
["NFS"]="2049"
|
||||
["CPanel"]="2082-2083"
|
||||
["GNUnet"]="2086-2087"
|
||||
["NBX"]="2095-2096"
|
||||
["Zephyr"]="2102-2104"
|
||||
["XboxLive"]="3074"
|
||||
["MySQL"]="3306"
|
||||
["SVN"]="3690"
|
||||
["RWHOIS"]="4321"
|
||||
["Virtuozzo"]="4643"
|
||||
["RTPVOIP"]="5000-5005"
|
||||
["MMCC"]="5050"
|
||||
["ICQ"]="5190"
|
||||
["XMPP"]="5222-5223"
|
||||
["AndroidMarket"]="5228"
|
||||
["PostgreSQL"]="5432"
|
||||
["MongoDBDefault"]="27017"
|
||||
["Electrum"]="8082"
|
||||
["SimplifyMedia"]="8087-8088"
|
||||
["Zcash"]="8232-8233"
|
||||
["Bitcoin"]="8332-8333"
|
||||
["HTTPSALT"]="8443"
|
||||
["TeamSpeak"]="8767"
|
||||
["MQTTS"]="8883"
|
||||
["HTTPProxy"]="8888"
|
||||
["TorORPort"]="9001"
|
||||
["TorDirPort"]="9030"
|
||||
["Tari"]="9053"
|
||||
["Gaming"]="9339"
|
||||
["Git"]="9418"
|
||||
["HTTPSALT2"]="9443"
|
||||
["Lightning"]="9735"
|
||||
["NDMP"]="10000"
|
||||
["OpenPGP"]="11371"
|
||||
["Monero"]="18080-18081"
|
||||
["MoneroRPC"]="18089"
|
||||
["GoogleVoice"]="19294"
|
||||
["EnsimControlPanel"]="19638"
|
||||
["DarkFiTor"]="25551"
|
||||
["Minecraft"]="25565"
|
||||
["DarkFi"]="26661"
|
||||
["Steam"]="27000-27050"
|
||||
["ElectrumSSL"]="50002"
|
||||
["MOSH"]="60000-61000"
|
||||
["Mumble"]="64738"
|
||||
)
|
||||
|
||||
# Add TCP and UDP rules for each allowed port
|
||||
for service in "${!PORT_MAPPINGS[@]}"; do
|
||||
port="${PORT_MAPPINGS[$service]}"
|
||||
echo -e "${YELLOW}Adding rules for $service (Port: $port)${NC}"
|
||||
|
||||
# Add both TCP and UDP rules for all services
|
||||
add_port_rules iptables "$port" "tcp"
|
||||
add_port_rules ip6tables "$port" "tcp"
|
||||
add_port_rules iptables "$port" "udp"
|
||||
add_port_rules ip6tables "$port" "udp"
|
||||
done
|
||||
|
||||
add_default_reject_rule
|
||||
|
||||
echo -e "${GREEN}Port allowlist applied successfully.${NC}"
|
||||
}
|
||||
|
||||
safe_iptables_rule_remove() {
|
||||
local chain="$1"
|
||||
local table="${2:-filter}"
|
||||
local interface="$3"
|
||||
|
||||
# Remove rule if it exists
|
||||
if iptables -t "$table" -C "$chain" -o "$interface" -j "$NYM_CHAIN" 2>/dev/null; then
|
||||
iptables -t "$table" -D "$chain" -o "$interface" -j "$NYM_CHAIN"
|
||||
fi
|
||||
}
|
||||
|
||||
safe_ip6tables_rule_remove() {
|
||||
local chain="$1"
|
||||
local table="${2:-filter}"
|
||||
local interface="$3"
|
||||
|
||||
# Remove rule if it exists
|
||||
if ip6tables -t "$table" -C "$chain" -o "$interface" -j "$NYM_CHAIN" 2>/dev/null; then
|
||||
ip6tables -t "$table" -D "$chain" -o "$interface" -j "$NYM_CHAIN"
|
||||
fi
|
||||
}
|
||||
|
||||
clear_rules() {
|
||||
echo -e "${YELLOW}Clearing Nym exit policy rules...${NC}"
|
||||
|
||||
# Flush all rules in the NYM-EXIT chain
|
||||
iptables -F "$NYM_CHAIN" 2>/dev/null || true
|
||||
ip6tables -F "$NYM_CHAIN" 2>/dev/null || true
|
||||
|
||||
# Remove the chain from FORWARD if it exists
|
||||
iptables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true
|
||||
ip6tables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true
|
||||
|
||||
# Delete the chains
|
||||
iptables -X "$NYM_CHAIN" 2>/dev/null || true
|
||||
ip6tables -X "$NYM_CHAIN" 2>/dev/null || true
|
||||
|
||||
echo -e "${GREEN}Nym exit policy rules cleared successfully.${NC}"
|
||||
}
|
||||
|
||||
remove_duplicate_rules() {
|
||||
local interface="$1"
|
||||
|
||||
if [[ -z "$interface" ]]; then
|
||||
echo -e "${RED}Error: No interface specified. Usage: $0 remove-duplicates <interface>${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Detecting and removing duplicate rules for $interface...${NC}"
|
||||
|
||||
# Verbose duplicate rule detection for IPv4
|
||||
echo -e "${YELLOW}Checking IPv4 duplicate rules:${NC}"
|
||||
iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq -d && {
|
||||
echo -e "${RED}Duplicate IPv4 rules found! Removing...${NC}"
|
||||
# Remove duplicates by saving unique rules
|
||||
iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq | while read -r rule; do
|
||||
# Carefully remove duplicates
|
||||
full_rule=$(echo "$rule" | sed 's/^-A/iptables -D/')
|
||||
eval "$full_rule" 2>/dev/null
|
||||
done
|
||||
} || echo -e "${GREEN}No duplicate IPv4 rules found.${NC}"
|
||||
|
||||
# Verbose duplicate rule detection for IPv6
|
||||
echo -e "${YELLOW}Checking IPv6 duplicate rules:${NC}"
|
||||
ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq -d && {
|
||||
echo -e "${RED}Duplicate IPv6 rules found! Removing...${NC}"
|
||||
# Remove duplicates by saving unique rules
|
||||
ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq | while read -r rule; do
|
||||
# Carefully remove duplicates
|
||||
full_rule=$(echo "$rule" | sed 's/^-A/ip6tables -D/')
|
||||
eval "$full_rule" 2>/dev/null
|
||||
done
|
||||
} || echo -e "${GREEN}No duplicate IPv6 rules found.${NC}"
|
||||
|
||||
# Additional verification
|
||||
echo -e "\n${YELLOW}Rule verification:${NC}"
|
||||
echo "IPv4 Rules:"
|
||||
iptables -L FORWARD -v -n | grep "$interface"
|
||||
echo "IPv6 Rules:"
|
||||
ip6tables -L FORWARD -v -n | grep "$interface"
|
||||
|
||||
echo -e "${GREEN}Duplicate rule removal process completed.${NC}"
|
||||
}
|
||||
|
||||
save_rules() {
|
||||
echo -e "${YELLOW}Saving iptables rules to make them persistent...${NC}"
|
||||
|
||||
if [ -d "/etc/iptables" ]; then
|
||||
# For Debian/Ubuntu with iptables-persistent
|
||||
iptables-save >/etc/iptables/rules.v4
|
||||
ip6tables-save >/etc/iptables/rules.v6
|
||||
echo -e "${GREEN}Rules saved to /etc/iptables/rules.v4 and /etc/iptables/rules.v6${NC}"
|
||||
else
|
||||
# Fallback method
|
||||
iptables-save >/etc/iptables.rules
|
||||
ip6tables-save >/etc/ip6tables.rules
|
||||
echo -e "${GREEN}Rules saved to /etc/iptables.rules and /etc/ip6tables.rules${NC}"
|
||||
|
||||
# Add loading script to rc.local if it doesn't exist
|
||||
if [ ! -f "/etc/network/if-pre-up.d/iptables" ]; then
|
||||
cat >/etc/network/if-pre-up.d/iptables <<EOF
|
||||
#!/bin/sh
|
||||
iptables-restore < /etc/iptables.rules
|
||||
ip6tables-restore < /etc/ip6tables.rules
|
||||
EOF
|
||||
chmod +x /etc/network/if-pre-up.d/iptables
|
||||
echo -e "${GREEN}Created pre-up script to load rules at boot${NC}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
show_status() {
|
||||
echo -e "${YELLOW}Nym Exit Policy Status:${NC}"
|
||||
echo -e "${YELLOW}----------------------${NC}"
|
||||
|
||||
# Network information
|
||||
echo -e "${GREEN}Network Device:${NC} $NETWORK_DEVICE"
|
||||
echo -e "${GREEN}Wireguard Interface:${NC} $WG_INTERFACE"
|
||||
|
||||
# Interface check
|
||||
if ! ip link show "$WG_INTERFACE" &>/dev/null; then
|
||||
echo -e "${RED}WARNING: Wireguard interface $WG_INTERFACE not found!${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Interface details
|
||||
echo -e "\n${YELLOW}Interface Details:${NC}"
|
||||
ip link show "$WG_INTERFACE"
|
||||
|
||||
# IP Addresses
|
||||
echo -e "\n${YELLOW}IP Addresses:${NC}"
|
||||
ip -4 addr show dev "$WG_INTERFACE"
|
||||
ip -6 addr show dev "$WG_INTERFACE"
|
||||
|
||||
# Iptables Chain Status
|
||||
echo -e "\n${YELLOW}Iptables Chains:${NC}"
|
||||
{
|
||||
echo "IPv4 Chain:"
|
||||
iptables -L "$NYM_CHAIN" -n -v
|
||||
echo -e "\nIPv6 Chain:"
|
||||
ip6tables -L "$NYM_CHAIN" -n -v
|
||||
} || echo "One or both chains not found"
|
||||
|
||||
# Forwarding Status
|
||||
echo -e "\n${YELLOW}IP Forwarding:${NC}"
|
||||
echo "IPv4: $(cat /proc/sys/net/ipv4/ip_forward)"
|
||||
echo "IPv6: $(cat /proc/sys/net/ipv6/conf/all/forwarding)"
|
||||
}
|
||||
|
||||
test_connectivity() {
|
||||
echo -e "${YELLOW}Testing connectivity through $WG_INTERFACE...${NC}"
|
||||
|
||||
# More comprehensive interface check
|
||||
interface_info=$(ip link show "$WG_INTERFACE" 2>/dev/null)
|
||||
|
||||
if [ -z "$interface_info" ]; then
|
||||
echo -e "${RED}Interface $WG_INTERFACE not found!${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for multiple possible interface states
|
||||
if ! echo "$interface_info" | grep -qE "state (UP|UNKNOWN|DORMANT)"; then
|
||||
echo -e "${RED}Interface $WG_INTERFACE is not in an active state!${NC}"
|
||||
echo "$interface_info"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detailed interface information
|
||||
echo -e "${GREEN}Interface Details:${NC}"
|
||||
echo "$interface_info"
|
||||
|
||||
# Get IP addresses with more robust method
|
||||
ipv4_address=$(ip -4 addr show dev "$WG_INTERFACE" | grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+/\d+' | cut -d'/' -f1 | head -n1)
|
||||
ipv6_address=$(ip -6 addr show dev "$WG_INTERFACE" scope global | grep -oP '(?<=inet6\s)[0-9a-f:]+/\d+' | cut -d'/' -f1 | head -n1)
|
||||
|
||||
echo -e "${GREEN}IPv4 Address:${NC} ${ipv4_address:-Not found}"
|
||||
echo -e "${GREEN}IPv6 Address:${NC} ${ipv6_address:-Not found}"
|
||||
|
||||
# Connectivity tests
|
||||
if [[ -n "$ipv4_address" ]]; then
|
||||
echo -e "${YELLOW}Testing IPv4 connectivity from $ipv4_address...${NC}"
|
||||
|
||||
# Ping test
|
||||
if timeout 5 ping -c 3 -I "$ipv4_address" 8.8.8.8 >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}IPv4 connectivity to 8.8.8.8: Success${NC}"
|
||||
else
|
||||
echo -e "${RED}IPv4 connectivity to 8.8.8.8: Failed${NC}"
|
||||
fi
|
||||
|
||||
# DNS resolution test
|
||||
if timeout 5 ping -c 3 -I "$ipv4_address" google.com >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}IPv4 DNS resolution: Success${NC}"
|
||||
else
|
||||
echo -e "${RED}IPv4 DNS resolution: Failed${NC}"
|
||||
fi
|
||||
|
||||
# HTTP(S) connectivity test
|
||||
if command -v curl &>/dev/null; then
|
||||
if timeout 5 curl -s --interface "$ipv4_address" -o /dev/null -w "%{http_code}" https://www.google.com | grep -q "200"; then
|
||||
echo -e "${GREEN}IPv4 HTTPS connectivity: Success${NC}"
|
||||
else
|
||||
echo -e "${RED}IPv4 HTTPS connectivity: Failed${NC}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}No IPv4 address configured on $WG_INTERFACE${NC}"
|
||||
fi
|
||||
|
||||
# Similar tests for IPv6 if available
|
||||
if [[ -n "$ipv6_address" ]]; then
|
||||
echo -e "${YELLOW}Testing IPv6 connectivity from $ipv6_address...${NC}"
|
||||
|
||||
if timeout 5 ping6 -c 3 -I "$ipv6_address" 2001:4860:4860::8888 >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}IPv6 connectivity to Google DNS: Success${NC}"
|
||||
else
|
||||
echo -e "${RED}IPv6 connectivity to Google DNS: Failed${NC}"
|
||||
fi
|
||||
|
||||
if timeout 5 ping6 -c 3 -I "$ipv6_address" google.com >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}IPv6 DNS resolution: Success${NC}"
|
||||
else
|
||||
echo -e "${RED}IPv6 DNS resolution: Failed${NC}"
|
||||
fi
|
||||
|
||||
if command -v curl &>/dev/null; then
|
||||
if timeout 5 curl -s --interface "$ipv6_address" -o /dev/null -w "%{http_code}" https://www.google.com | grep -q "200"; then
|
||||
echo -e "${GREEN}IPv6 HTTPS connectivity: Success${NC}"
|
||||
else
|
||||
echo -e "${RED}IPv6 HTTPS connectivity: Failed${NC}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}No IPv6 address configured on $WG_INTERFACE${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Connectivity tests completed.${NC}"
|
||||
}
|
||||
|
||||
main() {
|
||||
# Check for root privileges
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo -e "${RED}This script must be run as root${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse command-line arguments
|
||||
case "$1" in
|
||||
install)
|
||||
install_dependencies
|
||||
configure_ip_forwarding
|
||||
create_nym_chain
|
||||
setup_nat_rules
|
||||
configure_dns_and_icmp
|
||||
apply_spamhaus_blocklist
|
||||
apply_port_allowlist
|
||||
save_rules
|
||||
echo -e "${GREEN}Nym exit policy installed successfully.${NC}"
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
test)
|
||||
test_connectivity
|
||||
;;
|
||||
clear)
|
||||
clear_rules
|
||||
echo -e "${GREEN}Nym exit policy rules cleared.${NC}"
|
||||
;;
|
||||
remove-duplicates)
|
||||
remove_duplicate_rules "$2"
|
||||
;;
|
||||
help | --help | -h)
|
||||
echo "Usage: $0 [command]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " install Install and configure Nym exit policy"
|
||||
echo " status Show current Nym exit policy status"
|
||||
echo " test Test connectivity through Wireguard interface"
|
||||
echo " clear Remove all Nym exit policy rules"
|
||||
echo " remove-duplicates <interface> Remove duplicate iptables rules for an interface"
|
||||
echo " help Show this help message"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Invalid command. Use '$0 help' for usage information.${NC}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -4,15 +4,15 @@ all: build build-node
|
||||
build: test build-wasm
|
||||
|
||||
build-wasm:
|
||||
wasm-pack build --scope nymproject --target web --out-dir ../../dist/wasm/client
|
||||
wasm-opt -Oz -o ../../dist/wasm/client/nym_client_wasm_bg.wasm ../../dist/wasm/client/nym_client_wasm_bg.wasm
|
||||
taskset -c 0-11 wasm-pack build --scope nymproject --target web --out-dir ../../dist/wasm/client
|
||||
taskset -c 0-11 wasm-opt -Oz -o ../../dist/wasm/client/nym_client_wasm_bg.wasm ../../dist/wasm/client/nym_client_wasm_bg.wasm
|
||||
|
||||
build-debug-dev:
|
||||
wasm-pack build --debug --scope nymproject --target no-modules
|
||||
|
||||
build-rust-node:
|
||||
wasm-pack build --scope nymproject --target nodejs --out-dir ../../dist/node/wasm/client
|
||||
wasm-opt -Oz -o ../../dist/node/wasm/client/nym_client_wasm_bg.wasm ../../dist/node/wasm/client/nym_client_wasm_bg.wasm
|
||||
taskset -c 0-11 wasm-pack build --scope nymproject --target nodejs --out-dir ../../dist/node/wasm/client
|
||||
taskset -c 0-11 wasm-opt -Oz -o ../../dist/node/wasm/client/nym_client_wasm_bg.wasm ../../dist/node/wasm/client/nym_client_wasm_bg.wasm
|
||||
|
||||
build-package-json-node:
|
||||
node build-node.mjs
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
all: build-full
|
||||
|
||||
build-full:
|
||||
wasm-pack build --all-features --scope nymproject --target web --out-dir ../../dist/wasm/full-nym-wasm
|
||||
wasm-opt -Oz -o ../../dist/wasm/full-nym-wasm/nym_wasm_sdk_bg.wasm ../../dist/wasm/full-nym-wasm/nym_wasm_sdk_bg.wasm
|
||||
taskset -c 0-11 wasm-pack build --all-features --scope nymproject --target web --out-dir ../../dist/wasm/full-nym-wasm
|
||||
taskset -c 0-11 wasm-opt -Oz -o ../../dist/wasm/full-nym-wasm/nym_wasm_sdk_bg.wasm ../../dist/wasm/full-nym-wasm/nym_wasm_sdk_bg.wasm
|
||||
|
||||
@@ -9,8 +9,8 @@ build-go-opt:
|
||||
$(MAKE) -C go-mix-conn build-go-opt
|
||||
|
||||
build-rust:
|
||||
wasm-pack build --scope nymproject --target web --out-dir ../../dist/wasm/mix-fetch
|
||||
wasm-opt -Oz -o ../../dist/wasm/mix-fetch/mix_fetch_wasm_bg.wasm ../../dist/wasm/mix-fetch/mix_fetch_wasm_bg.wasm
|
||||
taskset -c 0-11 wasm-pack build --scope nymproject --target web --out-dir ../../dist/wasm/mix-fetch
|
||||
taskset -c 0-11 wasm-opt -Oz -o ../../dist/wasm/mix-fetch/mix_fetch_wasm_bg.wasm ../../dist/wasm/mix-fetch/mix_fetch_wasm_bg.wasm
|
||||
|
||||
build-rust-debug:
|
||||
wasm-pack build --debug --scope nymproject --target no-modules
|
||||
@@ -23,4 +23,4 @@ check-fmt-go:
|
||||
|
||||
check-fmt-rust:
|
||||
cargo fmt --check
|
||||
cargo clippy --target wasm32-unknown-unknown -- -Dwarnings
|
||||
cargo clippy --target wasm32-unknown-unknown -- -Dwarnings
|
||||
|
||||
Reference in New Issue
Block a user