Skip to content

Commit 99bffe6

Browse files
Bownairomarko-k0
authored andcommitted
Update firewall configuration through SetupOS and HostOS
1 parent 6b7b236 commit 99bffe6

File tree

33 files changed

+207
-185
lines changed

33 files changed

+207
-185
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ic-os/defs.bzl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ def icos_build(
482482
":disk-img.tar.zst.cas-url",
483483
":disk-img.tar.zst.sha256",
484484
"//ic-os:scripts/build-bootstrap-config-image.sh",
485-
"//rs/tests:src/ipv6_prefixes.json",
485+
"//rs/tests:src/default_firewall_whitelist.conf",
486486
":version.txt",
487487
],
488488
outs = ["launch_remote_vm_script"],
@@ -492,12 +492,12 @@ def icos_build(
492492
URL="$$(cat $(location :disk-img.tar.zst.cas-url))"
493493
SHA="$$(cat $(location :disk-img.tar.zst.sha256))"
494494
SCRIPT="$(location //ic-os:scripts/build-bootstrap-config-image.sh)"
495-
IPV6_PREFIXES="$(location //rs/tests:src/ipv6_prefixes.json)"
495+
DEFAULT_FIREWALL_WHITELIST="$(location //rs/tests:src/default_firewall_whitelist.conf)"
496496
cat <<EOF > $@
497497
#!/usr/bin/env bash
498498
set -euo pipefail
499499
cd "\\$$BUILD_WORKSPACE_DIRECTORY"
500-
$$BIN --version "$$VERSION" --url "$$URL" --sha256 "$$SHA" --build-bootstrap-script "$$SCRIPT" --ipv6-prefixes-path "$$IPV6_PREFIXES"
500+
$$BIN --version "$$VERSION" --url "$$URL" --sha256 "$$SHA" --build-bootstrap-script "$$SCRIPT" --default-firewall-whitelist "$$DEFAULT_FIREWALL_WHITELIST"
501501
EOF
502502
""",
503503
executable = True,

ic-os/guestos/rootfs/etc/systemd/system/ic-crypto-csp.service

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Environment=RUST_BACKTRACE=1
2020
# only on ExecStartPre by ic-replica.service. As a temporary workaround, we are generating
2121
# an ic-csp-service-specific version of ic.json5 of which only the parts related to crypto
2222
# and logging are relevant.
23-
ExecStartPre=+/opt/ic/bin/generate-replica-config.sh -n /boot/config/network.conf -i /opt/ic/share/ic.json5.template -o /run/ic-node/config/ic-crypto-csp.json5
23+
ExecStartPre=+/opt/ic/bin/generate-replica-config.sh -i /opt/ic/share/ic.json5.template -o /run/ic-node/config/ic-crypto-csp.json5
2424
ExecStart=/opt/ic/bin/ic-crypto-csp --replica-config-file /run/ic-node/config/ic-crypto-csp.json5
2525
NotifyAccess=main
2626
Restart=always

ic-os/guestos/rootfs/etc/systemd/system/ic-replica.service

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Environment=RUST_BACKTRACE=1
2828
# Remember to update 'rs/default.nix' for nix-shell users
2929
# Remember to update 'src/dfx/src/actors/replica.rs' in the sdk repo for dfx users
3030
Environment=RUST_MIN_STACK=8192000
31-
ExecStartPre=+/opt/ic/bin/generate-replica-config.sh -n /boot/config/network.conf -c /boot/config/nns.conf -b /boot/config/backup.conf -l /boot/config/log.conf -m /boot/config/malicious_behavior.conf -q /boot/config/query_stats.conf -i /opt/ic/share/ic.json5.template -o /run/ic-node/config/ic.json5
31+
ExecStartPre=+/opt/ic/bin/generate-replica-config.sh -n /boot/config/network.conf -c /boot/config/nns.conf -b /boot/config/backup.conf -l /boot/config/log.conf -m /boot/config/malicious_behavior.conf -q /boot/config/query_stats.conf -w /boot/config/default_firewall_whitelist.conf -i /opt/ic/share/ic.json5.template -o /run/ic-node/config/ic.json5
3232
ExecStart=/opt/ic/bin/orchestrator --replica-binary-dir /var/lib/ic/data/images --cup-dir /var/lib/ic/data/cups --replica-config-file /run/ic-node/config/ic.json5 --enable-provisional-registration --ic-binary-directory /opt/ic/bin --orchestrator-data-directory /var/lib/ic/data/orchestrator --version-file /opt/ic/share/version.txt
3333
LimitNOFILE=1048576
3434
Restart=always

ic-os/guestos/rootfs/opt/ic/bin/bootstrap-ic-node.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function process_bootstrap() {
127127

128128
# stash the following configuration files to config store
129129
# note: keep this list in sync with configurations supported in build-bootstrap-config-image.sh
130-
for FILE in filebeat.conf network.conf nns.conf backup.conf log.conf malicious_behavior.conf query_stats.conf bitcoind_addr.conf socks_proxy.conf; do
130+
for FILE in filebeat.conf network.conf nns.conf backup.conf log.conf malicious_behavior.conf query_stats.conf bitcoind_addr.conf socks_proxy.conf default_firewall_whitelist.conf; do
131131
if [ -e "${TMPDIR}/${FILE}" ]; then
132132
echo "Setting up ${FILE}"
133133
cp "${TMPDIR}/${FILE}" "${CONFIG_ROOT}/${FILE}"

ic-os/guestos/rootfs/opt/ic/bin/generate-replica-config.sh

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
function usage() {
77
cat <<EOF
88
Usage:
9-
generate-replica-config [-n network.conf] [-c nns.conf] [-b backup.conf] [-l log.conf] [-m malicious_behavior.conf] [-q query_stats.conf] -i ic.json5.template -o ic.json5
9+
generate-replica-config [-n network.conf] [-c nns.conf] [-b backup.conf] [-l log.conf] [-m malicious_behavior.conf] [-q query_stats.conf] [-w default_firewall_whitelist.conf] -i ic.json5.template -o ic.json5
1010
1111
Generate replica config from template file.
1212
@@ -16,6 +16,7 @@ Usage:
1616
-l log.conf: Optional, logging parameters of the node software
1717
-m malicious_behavior.conf: Optional, malicious behavior parameters
1818
-q query_stats.conf: Optional, query statistics epoch length configuration
19+
-w default_firewall_whitelist.conf: Optional, default firewall whitelist configuration
1920
-i infile: input ic.json5.template file
2021
-o outfile: output ic.json5 file
2122
EOF
@@ -76,7 +77,6 @@ function read_network_variables() {
7677
"ipv6_address") ipv6_address="${value}" ;;
7778
"ipv6_gateway") ipv6_gateway="${value}" ;;
7879
"name_servers") name_servers="${value}" ;;
79-
"ipv6_prefixes") ipv6_prefixes="${value}" ;;
8080
"ipv4_address") ipv4_address="${value}" ;;
8181
"ipv4_gateway") ipv4_gateway="${value}" ;;
8282
"domain") domain="${value}" ;;
@@ -158,7 +158,23 @@ function read_query_stats_variables() {
158158
done <"$1"
159159
}
160160

161-
while getopts "l:m:q:n:c:i:o:b:" OPT; do
161+
# Read default firewall whitelist config variables from file. The file must be of the
162+
# form "key=value" for each line with a specific set of keys permissible (see
163+
# code below).
164+
#
165+
# Arguments:
166+
# - $1: Name of the file to be read.
167+
function read_default_firewall_whitelist_variables() {
168+
# Read limited set of keys. Be extra-careful quoting values as it could
169+
# otherwise lead to executing arbitrary shell code!
170+
while IFS="=" read -r key value; do
171+
case "$key" in
172+
"ipv6_whitelist") ipv6_whitelist="${value}" ;;
173+
esac
174+
done <"$1"
175+
}
176+
177+
while getopts "l:m:q:n:c:i:o:b:w:" OPT; do
162178
case "${OPT}" in
163179
n)
164180
NETWORK_CONFIG_FILE="${OPTARG}"
@@ -178,6 +194,9 @@ while getopts "l:m:q:n:c:i:o:b:" OPT; do
178194
q)
179195
QUERY_STATS_CONFIG_FILE="${OPTARG}"
180196
;;
197+
w)
198+
DEFAULT_FIREWALL_WHITELIST_CONFIG_FILE="${OPTARG}"
199+
;;
181200
i)
182201
IN_FILE="${OPTARG}"
183202
;;
@@ -220,10 +239,13 @@ if [ "${QUERY_STATS_CONFIG_FILE}" != "" -a -e "${QUERY_STATS_CONFIG_FILE}" ]; th
220239
read_query_stats_variables "${QUERY_STATS_CONFIG_FILE}"
221240
fi
222241

242+
if [ "${DEFAULT_FIREWALL_WHITELIST_CONFIG_FILE}" != "" -a -e "${DEFAULT_FIREWALL_WHITELIST_CONFIG_FILE}" ]; then
243+
read_default_firewall_whitelist_variables "${DEFAULT_FIREWALL_WHITELIST_CONFIG_FILE}"
244+
fi
245+
223246
INTERFACE=($(find /sys/class/net -type l -not -lname '*virtual*' -exec basename '{}' ';'))
224247
IPV6_ADDRESS="${ipv6_address%/*}"
225248
IPV6_ADDRESS="${IPV6_ADDRESS:-$(get_if_address_retries 6 ${INTERFACE} 12)}"
226-
IPV6_PREFIXES="${ipv6_prefixes:-}"
227249
IPV4_ADDRESS="${ipv4_address:-}"
228250
IPV4_GATEWAY="${ipv4_gateway:-}"
229251
DOMAIN="${domain:-}"
@@ -241,6 +263,8 @@ MALICIOUS_BEHAVIOR="${malicious_behavior:-null}"
241263
QUERY_STATS_AGGREGATION="${query_stats_aggregation:-\"Disabled\"}"
242264
# Default is 1800 blocks i.e. around 30min
243265
QUERY_STATS_EPOCH_LENGTH="${query_stats_epoch_length:-1800}"
266+
# Default value is none
267+
IPV6_WHITELIST="${ipv6_whitelist:-}"
244268

245269
if [ "${IPV6_ADDRESS}" == "" ]; then
246270
echo "Cannot determine an IPv6 address, aborting"
@@ -264,7 +288,6 @@ if [ "${hostname}" == "" ]; then
264288
fi
265289

266290
sed -e "s@{{ ipv6_address }}@${IPV6_ADDRESS}@" \
267-
-e "s@{{ ipv6_prefixes }}@${IPV6_PREFIXES}@" \
268291
-e "s@{{ ipv4_address }}@${IPV4_ADDRESS}@" \
269292
-e "s@{{ ipv4_gateway }}@${IPV4_GATEWAY}@" \
270293
-e "s@{{ domain }}@${DOMAIN}@" \
@@ -276,6 +299,7 @@ sed -e "s@{{ ipv6_address }}@${IPV6_ADDRESS}@" \
276299
-e "s@{{ malicious_behavior }}@${MALICIOUS_BEHAVIOR}@" \
277300
-e "s@{{ query_stats_aggregation }}@${QUERY_STATS_AGGREGATION}@" \
278301
-e "s@{{ query_stats_epoch_length }}@${QUERY_STATS_EPOCH_LENGTH}@" \
302+
-e "s@{{ ipv6_whitelist }}@${IPV6_WHITELIST}@" \
279303
"${IN_FILE}" >"${OUT_FILE}"
280304

281305
# umask for service is set to be restricted, but this file needs to be

ic-os/guestos/rootfs/opt/ic/share/ic.json5.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ table ip6 filter {\n\
267267
ipv6_user_output_rule_template: "meta skuid <<USER>> ip6 daddr {<<IPv6_PREFIXES>>} ct state { new } tcp dport {<<PORTS>>} <<ACTION>> # <<COMMENT>>",
268268
default_rules: [{
269269
ipv4_prefixes: [],
270-
ipv6_prefixes: {{ ipv6_prefixes }},
270+
ipv6_prefixes: [{{ ipv6_whitelist }}],
271271
ports: [22, 2497, 4100, 7070, 8080, 9090, 9091, 9100, 19100, 19531],
272272
action: 1,
273273
comment: "Default rule from template",

ic-os/hostos/rootfs/opt/ic/bin/generate-guestos-config.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ function assemble_config_media() {
115115
if [ -f "/boot/config/node_operator_private_key.pem" ]; then
116116
cmd+=(--node_operator_private_key "/boot/config/node_operator_private_key.pem")
117117
fi
118+
if [ -f "/boot/config/default_firewall_whitelist.conf" ]; then
119+
cmd+=(--default_firewall_whitelist "/boot/config/default_firewall_whitelist.conf")
120+
fi
118121

119122
# Run the above command
120123
"${cmd[@]}"

ic-os/scripts/build-bootstrap-config-image.sh

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ options may be specified:
3333
script, e.g. --ipv6_name_servers "2606:4700:4700::1111
3434
2606:4700:4700::1001").
3535
36-
--ipv6_prefixes prefixes
37-
Comma separated list of IPv6 networks that are whitelisted in the guestOS' firewall on orchestrator startup.
36+
--default_firewall_whitelist path
37+
File containing the default whitelist configuration for GuestOS on
38+
orchestrator startup.
3839
3940
--ipv4_address a.b.c.d/n
4041
(optional) The IPv4 address to assign. Must include prefix length (e.g.
@@ -133,7 +134,7 @@ function build_ic_bootstrap_tar() {
133134
local OUT_FILE="$1"
134135
shift
135136

136-
local IPV6_ADDRESS IPV6_GATEWAY IPV6_NAME_SERVERS IVP6_PREFIXES DOMAIN HOSTNAME
137+
local IPV6_ADDRESS IPV6_GATEWAY IPV6_NAME_SERVERS DOMAIN HOSTNAME
137138
local IC_CRYPTO IC_REGISTRY_LOCAL_STORE
138139
local NNS_URL NNS_PUBLIC_KEY NODE_OPERATOR_PRIVATE_KEY
139140
local BACKUP_RETENTION_TIME_SECS BACKUP_PURGING_INTERVAL_SECS
@@ -143,6 +144,7 @@ function build_ic_bootstrap_tar() {
143144
local MALICIOUS_BEHAVIOR
144145
local QUERY_STATS_EPOCH_LENGTH
145146
local BITCOIND_ADDR
147+
local DEFAULT_FIREWALL_WHITELIST
146148

147149
while true; do
148150
if [ $# == 0 ]; then
@@ -159,8 +161,8 @@ function build_ic_bootstrap_tar() {
159161
--ipv6_name_servers)
160162
IPV6_NAME_SERVERS="$2"
161163
;;
162-
--ipv6_prefixes)
163-
IPV6_PREFIXES="$2"
164+
--default_firewall_whitelist)
165+
DEFAULT_FIREWALL_WHITELIST="$2"
164166
;;
165167
--ipv4_address)
166168
IPV4_ADDRESS="$2"
@@ -240,7 +242,6 @@ function build_ic_bootstrap_tar() {
240242
${IPV6_ADDRESS:+ipv6_address=$IPV6_ADDRESS}
241243
${IPV6_GATEWAY:+ipv6_gateway=$IPV6_GATEWAY}
242244
name_servers=$IPV6_NAME_SERVERS
243-
ipv6_prefixes=$IPV6_PREFIXES
244245
hostname=$HOSTNAME
245246
${IPV4_ADDRESS:+ipv4_address=$IPV4_ADDRESS}
246247
${IPV4_GATEWAY:+ipv4_gateway=$IPV4_GATEWAY}
@@ -289,6 +290,9 @@ EOF
289290
if [ "${NODE_OPERATOR_PRIVATE_KEY}" != "" ]; then
290291
cp "${NODE_OPERATOR_PRIVATE_KEY}" "${BOOTSTRAP_TMPDIR}/node_operator_private_key.pem"
291292
fi
293+
if [ "${DEFAULT_FIREWALL_WHITELIST}" != "" ]; then
294+
cp "${DEFAULT_FIREWALL_WHITELIST}" "${BOOTSTRAP_TMPDIR}/default_firewall_whitelist.conf"
295+
fi
292296

293297
tar cf "${OUT_FILE}" \
294298
--sort=name \

ic-os/setupos/rootfs/opt/ic/bin/config.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ function clone_config() {
4848
log_and_reboot_on_error "${?}" "Unable to copy 'node_operator_private_key.pem' configuration file."
4949
fi
5050

51+
if [ -f "${CONFIG_DIR}/default_firewall_whitelist.conf" ]; then
52+
cp ${CONFIG_DIR}/default_firewall_whitelist.conf ${CONFIG_TMP}/default_firewall_whitelist.conf
53+
log_and_reboot_on_error "${?}" "Unable to copy 'default_firewall_whitelist.conf' configuration file."
54+
fi
55+
5156
if [ -d "${SSH_AUTHORIZED_KEYS}" ]; then
5257
cp -r "${SSH_AUTHORIZED_KEYS}" "${CONFIG_TMP}"
5358
log_and_reboot_on_error "${?}" "Unable to copy 'ssh_authorized_keys' directory."

ic-os/setupos/rootfs/opt/ic/bin/devices.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ function copy_config_files() {
4242
echo "node_operator_private_key.pem does not exist, requiring HSM."
4343
fi
4444

45+
if [ -f "${CONFIG_DIR}/default_firewall_whitelist.conf" ]; then
46+
cp ${CONFIG_DIR}/default_firewall_whitelist.conf /media/
47+
log_and_reboot_on_error "${?}" "Unable to copy default_firewall_whitelist.conf to hostOS config partition."
48+
fi
49+
4550
echo "* Copying deployment.json to config partition..."
4651
cp /data/deployment.json /media/
4752
log_and_reboot_on_error "${?}" "Unable to copy deployment.json to hostOS config partition."

rs/ic_os/launch-single-vm/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ DEPENDENCIES = [
66
"@crate_index//:clap",
77
"@crate_index//:reqwest",
88
"@crate_index//:serde",
9-
"@crate_index//:serde_json",
109
"@crate_index//:slog-async",
1110
"@crate_index//:slog-term",
1211
"@crate_index//:slog",

rs/ic_os/launch-single-vm/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ ic-types = { path = "../../types/types" }
1414
clap = { workspace = true }
1515
reqwest = { workspace = true }
1616
serde = { workspace = true }
17-
serde_json = { workspace = true }
1817
slog-async = { version = "2.5", features = ["nested-values"] }
1918
slog-term = "2.6.0"
2019
slog = { workspace = true }

rs/ic_os/launch-single-vm/src/main.rs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use clap::Parser;
77
use reqwest::blocking::Client;
88
use serde::Serialize;
99
use slog::{o, Drain};
10-
use std::fs::File;
1110
use tempfile::tempdir;
1211
use url::Url;
1312

@@ -40,9 +39,9 @@ struct Args {
4039
/// Path to `build-bootstrap-config-image.sh` script
4140
#[clap(long)]
4241
build_bootstrap_script: PathBuf,
43-
/// Path to ipv6_prefixes.json
42+
/// Path to `default_firewall_whitelist.conf` file
4443
#[clap(long)]
45-
ipv6_prefixes_path: PathBuf,
44+
default_firewall_whitelist: PathBuf,
4645
/// Key to be used for `admin` SSH
4746
#[clap(long)]
4847
ssh_key_path: Option<PathBuf>,
@@ -64,7 +63,7 @@ fn main() {
6463
let url = args.url;
6564
let sha256 = args.sha256;
6665
let build_bootstrap_script = args.build_bootstrap_script;
67-
let ipv6_prefixes_path = args.ipv6_prefixes_path;
66+
let default_firewall_whitelist = args.default_firewall_whitelist;
6867
let ssh_key_path = args.ssh_key_path;
6968

7069
let test_name = "test_single_vm";
@@ -178,16 +177,6 @@ fn main() {
178177
let filename = "config.tar.gz";
179178
let config_path = tempdir.as_ref().join(filename);
180179
let local_store = prep_dir.join("ic_registry_local_store");
181-
let ipv6_prefixes: Vec<String> =
182-
serde_json::from_reader(File::open(ipv6_prefixes_path).unwrap()).unwrap();
183-
let ipv6_prefixes = format!(
184-
"[{}]",
185-
ipv6_prefixes
186-
.iter()
187-
.map(|s| format!("\"{s}\""))
188-
.collect::<Vec<_>>()
189-
.join(", "),
190-
);
191180
Command::new(build_bootstrap_script)
192181
.arg(&config_path)
193182
.arg("--nns_url")
@@ -198,8 +187,8 @@ fn main() {
198187
.arg(&local_store)
199188
.arg("--accounts_ssh_authorized_keys")
200189
.arg(&keys_dir)
201-
.arg("--ipv6_prefixes")
202-
.arg(ipv6_prefixes)
190+
.arg("--default_firewall_whitelist")
191+
.arg(default_firewall_whitelist)
203192
.status()
204193
.unwrap();
205194

rs/ic_os/setupos-inject-configuration/src/main.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ struct Cli {
3434

3535
#[command(flatten)]
3636
deployment: DeploymentConfig,
37+
38+
#[arg(long)]
39+
default_firewall_whitelist_path: Option<PathBuf>,
3740
}
3841

3942
#[derive(Args)]
@@ -120,6 +123,17 @@ async fn main() -> Result<(), Error> {
120123
.context("failed to copy public keys")?;
121124
}
122125

126+
// Update default firewall whitelist
127+
if let Some(default_firewall_whitelist_path) = cli.default_firewall_whitelist_path {
128+
config
129+
.write_file(
130+
&default_firewall_whitelist_path,
131+
Path::new("/default_firewall_whitelist.conf"),
132+
)
133+
.await
134+
.context("failed to copy default firewall config")?;
135+
}
136+
123137
// Close config partition
124138
config.close().await?;
125139

rs/prep/src/internet_computer.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -388,22 +388,23 @@ impl IcConfig {
388388
let mut mutations = self.initial_mutations.clone();
389389

390390
if let Some(prefixes) = self.whitelisted_prefixes {
391-
let ports = if let Some(ports) = self.whitelisted_ports {
392-
ports
391+
// Port 8080 is always included.
392+
let mut ports = vec![8080];
393+
394+
if let Some(additional_ports) = self.whitelisted_ports {
395+
ports = additional_ports
393396
.split(',')
394-
.map(|port| port.parse::<u32>().unwrap())
395-
.chain(std::iter::once(8080))
397+
.map(|port| port.trim().parse::<u32>().unwrap())
398+
.chain(ports)
396399
.collect()
397-
} else {
398-
vec![8080]
399400
};
400401

401402
mutations.extend(vec![insert(
402403
make_firewall_rules_record_key(&FirewallRulesScope::Global),
403404
encode_or_panic(&FirewallRuleSet {
404405
entries: vec![FirewallRule {
405406
ipv4_prefixes: Vec::new(),
406-
ipv6_prefixes: prefixes.split(',').map(|v| v.to_string()).collect(),
407+
ipv6_prefixes: prefixes.split(',').map(|v| v.trim().to_string()).collect(),
407408
ports,
408409
action: FirewallAction::Allow as i32,
409410
comment: "Globally allow provided prefixes for testing".to_string(),

0 commit comments

Comments
 (0)