Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7f445a330 | |||
| 360c7fda57 | |||
| 2cbb2d8327 | |||
| 808e3f0562 | |||
| f0dade3c5b | |||
| 0a3c2b3cca | |||
| ac66906980 | |||
| afd9f823d8 | |||
| d818448848 | |||
| a9a1ba2847 | |||
| 2708c0ce10 | |||
| bb3e9b3d4e | |||
| e624f42ad5 | |||
| 7da83397dd | |||
| 26d0b4b159 | |||
| 8339d6ab49 | |||
| f037b2ae68 |
@@ -75,29 +75,28 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
# Enable wireguard by default on linux only
|
||||
args: --workspace --features wireguard
|
||||
args: --workspace
|
||||
|
||||
- name: Build all examples
|
||||
if: matrix.os == 'custom-linux'
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --examples --features wireguard
|
||||
args: --workspace --examples
|
||||
|
||||
- name: Run all tests
|
||||
if: matrix.os == 'custom-linux'
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --features wireguard
|
||||
args: --workspace
|
||||
|
||||
- name: Run expensive tests
|
||||
if: (github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master') && matrix.os == 'custom-linux'
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --features wireguard -- --ignored
|
||||
args: --workspace -- --ignored
|
||||
|
||||
- name: Annotate with clippy checks
|
||||
if: matrix.os == 'custom-linux'
|
||||
@@ -105,10 +104,10 @@ jobs:
|
||||
continue-on-error: true
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --workspace --features wireguard
|
||||
args: --workspace
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace --all-targets --features wireguard -- -D warnings
|
||||
args: --workspace --all-targets -- -D warnings
|
||||
|
||||
Generated
+7
-4
@@ -6667,12 +6667,15 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-client-core",
|
||||
"nym-config",
|
||||
"nym-exit-policy",
|
||||
"nym-network-requester",
|
||||
"nym-sdk",
|
||||
"nym-service-providers-common",
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tap",
|
||||
@@ -9439,9 +9442,9 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "safer-ffi"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9c1d19b288ca9898cd421c7b105fb7269918a7f8e9253a991e228981ca421ad"
|
||||
checksum = "395ace5aff9629c7268ca8255aceb945525b2cb644015f3caec5131a6a537c11"
|
||||
dependencies = [
|
||||
"inventory",
|
||||
"libc",
|
||||
@@ -9456,9 +9459,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "safer_ffi-proc_macros"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2d7a04caa3ca2224f5ea4ddd850e2629c3b36b2b83621f87a8303bf41020110"
|
||||
checksum = "9255504d5467bae9e07d58b8de446ba6739b29bf72e1fa35b2387e30d29dcbfe"
|
||||
dependencies = [
|
||||
"macro_rules_attribute",
|
||||
"prettyplease",
|
||||
|
||||
@@ -25,12 +25,20 @@ pub const DEFAULT_CONFIG_FILENAME: &str = "config.toml";
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
pub fn must_get_home() -> PathBuf {
|
||||
dirs::home_dir().expect("Failed to evaluate $HOME value")
|
||||
if let Some(home_dir) = std::env::var_os("NYM_HOME_DIR") {
|
||||
home_dir.into()
|
||||
} else {
|
||||
dirs::home_dir().expect("Failed to evaluate $HOME value")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
pub fn may_get_home() -> Option<PathBuf> {
|
||||
dirs::home_dir()
|
||||
if let Some(home_dir) = std::env::var_os("NYM_HOME_DIR") {
|
||||
Some(home_dir.into())
|
||||
} else {
|
||||
dirs::home_dir()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NymConfigTemplate: Serialize {
|
||||
|
||||
@@ -22,14 +22,17 @@ As we shared in our blog post article [*What does it take to build the wolds mos
|
||||
|
||||
### What are the changes?
|
||||
|
||||
Project smoosh will have three steps:
|
||||
Project Smoosh will have four steps, please follow the table below to track the dynamic progress:
|
||||
|
||||
1. Combine the `nym-gateway` and `nym-network-requester` into one binary ✅
|
||||
2. Create [Exit Gateway](../legal/exit-gateway.md): Take the `nym-gateway` binary including `nym-network-requester` combined in \#1 and switch from [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) ✅
|
||||
3. Combine all the nodes in the Nym Mixnet into one binary, that is `nym-mixnode`, `nym-gateway` (entry and exit) and `nym-network-requester`.
|
||||
| **Step** | **Status** |
|
||||
| :--- | :--- |
|
||||
| **1.** Combine the `nym-gateway` and `nym-network-requester` into one binary | ✅ done |
|
||||
| **2.** Create [Exit Gateway](../legal/exit-gateway.md): Take the `nym-gateway` binary including `nym-network-requester` combined in \#1 and switch from [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) | ✅ done |
|
||||
| **3.** Combine all the nodes in the Nym Mixnet into one binary, that is `nym-mixnode`, `nym-gateway` (entry and exit) and `nym-network-requester`. | 🛠️ in progress |
|
||||
| **4.** Adjust reward scheme to incentivise and reward Exit Gateways as a part of `nym-node` binary, implementing [zkNym credentials](https://youtu.be/nLmdsZ1BsQg?t=1717). | 🛠️ in progress |
|
||||
|
||||
These three steps will be staggered over time - period of several months, and will be implemented one by one with enough time to take in feedback and fix bugs in between.
|
||||
Generally, the software will be the same, just instead of multiple binaries, there will be one Nym Mixnet node binary. Delegations will remain on as they are now, per our token economics (staking, saturation etc)
|
||||
These steps will be staggered over time - period of several months, and will be implemented one by one with enough time to take in feedback and fix bugs in between.
|
||||
Generally, the software will be the same, just instead of multiple binaries, there will be one Nym Node (`nym-node`) binary. Delegations will remain on as they are now, per our token economics (staking, saturation etc)
|
||||
|
||||
### What does it mean for Nym nodes operators?
|
||||
|
||||
@@ -49,13 +52,15 @@ The operators running Gateways would have to “open” their nodes to a wider r
|
||||
|
||||
### How will the Exit policy be implemented?
|
||||
|
||||
The progression of exit policy on Gateways will have three steps:
|
||||
Follow the dynamic progress of exit policy implementation on Gateways below:
|
||||
|
||||
1. By default the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) filtering will be disabled and the current [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) filtering is going to continue be used. This is to prevent operators getting surprised by upgrading their Gateways (or Network Requesters) and suddenly be widely open to the internet. To enable the new exit policy, operators must use `--with-exit-policy` flag or modify the `config.toml` file. ✅
|
||||
2. Relatively soon the exit policy will be part of the Gateway setup by default. To disable this exit policy, operators must use `--disable-exit-policy` flag.
|
||||
3. Further down the line, it will be the only option. Then the `allowed.list` will be completely removed.
|
||||
| **Step** | **Status** |
|
||||
| :--- | :--- |
|
||||
| **1.** By default the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) filtering is disabled and the [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) filtering is going to continue be used. This is to prevent operators getting surprised by upgrading their Gateways (or Network Requesters) and suddenly be widely open to the internet. To enable the new exit policy, operators must use `--with-exit-policy` flag or modify the `config.toml` file. | ✅ done |
|
||||
| **2.** The exit policy is part of the Gateway setup by default. To disable this exit policy, operators must use `--disable-exit-policy` flag. | 🛠️ in progress |
|
||||
| **3.** The exit policy is the only option. The `allowed.list` is completely removed. | 🛠️ in progress |
|
||||
|
||||
Keep in mind this only relates to changes happening on Gateway and Network Requester side. Whether this will be optional or mandatory depends on the chosen [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators).
|
||||
Keep in mind the table above only relates to changes happening on Gateways. For the Project Smoosh progress refer to the [table above](./smoosh-faq.md#what-are-the-changes). Whether Exit Gateway functionality will be optional or mandatory part of every active Nym Node depends on the chosen [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators).
|
||||
|
||||
### Can I run a Mix Node only?
|
||||
|
||||
|
||||
@@ -29,15 +29,14 @@ Follow these steps to upgrade your Node binary and update its config file:
|
||||
- if you run it as `systemd` service, run: `systemctl stop nym-<NODE>.service`
|
||||
* Replace the existing `<NODE>` binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)).
|
||||
* Re-run `init` with the same values as you used initially for your `<NODE>` ([Mix Node](./mix-node-setup.md#initialising-your-mix-node), [Gateway](./gateway-setup.md#initialising-your-gateway)) . **This will just update the config file, it will not overwrite existing keys**.
|
||||
* Restart your node process with the new binary.
|
||||
- if you automatized (recommended) run:
|
||||
* Restart your node process with the new binary:
|
||||
- if your node is not automitized, just `run` your `<NODE>` with `./nym-<NODE> run --id <ID>`. Here are exact guidelines for [Mix Node](./mix-node-setup.md#running-your-mix-node) and [Gateway](./gateway-setup.md#running-your-gateway).
|
||||
- if you automatized your node via systemd (recommended) run:
|
||||
```sh
|
||||
systemctl daemon-reload # to pickup the new unit file
|
||||
systemctl start nym-<NODE>.service
|
||||
journalctl -f -u <NODE>.service # to monitor log of you node
|
||||
```
|
||||
- if your node is not automitized, just `run` your `<NODE>` with `./nym-<NODE> run --id <ID>`. Here are exact guidelines for [Mix Node](./mix-node-setup.md#running-your-mix-node) and [Gateway](./gateway-setup.md#running-your-gateway).
|
||||
|
||||
|
||||
If these steps are too difficult and you prefer to just run a script, you can use [ExploreNYM script](https://github.com/ExploreNYM/bash-tool) or one done by [Nym developers](https://gist.github.com/tommyv1987/4dca7cc175b70742c9ecb3d072eb8539).
|
||||
|
||||
|
||||
@@ -580,7 +580,9 @@ mod test {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic]
|
||||
#[should_panic(
|
||||
expected = "Received committed block which isn't last produced block, this is a bug!"
|
||||
)]
|
||||
async fn test_on_committed_with_invalid_pending_block() {
|
||||
let (mut manager, _) = block_manager_with_defaults();
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import { Typography } from '@mui/material';
|
||||
import MuiLink from '@mui/material/Link';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { Socials } from './Socials';
|
||||
import { useIsMobile } from '../hooks/useIsMobile';
|
||||
import { NymVpnIcon } from '../icons/NymVpn';
|
||||
|
||||
export const Footer: FCWithChildren = () => {
|
||||
const isMobile = useIsMobile();
|
||||
@@ -31,6 +34,9 @@ export const Footer: FCWithChildren = () => {
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<MuiLink component={Link} to="http://nymvpn.com" target="_blank" underline="none" marginRight={1}>
|
||||
<NymVpnIcon />
|
||||
</MuiLink>
|
||||
<Socials isFooter />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { useMainContext } from '../context/main';
|
||||
import { MobileDrawerClose } from '../icons/MobileDrawerClose';
|
||||
import { Socials } from './Socials';
|
||||
import { Footer } from './Footer';
|
||||
import { NymVpnIcon } from '../icons/NymVpn';
|
||||
import { DarkLightSwitchDesktop } from './Switch';
|
||||
import { NavOptionType } from '../context/nav';
|
||||
|
||||
@@ -341,6 +342,9 @@ export const Nav: FCWithChildren = ({ children }) => {
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<MuiLink component={Link} to="http://nymvpn.com" target="_blank" underline="none" marginRight={1}>
|
||||
<NymVpnIcon />
|
||||
</MuiLink>
|
||||
<Socials />
|
||||
<DarkLightSwitchDesktop defaultChecked />
|
||||
</Box>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import * as React from 'react';
|
||||
|
||||
interface DiscordIconProps {
|
||||
size?: { width: number; height: number };
|
||||
}
|
||||
|
||||
export const NymVpnIcon: FCWithChildren<DiscordIconProps> = ({ size }) => (
|
||||
<svg width={size?.width} height={size?.height} viewBox="0 0 170 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M19.6118 0.128906H19.5405V0.187854V20.7961L10.7849 0.164277L10.773 0.128906H10.7255H5.75959H0.187819H0.128418V0.187854V23.8142V23.8732H0.187819H5.75959H5.81899V23.8142V3.17063L14.6103 23.8378L14.6222 23.8732H14.6697H19.6118H25.1717H25.2311V23.8142V0.187854V0.128906H25.1717H19.6118Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M19.4121 0H25.3603V24H14.5297L14.4901 23.8819L5.94824 3.80121V24H0V0H10.8663L10.906 0.118132L19.4121 20.1621V0ZM19.5409 20.7951L10.7853 0.163225L10.7734 0.127854H0.128835V23.8721H5.81941V3.16958L14.6107 23.8368L14.6226 23.8721H25.2315V0.127854H19.5409V20.7951Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M89.8116 0.128906H79.1908H79.1314L79.1195 0.176068L73.6784 20.8904L68.2255 0.176068L68.2136 0.128906H68.1661H57.5215H57.4502V0.187854V23.8142V23.8732H57.5215H63.0814H63.1408V23.8142V3.33568L68.5225 23.826L68.5343 23.8732H68.5937H78.7394H78.7869L78.7988 23.826L84.1804 3.33568V23.8142V23.8732H84.2398H89.8116H89.871V23.8142V0.187854V0.128906H89.8116Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M79.0312 0H90.0003V24H84.052V4.33208L78.9242 23.856L78.9238 23.8572L78.8879 24H68.4342L68.3982 23.8572L68.3979 23.856L63.27 4.33208V24H57.3218V0H68.3146L68.3505 0.142699L68.3509 0.144015L73.6787 20.383L78.9949 0.144015L78.9953 0.142765L79.0312 0ZM73.6788 20.8894L68.2259 0.175015L68.214 0.127854H57.4506V23.8721H63.1412V3.33463L68.5229 23.825L68.5348 23.8721H78.7873L78.7992 23.825L84.1809 3.33463V23.8721H89.8714V0.127854H79.1318L79.1199 0.175015L73.6788 20.8894Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M48.2909 0.128906H48.2553L48.2434 0.152487L41.4836 11.8124L34.6882 0.152487L34.6763 0.128906H34.6407H28.2135H28.0947L28.1541 0.223225L38.6205 18.2142V23.8142V23.8732H38.6799H44.2517H44.3111V23.8142V18.2142L54.7775 0.223225L54.8369 0.128906H54.7181H48.2909Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M48.1757 0H55.0693L54.8879 0.288036L44.4399 18.2474V24H38.4917V18.2474L28.0437 0.288036L27.8623 0H34.756L34.8017 0.0907854L41.4833 11.5555L48.1299 0.0909153L48.1757 0ZM48.2434 0.151434L41.4836 11.8114L34.6882 0.151434L34.6763 0.127854H28.0948L28.1542 0.222173L38.6205 18.2131V23.8721H44.3111V18.2131L54.7775 0.222173L54.8369 0.127854H48.2553L48.2434 0.151434Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M169.238 0V24H166.422C166.006 24 165.654 23.9341 165.366 23.8023C165.088 23.6596 164.811 23.418 164.534 23.0776L153.542 8.76321C153.584 9.19149 153.611 9.60878 153.622 10.0151C153.643 10.4104 153.654 10.7838 153.654 11.1352V24H148.886V0H151.734C151.968 0 152.166 0.0109813 152.326 0.032944C152.486 0.0549066 152.63 0.0988326 152.758 0.164722C152.886 0.219629 153.008 0.30199 153.126 0.411805C153.243 0.521619 153.376 0.669869 153.526 0.856553L164.614 15.2697C164.56 14.8085 164.523 14.3638 164.502 13.9355C164.48 13.4962 164.47 13.0844 164.47 12.7001V0H169.238Z"
|
||||
fill="#A8A6A6"
|
||||
/>
|
||||
<path
|
||||
d="M134.206 11.7776C135.614 11.7776 136.627 11.4317 137.246 10.7399C137.865 10.048 138.174 9.08167 138.174 7.84077C138.174 7.29169 138.094 6.79204 137.934 6.3418C137.774 5.89156 137.529 5.50721 137.198 5.18874C136.878 4.8593 136.467 4.60673 135.966 4.43102C135.475 4.25532 134.889 4.16747 134.206 4.16747H131.39V11.7776H134.206ZM134.206 0C135.849 0 137.257 0.203157 138.43 0.609471C139.614 1.0048 140.585 1.55388 141.342 2.25669C142.11 2.95951 142.675 3.78861 143.038 4.74399C143.401 5.69938 143.582 6.73164 143.582 7.84077C143.582 9.03775 143.395 10.1359 143.022 11.1352C142.649 12.1345 142.078 12.9911 141.31 13.7049C140.542 14.4187 139.566 14.9787 138.382 15.385C137.209 15.7804 135.817 15.978 134.206 15.978H131.39V24H125.982V0H134.206Z"
|
||||
fill="#A8A6A6"
|
||||
/>
|
||||
<path
|
||||
d="M121.584 0L112.24 24H107.344L98 0H102.352C102.821 0 103.2 0.115305 103.488 0.345915C103.776 0.565545 103.995 0.851064 104.144 1.20247L108.656 14.0508C108.869 14.6108 109.077 15.2258 109.28 15.8957C109.483 16.5546 109.675 17.2464 109.856 17.9712C110.005 17.2464 110.171 16.5546 110.352 15.8957C110.544 15.2258 110.747 14.6108 110.96 14.0508L115.44 1.20247C115.557 0.894989 115.765 0.620452 116.064 0.378861C116.373 0.126287 116.752 0 117.2 0H121.584Z"
|
||||
fill="#A8A6A6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
NymVpnIcon.defaultProps = {
|
||||
size: { width: 80, height: 12 },
|
||||
};
|
||||
+1
-4
@@ -76,7 +76,7 @@ nym-statistics-common = { path = "../common/statistics" }
|
||||
nym-task = { path = "../common/task" }
|
||||
nym-types = { path = "../common/types" }
|
||||
nym-validator-client = { path = "../common/client-libs/validator-client" }
|
||||
nym-wireguard = { path = "../common/wireguard", optional = true }
|
||||
nym-wireguard = { path = "../common/wireguard" }
|
||||
nym-ip-packet-router = { path = "../service-providers/ip-packet-router" }
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -92,6 +92,3 @@ sqlx = { version = "0.5", features = [
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
|
||||
[features]
|
||||
wireguard = ["nym-wireguard"]
|
||||
|
||||
+12
-10
@@ -200,7 +200,6 @@ impl<St> Gateway<St> {
|
||||
mixnet_handling::Listener::new(listening_address, shutdown).start(connection_handler);
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn start_wireguard(
|
||||
&self,
|
||||
shutdown: TaskClient,
|
||||
@@ -520,15 +519,18 @@ impl<St> Gateway<St> {
|
||||
Arc::new(coconut_verifier),
|
||||
);
|
||||
|
||||
// Once this is a bit more mature, make this a commandline flag instead of a compile time
|
||||
// flag
|
||||
#[cfg(feature = "wireguard")]
|
||||
if let Err(err) = self
|
||||
.start_wireguard(shutdown.subscribe().named("wireguard"))
|
||||
.await
|
||||
{
|
||||
// that's a nasty workaround, but anyhow errors are generally nicer, especially on exit
|
||||
bail!("{err}")
|
||||
// TODO: later we'll make this a commandline flag
|
||||
let wireguard_enabled = std::env::var("NYM_ENABLE_WIREGUARD")
|
||||
.map(|v| v == "1")
|
||||
.unwrap_or(false);
|
||||
if wireguard_enabled {
|
||||
if let Err(err) = self
|
||||
.start_wireguard(shutdown.subscribe().named("wireguard"))
|
||||
.await
|
||||
{
|
||||
// that's a nasty workaround, but anyhow errors are generally nicer, especially on exit
|
||||
bail!("{err}")
|
||||
}
|
||||
}
|
||||
|
||||
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
|
||||
|
||||
@@ -81,3 +81,8 @@ cpucycles = [
|
||||
"opentelemetry",
|
||||
"nym-bin-common/tracing",
|
||||
]
|
||||
|
||||
[package.metadata.deb]
|
||||
name = "nym-mixnode"
|
||||
maintainer-scripts = "debian"
|
||||
systemd-units = { enable = false }
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#DEBHELPER#
|
||||
|
||||
useradd nym
|
||||
mkdir -p /etc/nym
|
||||
chown -R nym /etc/nym
|
||||
su nym -c 'NYM_HOME_DIR=/etc/nym nym-mixnode init --host 0.0.0.0 --id nym-mixnode'
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Nym Mixnode
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/nym-mixnode run --id nym-mixnode
|
||||
User=nym
|
||||
Environment="NYM_HOME_DIR=/etc/nym"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -28,7 +28,7 @@ tokio = { workspace = true, features = ["sync", "time"] }
|
||||
log = "0.4.17"
|
||||
rand = "0.7.3"
|
||||
|
||||
safer-ffi = { version = "0.1.0-rc1" }
|
||||
safer-ffi = { version = "0.1.4" }
|
||||
|
||||
[target.'cfg(target_os="android")'.dependencies]
|
||||
jni = { version = "0.21", default-features = false }
|
||||
|
||||
@@ -15,12 +15,15 @@ log = { workspace = true }
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
nym-client-core = { path = "../../common/client-core" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-exit-policy = { path = "../../common/exit-policy" }
|
||||
nym-network-requester = { path = "../network-requester" }
|
||||
nym-sdk = { path = "../../sdk/rust/nym-sdk" }
|
||||
nym-service-providers-common = { path = "../common" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-wireguard = { path = "../../common/wireguard" }
|
||||
nym-wireguard-types = { path = "../../common/wireguard-types" }
|
||||
reqwest.workspace = true
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
tap.workspace = true
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
pub use nym_client_core::error::ClientCoreError;
|
||||
use nym_exit_policy::PolicyError;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum IpPacketRouterError {
|
||||
@@ -31,5 +34,29 @@ pub enum IpPacketRouterError {
|
||||
PacketParseFailed { source: etherparse::ReadError },
|
||||
|
||||
#[error("parsed packet is missing IP header")]
|
||||
PacketMissingHeader,
|
||||
PacketMissingIpHeader,
|
||||
|
||||
#[error("parsed packet is missing transport header")]
|
||||
PacketMissingTransportHeader,
|
||||
|
||||
#[error("the provided socket address, '{addr}' is not covered by the exit policy!")]
|
||||
AddressNotCoveredByExitPolicy { addr: SocketAddr },
|
||||
|
||||
#[error("failed filter check: '{addr}'")]
|
||||
AddressFailedFilterCheck { addr: SocketAddr },
|
||||
|
||||
#[error("failed to apply the exit policy: {source}")]
|
||||
ExitPolicyFailure {
|
||||
#[from]
|
||||
source: PolicyError,
|
||||
},
|
||||
|
||||
#[error("the url provided for the upstream exit policy source is malformed: {source}")]
|
||||
MalformedExitPolicyUpstreamUrl {
|
||||
#[source]
|
||||
source: reqwest::Error,
|
||||
},
|
||||
|
||||
#[error("can't setup an exit policy without any upstream urls")]
|
||||
NoUpstreamExitPolicy,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
use std::{net::IpAddr, path::Path};
|
||||
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
|
||||
|
||||
use std::{
|
||||
net::{IpAddr, SocketAddr},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use error::IpPacketRouterError;
|
||||
use futures::{channel::oneshot, StreamExt};
|
||||
@@ -12,6 +17,7 @@ use nym_sdk::{
|
||||
};
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::{connections::TransmissionLane, TaskClient, TaskHandle};
|
||||
use request_filter::RequestFilter;
|
||||
use tap::TapFallible;
|
||||
|
||||
use crate::config::BaseClientConfig;
|
||||
@@ -20,6 +26,7 @@ pub use crate::config::Config;
|
||||
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
mod request_filter;
|
||||
|
||||
// The interface used to route traffic
|
||||
pub const TUN_BASE_NAME: &str = "nymtun";
|
||||
@@ -29,11 +36,16 @@ pub const TUN_DEVICE_NETMASK: &str = "255.255.255.0";
|
||||
pub struct OnStartData {
|
||||
// to add more fields as required
|
||||
pub address: Recipient,
|
||||
|
||||
pub request_filter: RequestFilter,
|
||||
}
|
||||
|
||||
impl OnStartData {
|
||||
pub fn new(address: Recipient) -> Self {
|
||||
Self { address }
|
||||
pub fn new(address: Recipient, request_filter: RequestFilter) -> Self {
|
||||
Self {
|
||||
address,
|
||||
request_filter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,9 +151,12 @@ impl IpPacketRouterBuilder {
|
||||
);
|
||||
tun.start();
|
||||
|
||||
let request_filter = request_filter::RequestFilter::new(&self.config).await?;
|
||||
request_filter.start_update_tasks().await;
|
||||
|
||||
let ip_packet_router_service = IpPacketRouter {
|
||||
_config: self.config,
|
||||
// tun,
|
||||
request_filter: request_filter.clone(),
|
||||
tun_task_tx,
|
||||
tun_task_response_rx,
|
||||
mixnet_client,
|
||||
@@ -152,7 +167,10 @@ impl IpPacketRouterBuilder {
|
||||
log::info!("All systems go. Press CTRL-C to stop the server.");
|
||||
|
||||
if let Some(on_start) = self.on_start {
|
||||
if on_start.send(OnStartData::new(self_address)).is_err() {
|
||||
if on_start
|
||||
.send(OnStartData::new(self_address, request_filter))
|
||||
.is_err()
|
||||
{
|
||||
// the parent has dropped the channel before receiving the response
|
||||
return Err(IpPacketRouterError::DisconnectedParent);
|
||||
}
|
||||
@@ -165,7 +183,7 @@ impl IpPacketRouterBuilder {
|
||||
#[allow(unused)]
|
||||
struct IpPacketRouter {
|
||||
_config: Config,
|
||||
// tun: nym_wireguard::tun_device::TunDevice,
|
||||
request_filter: request_filter::RequestFilter,
|
||||
tun_task_tx: nym_wireguard::tun_task_channel::TunTaskTx,
|
||||
tun_task_response_rx: nym_wireguard::tun_task_channel::TunTaskResponseRx,
|
||||
mixnet_client: nym_sdk::mixnet::MixnetClient,
|
||||
@@ -235,26 +253,38 @@ impl IpPacketRouter {
|
||||
) -> Result<(), IpPacketRouterError> {
|
||||
log::info!("Received message: {:?}", reconstructed.sender_tag);
|
||||
|
||||
let headers = etherparse::SlicedPacket::from_ip(&reconstructed.message).map_err(|err| {
|
||||
log::warn!("Received non-IP packet: {err}");
|
||||
IpPacketRouterError::PacketParseFailed { source: err }
|
||||
})?;
|
||||
// We don't forward packets that we are not able to parse. BUT, there might be a good
|
||||
// reason to still forward them.
|
||||
//
|
||||
// For example, if we are running in a mode where we are only supposed to forward
|
||||
// packets to a specific destination, we might want to forward them anyway.
|
||||
//
|
||||
// TODO: look into this
|
||||
let ParsedPacket {
|
||||
packet_type,
|
||||
src_addr,
|
||||
dst_addr,
|
||||
dst,
|
||||
} = parse_packet(&reconstructed.message)?;
|
||||
|
||||
let (src_addr, dst_addr): (IpAddr, IpAddr) = match headers.ip {
|
||||
Some(etherparse::InternetSlice::Ipv4(ipv4_header, _)) => (
|
||||
ipv4_header.source_addr().into(),
|
||||
ipv4_header.destination_addr().into(),
|
||||
),
|
||||
Some(etherparse::InternetSlice::Ipv6(ipv6_header, _)) => (
|
||||
ipv6_header.source_addr().into(),
|
||||
ipv6_header.destination_addr().into(),
|
||||
),
|
||||
None => {
|
||||
log::warn!("Received non-IP packet");
|
||||
return Err(IpPacketRouterError::PacketMissingHeader);
|
||||
let dst_str = dst.map_or(dst_addr.to_string(), |dst| dst.to_string());
|
||||
log::info!("Received packet: {packet_type}: {src_addr} -> {dst_str}");
|
||||
|
||||
// Filter check
|
||||
if let Some(dst) = dst {
|
||||
if !self.request_filter.check_address(&dst).await {
|
||||
log::warn!("Failed filter check: {dst}");
|
||||
|
||||
// TODO: send back a response here
|
||||
|
||||
return Err(IpPacketRouterError::AddressFailedFilterCheck { addr: dst });
|
||||
}
|
||||
};
|
||||
log::info!("Received packet: {src_addr} -> {dst_addr}");
|
||||
} else {
|
||||
// TODO: are we always allowing packets without port numbers?
|
||||
log::warn!(
|
||||
"Ignoring filter check for packet without port number! (TODO: is this correct?)"
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: set the tag correctly. Can we just reuse sender_tag?
|
||||
let peer_tag = 0;
|
||||
@@ -270,6 +300,57 @@ impl IpPacketRouter {
|
||||
}
|
||||
}
|
||||
|
||||
struct ParsedPacket<'a> {
|
||||
packet_type: &'a str,
|
||||
src_addr: IpAddr,
|
||||
dst_addr: IpAddr,
|
||||
dst: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
fn parse_packet(packet: &[u8]) -> Result<ParsedPacket, IpPacketRouterError> {
|
||||
let headers = etherparse::SlicedPacket::from_ip(packet).map_err(|err| {
|
||||
log::warn!("Unable to parse incoming data as IP packet: {err}");
|
||||
IpPacketRouterError::PacketParseFailed { source: err }
|
||||
})?;
|
||||
|
||||
let (packet_type, dst_port) = match headers.transport {
|
||||
Some(etherparse::TransportSlice::Udp(header)) => ("ipv4", Some(header.destination_port())),
|
||||
Some(etherparse::TransportSlice::Tcp(header)) => ("ipv6", Some(header.destination_port())),
|
||||
Some(etherparse::TransportSlice::Icmpv4(_)) => ("icpv4", None),
|
||||
Some(etherparse::TransportSlice::Icmpv6(_)) => ("icmpv6", None),
|
||||
Some(etherparse::TransportSlice::Unknown(_)) => ("unknown", None),
|
||||
None => {
|
||||
log::warn!("Received packet missing transport header");
|
||||
return Err(IpPacketRouterError::PacketMissingTransportHeader);
|
||||
}
|
||||
};
|
||||
|
||||
let (src_addr, dst_addr, dst) = match headers.ip {
|
||||
Some(etherparse::InternetSlice::Ipv4(ipv4_header, _)) => {
|
||||
let src_addr: IpAddr = ipv4_header.source_addr().into();
|
||||
let dst_addr: IpAddr = ipv4_header.destination_addr().into();
|
||||
let dst = dst_port.map(|port| SocketAddr::new(dst_addr, port));
|
||||
(src_addr, dst_addr, dst)
|
||||
}
|
||||
Some(etherparse::InternetSlice::Ipv6(ipv6_header, _)) => {
|
||||
let src_addr: IpAddr = ipv6_header.source_addr().into();
|
||||
let dst_addr: IpAddr = ipv6_header.destination_addr().into();
|
||||
let dst = dst_port.map(|port| SocketAddr::new(dst_addr, port));
|
||||
(src_addr, dst_addr, dst)
|
||||
}
|
||||
None => {
|
||||
log::warn!("Received packet missing IP header");
|
||||
return Err(IpPacketRouterError::PacketMissingIpHeader);
|
||||
}
|
||||
};
|
||||
Ok(ParsedPacket {
|
||||
packet_type,
|
||||
src_addr,
|
||||
dst_addr,
|
||||
dst,
|
||||
})
|
||||
}
|
||||
|
||||
// Helper function to create the mixnet client.
|
||||
// This is NOT in the SDK since we don't want to expose any of the client-core config types.
|
||||
// We could however consider moving it to a crate in common in the future.
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use crate::error::IpPacketRouterError;
|
||||
use nym_exit_policy::client::get_exit_policy;
|
||||
use nym_exit_policy::ExitPolicy;
|
||||
use reqwest::IntoUrl;
|
||||
use url::Url;
|
||||
|
||||
pub struct ExitPolicyRequestFilter {
|
||||
upstream: Option<Url>,
|
||||
policy: ExitPolicy,
|
||||
}
|
||||
|
||||
impl ExitPolicyRequestFilter {
|
||||
pub(crate) async fn new_upstream(url: impl IntoUrl) -> Result<Self, IpPacketRouterError> {
|
||||
let url = url
|
||||
.into_url()
|
||||
.map_err(|source| IpPacketRouterError::MalformedExitPolicyUpstreamUrl { source })?;
|
||||
|
||||
Ok(ExitPolicyRequestFilter {
|
||||
upstream: Some(url.clone()),
|
||||
policy: get_exit_policy(url).await?,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn new(policy: ExitPolicy) -> Self {
|
||||
ExitPolicyRequestFilter {
|
||||
upstream: None,
|
||||
policy,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn policy(&self) -> &ExitPolicy {
|
||||
&self.policy
|
||||
}
|
||||
|
||||
pub fn upstream(&self) -> Option<&Url> {
|
||||
self.upstream.as_ref()
|
||||
}
|
||||
|
||||
pub(crate) async fn check(&self, addr: &SocketAddr) -> Result<bool, IpPacketRouterError> {
|
||||
self.policy
|
||||
.allows_sockaddr(addr)
|
||||
.ok_or(IpPacketRouterError::AddressNotCoveredByExitPolicy { addr: *addr })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::error::IpPacketRouterError;
|
||||
use crate::request_filter::exit_policy::ExitPolicyRequestFilter;
|
||||
use log::{info, warn};
|
||||
use std::{net::SocketAddr, sync::Arc};
|
||||
|
||||
pub mod exit_policy;
|
||||
|
||||
enum RequestFilterInner {
|
||||
ExitPolicy {
|
||||
policy_filter: ExitPolicyRequestFilter,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RequestFilter {
|
||||
inner: Arc<RequestFilterInner>,
|
||||
}
|
||||
|
||||
impl RequestFilter {
|
||||
pub(crate) async fn new(config: &Config) -> Result<Self, IpPacketRouterError> {
|
||||
info!("setting up ExitPolicy based request filter...");
|
||||
Self::new_exit_policy_filter(config).await
|
||||
}
|
||||
|
||||
pub fn current_exit_policy_filter(&self) -> Option<&ExitPolicyRequestFilter> {
|
||||
match &*self.inner {
|
||||
RequestFilterInner::ExitPolicy { policy_filter } => Some(policy_filter),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn start_update_tasks(&self) {
|
||||
match &*self.inner {
|
||||
RequestFilterInner::ExitPolicy { .. } => {
|
||||
// nothing to do for the exit policy (yet; we might add a refresher at some point)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn new_exit_policy_filter(config: &Config) -> Result<Self, IpPacketRouterError> {
|
||||
let upstream_url = config
|
||||
.ip_packet_router
|
||||
.upstream_exit_policy_url
|
||||
.as_ref()
|
||||
.ok_or(IpPacketRouterError::NoUpstreamExitPolicy)?;
|
||||
let policy_filter = ExitPolicyRequestFilter::new_upstream(upstream_url.clone()).await?;
|
||||
Ok(RequestFilter {
|
||||
inner: Arc::new(RequestFilterInner::ExitPolicy { policy_filter }),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn check_address(&self, address: &SocketAddr) -> bool {
|
||||
match &*self.inner {
|
||||
RequestFilterInner::ExitPolicy { policy_filter } => {
|
||||
match policy_filter.check(address).await {
|
||||
Err(err) => {
|
||||
warn!("failed to validate '{address}' against the exit policy: {err}");
|
||||
false
|
||||
}
|
||||
Ok(res) => res,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user