Compare commits
2 Commits
a4d674190a
...
ff711a2fe1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff711a2fe1 | ||
|
|
4c6b441753 |
@ -3,6 +3,10 @@ name = "rpki"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "rpki_rtr"
|
||||||
|
path = "src/main_rtr.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
der-parser = "10.0.0"
|
der-parser = "10.0.0"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
|||||||
21
deploy/client/.env
Normal file
21
deploy/client/.env
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Target RTR server address for client compose files
|
||||||
|
# TCP example: 10.0.0.12:323
|
||||||
|
# TLS example: rpki.example.com:324
|
||||||
|
# SSH example: 10.0.0.12:22
|
||||||
|
RPKI_RTR_SERVER_ADDR=rpki-rtr-tcp:323
|
||||||
|
|
||||||
|
|
||||||
|
# RTR protocol version used as client command second argument (supported: 0,1,2)
|
||||||
|
RPKI_RTR_PROTOCOL_VERSION=2
|
||||||
|
|
||||||
|
# TLS server name used by --server-name in TLS mode
|
||||||
|
# Must match server certificate SAN dNSName.
|
||||||
|
RPKI_RTR_TLS_SERVER_NAME=localhost
|
||||||
|
|
||||||
|
# SSH mode examples:
|
||||||
|
# RPKI_RTR_SERVER_ADDR=10.0.0.12:2222
|
||||||
|
# RPKI_RTR_CLIENT_KEYS_VOLUME=../../certs:/app/certs:ro
|
||||||
|
# RPKI_RTR_CLIENT_KEY_PATH=/app/certs/rtr-client.key
|
||||||
|
# RPKI_RTR_SSH_SERVER_PUBKEY_PATH=/app/certs/ssh_host_rsa_key.pub
|
||||||
|
# RPKI_RTR_SSH_USERNAME=rpki-rtr
|
||||||
|
# RPKI_RTR_SSH_PASSWORD=your-password
|
||||||
@ -3,7 +3,7 @@ version: "3.9"
|
|||||||
services:
|
services:
|
||||||
rtr-client-1:
|
rtr-client-1:
|
||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command: ["rpki-rtr-tcp:323", "2", "reset", "--keep-after-error", "--summary-only"]
|
command: ["${RPKI_RTR_SERVER_ADDR:-rpki-rtr-tcp:323}", "${RPKI_RTR_PROTOCOL_VERSION:-2}", "reset", "--keep-after-error", "--summary-only"]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../logs/client:/app/logs
|
- ../../logs/client:/app/logs
|
||||||
restart: no
|
restart: no
|
||||||
@ -12,7 +12,7 @@ services:
|
|||||||
|
|
||||||
rtr-client-2:
|
rtr-client-2:
|
||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command: ["rpki-rtr-tcp:323", "2", "reset", "--keep-after-error", "--summary-only"]
|
command: ["${RPKI_RTR_SERVER_ADDR:-rpki-rtr-tcp:323}", "${RPKI_RTR_PROTOCOL_VERSION:-2}", "reset", "--keep-after-error", "--summary-only"]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../logs/client:/app/logs
|
- ../../logs/client:/app/logs
|
||||||
restart: no
|
restart: no
|
||||||
@ -21,7 +21,7 @@ services:
|
|||||||
|
|
||||||
rtr-client-3:
|
rtr-client-3:
|
||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command: ["rpki-rtr-tcp:323", "2", "reset", "--keep-after-error", "--summary-only"]
|
command: ["${RPKI_RTR_SERVER_ADDR:-rpki-rtr-tcp:323}", "${RPKI_RTR_PROTOCOL_VERSION:-2}", "reset", "--keep-after-error", "--summary-only"]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../logs/client:/app/logs
|
- ../../logs/client:/app/logs
|
||||||
restart: no
|
restart: no
|
||||||
@ -30,7 +30,7 @@ services:
|
|||||||
|
|
||||||
rtr-client-4:
|
rtr-client-4:
|
||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command: ["rpki-rtr-tcp:323", "2", "reset", "--keep-after-error", "--summary-only"]
|
command: ["${RPKI_RTR_SERVER_ADDR:-rpki-rtr-tcp:323}", "${RPKI_RTR_PROTOCOL_VERSION:-2}", "reset", "--keep-after-error", "--summary-only"]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../logs/client:/app/logs
|
- ../../logs/client:/app/logs
|
||||||
restart: no
|
restart: no
|
||||||
@ -39,7 +39,7 @@ services:
|
|||||||
|
|
||||||
rtr-client-5:
|
rtr-client-5:
|
||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command: ["rpki-rtr-tcp:323", "2", "reset", "--keep-after-error", "--summary-only"]
|
command: ["${RPKI_RTR_SERVER_ADDR:-rpki-rtr-tcp:323}", "${RPKI_RTR_PROTOCOL_VERSION:-2}", "reset", "--keep-after-error", "--summary-only"]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../logs/client:/app/logs
|
- ../../logs/client:/app/logs
|
||||||
restart: no
|
restart: no
|
||||||
|
|||||||
36
deploy/client/docker-compose.ssh.password.yml
Normal file
36
deploy/client/docker-compose.ssh.password.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
rtr-debug-client:
|
||||||
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: deploy/client/Dockerfile
|
||||||
|
image: rpki-rtr-debug-client:latest
|
||||||
|
command:
|
||||||
|
[
|
||||||
|
"${RPKI_RTR_SERVER_ADDR:-rpki-rtr-ssh:22}",
|
||||||
|
"${RPKI_RTR_PROTOCOL_VERSION:-2}",
|
||||||
|
"reset",
|
||||||
|
"--ssh",
|
||||||
|
"--ssh-user",
|
||||||
|
"${RPKI_RTR_SSH_USERNAME:-rpki-rtr}",
|
||||||
|
"--ssh-password",
|
||||||
|
"${RPKI_RTR_SSH_PASSWORD}",
|
||||||
|
"--ssh-server-key",
|
||||||
|
"${RPKI_RTR_SSH_SERVER_PUBKEY_PATH:-/app/certs/ssh_host_rsa_key.pub}",
|
||||||
|
"--keep-after-error",
|
||||||
|
"--summary-only"
|
||||||
|
]
|
||||||
|
volumes:
|
||||||
|
- ${RPKI_RTR_CLIENT_KEYS_VOLUME:-../../certs:/app/certs:ro}
|
||||||
|
- ../../logs/client:/app/logs
|
||||||
|
restart: no
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
networks:
|
||||||
|
- rpki_net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
rpki_net:
|
||||||
|
name: rpki_net
|
||||||
|
driver: bridge
|
||||||
@ -8,21 +8,21 @@ services:
|
|||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command:
|
command:
|
||||||
[
|
[
|
||||||
"rpki-rtr-ssh:${RPKI_RTR_SSH_PORT:-22}",
|
"${RPKI_RTR_SERVER_ADDR:-rpki-rtr-ssh:22}",
|
||||||
"2",
|
"${RPKI_RTR_PROTOCOL_VERSION:-2}",
|
||||||
"reset",
|
"reset",
|
||||||
"--ssh",
|
"--ssh",
|
||||||
"--ssh-user",
|
"--ssh-user",
|
||||||
"rpki-rtr",
|
"${RPKI_RTR_SSH_USERNAME:-rpki-rtr}",
|
||||||
"--ssh-key",
|
"--ssh-key",
|
||||||
"/app/certs/rtr-client.key",
|
"${RPKI_RTR_CLIENT_KEY_PATH:-/app/certs/rtr-client.key}",
|
||||||
"--ssh-server-key",
|
"--ssh-server-key",
|
||||||
"/app/certs/ssh_host_rsa_key.pub",
|
"${RPKI_RTR_SSH_SERVER_PUBKEY_PATH:-/app/certs/ssh_host_rsa_key.pub}",
|
||||||
"--keep-after-error",
|
"--keep-after-error",
|
||||||
"--summary-only"
|
"--summary-only"
|
||||||
]
|
]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../certs:/app/certs:ro
|
- ${RPKI_RTR_CLIENT_KEYS_VOLUME:-../../certs:/app/certs:ro}
|
||||||
- ../../logs/client:/app/logs
|
- ../../logs/client:/app/logs
|
||||||
restart: no
|
restart: no
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
|
|||||||
@ -4,7 +4,7 @@ services:
|
|||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: deploy/client/Dockerfile
|
dockerfile: deploy/client/Dockerfile
|
||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command: ["rpki-rtr-tcp:323", "2", "reset", "--keep-after-error", "--summary-only"]
|
command: ["${RPKI_RTR_SERVER_ADDR:-rpki-rtr-tcp:323}", "${RPKI_RTR_PROTOCOL_VERSION:-2}", "reset", "--keep-after-error", "--summary-only"]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../logs/client:/app/logs
|
- ../../logs/client:/app/logs
|
||||||
restart: no
|
restart: no
|
||||||
|
|||||||
@ -8,14 +8,14 @@ services:
|
|||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command:
|
command:
|
||||||
[
|
[
|
||||||
"rpki-rtr-tls:324",
|
"${RPKI_RTR_SERVER_ADDR:-rpki-rtr-tls:324}",
|
||||||
"2",
|
"${RPKI_RTR_PROTOCOL_VERSION:-2}",
|
||||||
"reset",
|
"reset",
|
||||||
"--tls",
|
"--tls",
|
||||||
"--ca-cert",
|
"--ca-cert",
|
||||||
"/app/certs/client-ca.crt",
|
"/app/certs/client-ca.crt",
|
||||||
"--server-name",
|
"--server-name",
|
||||||
"localhost",
|
"${RPKI_RTR_TLS_SERVER_NAME:-localhost}",
|
||||||
"--client-cert",
|
"--client-cert",
|
||||||
"/app/certs/client-good.crt",
|
"/app/certs/client-good.crt",
|
||||||
"--client-key",
|
"--client-key",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ services:
|
|||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: deploy/client/Dockerfile
|
dockerfile: deploy/client/Dockerfile
|
||||||
image: rpki-rtr-debug-client:latest
|
image: rpki-rtr-debug-client:latest
|
||||||
command: ["rpki-rtr-tcp:323", "2", "reset", "--keep-after-error", "--summary-only"]
|
command: ["${RPKI_RTR_SERVER_ADDR:-rpki-rtr-tcp:323}", "${RPKI_RTR_PROTOCOL_VERSION:-2}", "reset", "--keep-after-error", "--summary-only"]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../logs/client:/app/logs
|
- ../../logs/client:/app/logs
|
||||||
restart: no
|
restart: no
|
||||||
|
|||||||
8
deploy/server/.env
Normal file
8
deploy/server/.env
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Host directory containing CCR files to mount into the server container.
|
||||||
|
RPKI_RTR_CCR_HOST_DIR=../../data
|
||||||
|
|
||||||
|
# In-container directory used by rpki_rtr as CCR input directory.
|
||||||
|
RPKI_RTR_CCR_DIR=/app/data
|
||||||
|
|
||||||
|
# Max retained delta count in RTR cache.
|
||||||
|
RPKI_RTR_MAX_DELTA=10
|
||||||
@ -32,7 +32,7 @@ RUN apt-get update \
|
|||||||
COPY Cargo.toml Cargo.lock ./
|
COPY Cargo.toml Cargo.lock ./
|
||||||
COPY src ./src
|
COPY src ./src
|
||||||
|
|
||||||
RUN cargo build --release --bin rpki
|
RUN cargo build --release --bin rpki_rtr
|
||||||
|
|
||||||
FROM debian:bookworm-slim AS runtime
|
FROM debian:bookworm-slim AS runtime
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=builder /build/target/release/rpki /usr/local/bin/rpki
|
COPY --from=builder /build/target/release/rpki_rtr /usr/local/bin/rpki_rtr
|
||||||
COPY --chmod=755 deploy/server/entrypoint.sh /usr/local/bin/rpki-rtr-entrypoint.sh
|
COPY --chmod=755 deploy/server/entrypoint.sh /usr/local/bin/rpki-rtr-entrypoint.sh
|
||||||
|
|
||||||
RUN mkdir -p /app/data /app/rtr-db /app/certs /app/slurm /app/logs
|
RUN mkdir -p /app/data /app/rtr-db /app/certs /app/slurm /app/logs
|
||||||
|
|||||||
@ -10,29 +10,33 @@ services:
|
|||||||
restart: no
|
restart: no
|
||||||
ports:
|
ports:
|
||||||
- "323:323"
|
- "323:323"
|
||||||
- "${RPKI_RTR_SSH_HOST_PORT:-2222}:22"
|
- "${RPKI_RTR_SSH_HOST_PORT:-2222}:${RPKI_RTR_SSH_CONTAINER_PORT:-22}"
|
||||||
environment:
|
environment:
|
||||||
RPKI_RTR_ENABLE_TLS: "false"
|
RPKI_RTR_ENABLE_TLS: "false"
|
||||||
RPKI_RTR_ENABLE_SSH: "true"
|
RPKI_RTR_ENABLE_SSH: "true"
|
||||||
RPKI_RTR_TCP_ADDR: "0.0.0.0:323"
|
RPKI_RTR_TCP_ADDR: "0.0.0.0:323"
|
||||||
RPKI_RTR_SSH_ADDR: "0.0.0.0:22"
|
RPKI_RTR_SSH_ADDR: "0.0.0.0:${RPKI_RTR_SSH_CONTAINER_PORT:-22}"
|
||||||
RPKI_RTR_SSH_HOST_KEY_PATH: "/app/certs/ssh_host_rsa_key"
|
RPKI_RTR_SSH_HOST_KEY_PATH: "${RPKI_RTR_SSH_HOST_KEY_PATH:-/host-ssh/ssh_host_ed25519_key}"
|
||||||
RPKI_RTR_SSH_AUTHORIZED_KEYS_PATH: "/app/certs/rtr-authorized_keys"
|
RPKI_RTR_SSH_AUTHORIZED_KEYS_PATH: "${RPKI_RTR_SSH_AUTHORIZED_KEYS_PATH:-/app/certs/rtr-authorized_keys}"
|
||||||
RPKI_RTR_SSH_USERNAME: "rpki-rtr"
|
RPKI_RTR_SSH_USERNAME: "${RPKI_RTR_SSH_USERNAME:-rpki-rtr}"
|
||||||
RPKI_RTR_SSH_SUBSYSTEM_NAME: "rpki-rtr"
|
RPKI_RTR_SSH_SUBSYSTEM_NAME: "${RPKI_RTR_SSH_SUBSYSTEM_NAME:-rpki-rtr}"
|
||||||
|
# SSH auth mode: key | password | both
|
||||||
|
RPKI_RTR_SSH_AUTH_MODE: "${RPKI_RTR_SSH_AUTH_MODE:-key}"
|
||||||
# Optional: enable password authentication in addition to publickey
|
# Optional: enable password authentication in addition to publickey
|
||||||
# RPKI_RTR_SSH_PASSWORD: "test-password"
|
# RPKI_RTR_SSH_PASSWORD: "test-password"
|
||||||
RPKI_RTR_DB_PATH: "/app/rtr-db"
|
RPKI_RTR_DB_PATH: "/app/rtr-db"
|
||||||
RPKI_RTR_CCR_DIR: "/app/data"
|
RPKI_RTR_CCR_DIR: "${RPKI_RTR_CCR_DIR:-/app/data}"
|
||||||
RPKI_RTR_SLURM_DIR: "/app/slurm"
|
RPKI_RTR_SLURM_DIR: "/app/slurm"
|
||||||
RPKI_RTR_STRICT_CCR_VALIDATION: "false"
|
RPKI_RTR_STRICT_CCR_VALIDATION: "false"
|
||||||
RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "300"
|
RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "300"
|
||||||
|
RPKI_RTR_MAX_DELTA: "${RPKI_RTR_MAX_DELTA:-10}"
|
||||||
RPKI_RTR_MAX_CONCURRENT_HANDSHAKES: "128"
|
RPKI_RTR_MAX_CONCURRENT_HANDSHAKES: "128"
|
||||||
RUST_LOG: "info"
|
RUST_LOG: "info"
|
||||||
volumes:
|
volumes:
|
||||||
- ../../data:/app/data:ro
|
- ${RPKI_RTR_CCR_HOST_DIR:-../../data}:${RPKI_RTR_CCR_DIR:-/app/data}:ro
|
||||||
- ../../rtr-db:/app/rtr-db
|
- ../../rtr-db:/app/rtr-db
|
||||||
- ../../data:/app/slurm:ro
|
- ../../data:/app/slurm:ro
|
||||||
|
- ${RPKI_RTR_SSH_KEYS_VOLUME:-/etc/ssh:/host-ssh:ro}
|
||||||
- ../../certs:/app/certs:ro
|
- ../../certs:/app/certs:ro
|
||||||
- ../../logs/server:/app/logs
|
- ../../logs/server:/app/logs
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@ -15,15 +15,16 @@ services:
|
|||||||
RPKI_RTR_ENABLE_SSH: "false"
|
RPKI_RTR_ENABLE_SSH: "false"
|
||||||
RPKI_RTR_TCP_ADDR: "0.0.0.0:323"
|
RPKI_RTR_TCP_ADDR: "0.0.0.0:323"
|
||||||
RPKI_RTR_DB_PATH: "/app/rtr-db"
|
RPKI_RTR_DB_PATH: "/app/rtr-db"
|
||||||
RPKI_RTR_CCR_DIR: "/app/data"
|
RPKI_RTR_CCR_DIR: "${RPKI_RTR_CCR_DIR:-/app/data}"
|
||||||
RPKI_RTR_SLURM_DIR: "/app/slurm"
|
RPKI_RTR_SLURM_DIR: "/app/slurm"
|
||||||
RPKI_RTR_STRICT_CCR_VALIDATION: "false"
|
RPKI_RTR_STRICT_CCR_VALIDATION: "false"
|
||||||
RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "60"
|
RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "60"
|
||||||
|
RPKI_RTR_MAX_DELTA: "${RPKI_RTR_MAX_DELTA:-10}"
|
||||||
RPKI_RTR_MAX_CONNECTIONS: "100000"
|
RPKI_RTR_MAX_CONNECTIONS: "100000"
|
||||||
RPKI_RTR_MAX_CONCURRENT_HANDSHAKES: "128"
|
RPKI_RTR_MAX_CONCURRENT_HANDSHAKES: "128"
|
||||||
RUST_LOG: "info"
|
RUST_LOG: "info"
|
||||||
volumes:
|
volumes:
|
||||||
- ../../data:/app/data:ro
|
- ${RPKI_RTR_CCR_HOST_DIR:-../../data}:${RPKI_RTR_CCR_DIR:-/app/data}:ro
|
||||||
- ../../rtr-db:/app/rtr-db
|
- ../../rtr-db:/app/rtr-db
|
||||||
- ../../data:/app/slurm:ro
|
- ../../data:/app/slurm:ro
|
||||||
- ../../logs/server:/app/logs
|
- ../../logs/server:/app/logs
|
||||||
|
|||||||
@ -21,14 +21,15 @@ services:
|
|||||||
RPKI_RTR_TLS_CLIENT_CA_PATH: "/app/certs/client-ca.crt"
|
RPKI_RTR_TLS_CLIENT_CA_PATH: "/app/certs/client-ca.crt"
|
||||||
RPKI_RTR_ENFORCE_TLS_CLIENT_SAN_IP_MATCH: "false"
|
RPKI_RTR_ENFORCE_TLS_CLIENT_SAN_IP_MATCH: "false"
|
||||||
RPKI_RTR_DB_PATH: "/app/rtr-db"
|
RPKI_RTR_DB_PATH: "/app/rtr-db"
|
||||||
RPKI_RTR_CCR_DIR: "/app/data"
|
RPKI_RTR_CCR_DIR: "${RPKI_RTR_CCR_DIR:-/app/data}"
|
||||||
RPKI_RTR_SLURM_DIR: "/app/slurm"
|
RPKI_RTR_SLURM_DIR: "/app/slurm"
|
||||||
RPKI_RTR_STRICT_CCR_VALIDATION: "false"
|
RPKI_RTR_STRICT_CCR_VALIDATION: "false"
|
||||||
RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "300"
|
RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "300"
|
||||||
|
RPKI_RTR_MAX_DELTA: "${RPKI_RTR_MAX_DELTA:-10}"
|
||||||
RPKI_RTR_MAX_CONCURRENT_HANDSHAKES: "128"
|
RPKI_RTR_MAX_CONCURRENT_HANDSHAKES: "128"
|
||||||
RUST_LOG: "info"
|
RUST_LOG: "info"
|
||||||
volumes:
|
volumes:
|
||||||
- ../../data:/app/data:ro
|
- ${RPKI_RTR_CCR_HOST_DIR:-../../data}:${RPKI_RTR_CCR_DIR:-/app/data}:ro
|
||||||
- ../../rtr-db:/app/rtr-db
|
- ../../rtr-db:/app/rtr-db
|
||||||
- ../../data:/app/slurm:ro
|
- ../../data:/app/slurm:ro
|
||||||
- ../../tests/fixtures/tls:/app/certs:ro
|
- ../../tests/fixtures/tls:/app/certs:ro
|
||||||
|
|||||||
@ -18,10 +18,11 @@ services:
|
|||||||
RPKI_RTR_TCP_ADDR: "0.0.0.0:323"
|
RPKI_RTR_TCP_ADDR: "0.0.0.0:323"
|
||||||
RPKI_RTR_TLS_ADDR: "0.0.0.0:324"
|
RPKI_RTR_TLS_ADDR: "0.0.0.0:324"
|
||||||
RPKI_RTR_DB_PATH: "/app/rtr-db"
|
RPKI_RTR_DB_PATH: "/app/rtr-db"
|
||||||
RPKI_RTR_CCR_DIR: "/app/data"
|
RPKI_RTR_CCR_DIR: "${RPKI_RTR_CCR_DIR:-/app/data}"
|
||||||
RPKI_RTR_SLURM_DIR: "/app/slurm"
|
RPKI_RTR_SLURM_DIR: "/app/slurm"
|
||||||
RPKI_RTR_STRICT_CCR_VALIDATION: "false"
|
RPKI_RTR_STRICT_CCR_VALIDATION: "false"
|
||||||
RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "300"
|
RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "300"
|
||||||
|
RPKI_RTR_MAX_DELTA: "${RPKI_RTR_MAX_DELTA:-10}"
|
||||||
RPKI_RTR_MAX_CONCURRENT_HANDSHAKES: "128"
|
RPKI_RTR_MAX_CONCURRENT_HANDSHAKES: "128"
|
||||||
RUST_LOG: "info"
|
RUST_LOG: "info"
|
||||||
# SSH mode example:
|
# SSH mode example:
|
||||||
@ -35,7 +36,7 @@ services:
|
|||||||
# Optional: enable password auth in addition to publickey
|
# Optional: enable password auth in addition to publickey
|
||||||
# RPKI_RTR_SSH_PASSWORD: "test-password"
|
# RPKI_RTR_SSH_PASSWORD: "test-password"
|
||||||
volumes:
|
volumes:
|
||||||
- ../../data:/app/data:ro
|
- ${RPKI_RTR_CCR_HOST_DIR:-../../data}:${RPKI_RTR_CCR_DIR:-/app/data}:ro
|
||||||
- ../../rtr-db:/app/rtr-db
|
- ../../rtr-db:/app/rtr-db
|
||||||
- ../../data:/app/slurm:ro
|
- ../../data:/app/slurm:ro
|
||||||
- ../../logs/server:/app/logs
|
- ../../logs/server:/app/logs
|
||||||
|
|||||||
@ -7,4 +7,4 @@ log_name="${HOSTNAME:-rpki-rtr}"
|
|||||||
stdout_log="/app/logs/${log_name}.stdout.log"
|
stdout_log="/app/logs/${log_name}.stdout.log"
|
||||||
stderr_log="/app/logs/${log_name}.stderr.log"
|
stderr_log="/app/logs/${log_name}.stderr.log"
|
||||||
|
|
||||||
exec /usr/local/bin/rpki "$@" >>"$stdout_log" 2>>"$stderr_log"
|
exec /usr/local/bin/rpki_rtr "$@" >>"$stdout_log" 2>>"$stderr_log"
|
||||||
|
|||||||
@ -148,3 +148,24 @@ SSH 参数:
|
|||||||
- `keep-after-error`
|
- `keep-after-error`
|
||||||
- `output` / `output verbose` / `output summary`
|
- `output` / `output verbose` / `output summary`
|
||||||
- `quit`
|
- `quit`
|
||||||
|
|
||||||
|
## SSH Password Auth (Added)
|
||||||
|
|
||||||
|
`rtr_debug_client` now supports password auth in SSH mode.
|
||||||
|
|
||||||
|
- Use exactly one auth option in SSH mode:
|
||||||
|
- `--ssh-key <path>`
|
||||||
|
- `--ssh-password <value>`
|
||||||
|
- Host key verification is still required:
|
||||||
|
- `--ssh-known-hosts <path>` or `--ssh-server-key <path>`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo run --bin rtr_debug_client -- \
|
||||||
|
127.0.0.1:22 1 reset \
|
||||||
|
--ssh \
|
||||||
|
--ssh-user rpki-rtr \
|
||||||
|
--ssh-password 'your-password' \
|
||||||
|
--ssh-server-key certs/ssh_host_rsa_key.pub
|
||||||
|
```
|
||||||
|
|||||||
@ -1001,6 +1001,15 @@ impl Config {
|
|||||||
})?;
|
})?;
|
||||||
ensure_ssh_config(&mut transport)?.private_key = Some(PathBuf::from(path));
|
ensure_ssh_config(&mut transport)?.private_key = Some(PathBuf::from(path));
|
||||||
}
|
}
|
||||||
|
"--ssh-password" => {
|
||||||
|
let password = args.next().ok_or_else(|| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"--ssh-password requires a value",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
ensure_ssh_config(&mut transport)?.password = Some(password);
|
||||||
|
}
|
||||||
"--ssh-subsystem" => {
|
"--ssh-subsystem" => {
|
||||||
let subsystem = args.next().ok_or_else(|| {
|
let subsystem = args.next().ok_or_else(|| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
@ -1181,8 +1190,15 @@ impl TransportConfig {
|
|||||||
.unwrap_or_else(|| "<none>".to_string())
|
.unwrap_or_else(|| "<none>".to_string())
|
||||||
),
|
),
|
||||||
Self::Ssh(cfg) => format!(
|
Self::Ssh(cfg) => format!(
|
||||||
"ssh (user={}, subsystem={}, host_key_check={})",
|
"ssh (user={}, auth={}, subsystem={}, host_key_check={})",
|
||||||
cfg.user.as_deref().unwrap_or("<unset>"),
|
cfg.user.as_deref().unwrap_or("<unset>"),
|
||||||
|
if cfg.private_key.is_some() {
|
||||||
|
"publickey"
|
||||||
|
} else if cfg.password.is_some() {
|
||||||
|
"password"
|
||||||
|
} else {
|
||||||
|
"<unset>"
|
||||||
|
},
|
||||||
cfg.subsystem
|
cfg.subsystem
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or(DEFAULT_SSH_SUBSYSTEM_NAME),
|
.unwrap_or(DEFAULT_SSH_SUBSYSTEM_NAME),
|
||||||
@ -1222,6 +1238,7 @@ impl HostKeyVerification {
|
|||||||
struct SshConfig {
|
struct SshConfig {
|
||||||
user: Option<String>,
|
user: Option<String>,
|
||||||
private_key: Option<PathBuf>,
|
private_key: Option<PathBuf>,
|
||||||
|
password: Option<String>,
|
||||||
subsystem: Option<String>,
|
subsystem: Option<String>,
|
||||||
known_hosts: Option<PathBuf>,
|
known_hosts: Option<PathBuf>,
|
||||||
server_key: Option<PathBuf>,
|
server_key: Option<PathBuf>,
|
||||||
@ -1315,12 +1332,28 @@ fn finalize_transport(transport: TransportConfig, addr: &str) -> io::Result<Tran
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let private_key = cfg.private_key.take().ok_or_else(|| {
|
let private_key = cfg.private_key.take();
|
||||||
io::Error::new(
|
let password = cfg.password.take().and_then(|value| {
|
||||||
|
let trimmed = value.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(trimmed.to_string())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if private_key.is_some() && password.is_some() {
|
||||||
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::InvalidInput,
|
io::ErrorKind::InvalidInput,
|
||||||
"SSH mode requires --ssh-key <path>",
|
"SSH mode authentication must choose one: --ssh-key <path> or --ssh-password <value>",
|
||||||
)
|
));
|
||||||
})?;
|
}
|
||||||
|
if private_key.is_none() && password.is_none() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"SSH mode requires authentication: --ssh-key <path> or --ssh-password <value>",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if cfg.known_hosts.is_some() && cfg.server_key.is_some() {
|
if cfg.known_hosts.is_some() && cfg.server_key.is_some() {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
@ -1356,7 +1389,8 @@ fn finalize_transport(transport: TransportConfig, addr: &str) -> io::Result<Tran
|
|||||||
|
|
||||||
Ok(TransportConfig::Ssh(SshConfig {
|
Ok(TransportConfig::Ssh(SshConfig {
|
||||||
user: Some(user),
|
user: Some(user),
|
||||||
private_key: Some(private_key),
|
private_key,
|
||||||
|
password,
|
||||||
subsystem: Some(subsystem),
|
subsystem: Some(subsystem),
|
||||||
known_hosts: None,
|
known_hosts: None,
|
||||||
server_key: None,
|
server_key: None,
|
||||||
@ -1439,10 +1473,24 @@ async fn connect_ssh_stream(addr: &str, ssh: &SshConfig) -> io::Result<DynStream
|
|||||||
.user
|
.user
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "missing SSH user"))?;
|
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "missing SSH user"))?;
|
||||||
let private_key_path = ssh
|
let private_key_path = ssh.private_key.as_ref();
|
||||||
.private_key
|
let password = ssh
|
||||||
.as_ref()
|
.password
|
||||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "missing SSH private key"))?;
|
.as_deref()
|
||||||
|
.map(str::trim)
|
||||||
|
.filter(|value| !value.is_empty());
|
||||||
|
if private_key_path.is_some() && password.is_some() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"SSH auth config invalid: both private key and password provided",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if private_key_path.is_none() && password.is_none() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidInput,
|
||||||
|
"SSH auth config invalid: neither private key nor password provided",
|
||||||
|
));
|
||||||
|
}
|
||||||
let subsystem = ssh
|
let subsystem = ssh
|
||||||
.subsystem
|
.subsystem
|
||||||
.as_deref()
|
.as_deref()
|
||||||
@ -1471,38 +1519,53 @@ async fn connect_ssh_stream(addr: &str, ssh: &SshConfig) -> io::Result<DynStream
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let private_key = load_secret_key(private_key_path, None).map_err(|err| {
|
let auth_result = if let Some(private_key_path) = private_key_path {
|
||||||
io::Error::new(
|
let private_key = load_secret_key(private_key_path, None).map_err(|err| {
|
||||||
io::ErrorKind::InvalidInput,
|
|
||||||
format!(
|
|
||||||
"failed to load SSH private key {}: {}",
|
|
||||||
private_key_path.display(),
|
|
||||||
err
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let rsa_hash = session.best_supported_rsa_hash().await.map_err(|err| {
|
|
||||||
io::Error::new(
|
|
||||||
io::ErrorKind::ConnectionAborted,
|
|
||||||
format!("failed to negotiate SSH RSA hash: {}", err),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let auth_result = session
|
|
||||||
.authenticate_publickey(
|
|
||||||
user.to_string(),
|
|
||||||
PrivateKeyWithHashAlg::new(Arc::new(private_key), rsa_hash.flatten()),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|err| {
|
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::PermissionDenied,
|
io::ErrorKind::InvalidInput,
|
||||||
format!("SSH publickey authentication failed: {}", err),
|
format!(
|
||||||
|
"failed to load SSH private key {}: {}",
|
||||||
|
private_key_path.display(),
|
||||||
|
err
|
||||||
|
),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
let rsa_hash = session.best_supported_rsa_hash().await.map_err(|err| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::ConnectionAborted,
|
||||||
|
format!("failed to negotiate SSH RSA hash: {}", err),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
session
|
||||||
|
.authenticate_publickey(
|
||||||
|
user.to_string(),
|
||||||
|
PrivateKeyWithHashAlg::new(Arc::new(private_key), rsa_hash.flatten()),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::PermissionDenied,
|
||||||
|
format!("SSH publickey authentication failed: {}", err),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
} else {
|
||||||
|
session
|
||||||
|
.authenticate_password(
|
||||||
|
user.to_string(),
|
||||||
|
password.expect("password checked above").to_string(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::PermissionDenied,
|
||||||
|
format!("SSH password authentication failed: {}", err),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
};
|
||||||
if !auth_result.success() {
|
if !auth_result.success() {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::PermissionDenied,
|
io::ErrorKind::PermissionDenied,
|
||||||
"SSH publickey authentication rejected by server",
|
"SSH authentication rejected by server",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use tracing::{info, warn};
|
|||||||
|
|
||||||
use rpki::rtr::cache::{RtrCache, SharedRtrCache};
|
use rpki::rtr::cache::{RtrCache, SharedRtrCache};
|
||||||
use rpki::rtr::payload::Timing;
|
use rpki::rtr::payload::Timing;
|
||||||
|
use rpki::rtr::server::ssh::SshAuthMode;
|
||||||
use rpki::rtr::server::{RtrNotifier, RtrService, RtrServiceConfig, RunningRtrService};
|
use rpki::rtr::server::{RtrNotifier, RtrService, RtrServiceConfig, RunningRtrService};
|
||||||
use rpki::rtr::store::RtrStore;
|
use rpki::rtr::store::RtrStore;
|
||||||
use rpki::source::pipeline::{PayloadLoadConfig, load_payloads_from_latest_sources};
|
use rpki::source::pipeline::{PayloadLoadConfig, load_payloads_from_latest_sources};
|
||||||
@ -33,6 +34,7 @@ struct AppConfig {
|
|||||||
ssh_authorized_keys_path: String,
|
ssh_authorized_keys_path: String,
|
||||||
ssh_username: String,
|
ssh_username: String,
|
||||||
ssh_subsystem_name: String,
|
ssh_subsystem_name: String,
|
||||||
|
ssh_auth_mode: SshAuthMode,
|
||||||
ssh_password: Option<String>,
|
ssh_password: Option<String>,
|
||||||
|
|
||||||
max_delta: u8,
|
max_delta: u8,
|
||||||
@ -63,6 +65,7 @@ impl Default for AppConfig {
|
|||||||
ssh_authorized_keys_path: "./certs/rtr-authorized_keys".to_string(),
|
ssh_authorized_keys_path: "./certs/rtr-authorized_keys".to_string(),
|
||||||
ssh_username: "rpki-rtr".to_string(),
|
ssh_username: "rpki-rtr".to_string(),
|
||||||
ssh_subsystem_name: "rpki-rtr".to_string(),
|
ssh_subsystem_name: "rpki-rtr".to_string(),
|
||||||
|
ssh_auth_mode: SshAuthMode::Key,
|
||||||
ssh_password: None,
|
ssh_password: None,
|
||||||
|
|
||||||
max_delta: 100,
|
max_delta: 100,
|
||||||
@ -153,6 +156,14 @@ impl AppConfig {
|
|||||||
if let Some(value) = env_var("RPKI_RTR_SSH_SUBSYSTEM_NAME")? {
|
if let Some(value) = env_var("RPKI_RTR_SSH_SUBSYSTEM_NAME")? {
|
||||||
config.ssh_subsystem_name = value;
|
config.ssh_subsystem_name = value;
|
||||||
}
|
}
|
||||||
|
if let Some(value) = env_var("RPKI_RTR_SSH_AUTH_MODE")? {
|
||||||
|
config.ssh_auth_mode = SshAuthMode::parse(&value).ok_or_else(|| {
|
||||||
|
anyhow!(
|
||||||
|
"invalid RPKI_RTR_SSH_AUTH_MODE '{}': expected key|password|both",
|
||||||
|
value
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
if let Some(value) = env_var("RPKI_RTR_SSH_PASSWORD")? {
|
if let Some(value) = env_var("RPKI_RTR_SSH_PASSWORD")? {
|
||||||
let value = value.trim().to_string();
|
let value = value.trim().to_string();
|
||||||
config.ssh_password = if value.is_empty() { None } else { Some(value) };
|
config.ssh_password = if value.is_empty() { None } else { Some(value) };
|
||||||
@ -368,6 +379,7 @@ fn start_servers(config: &AppConfig, service: &RtrService) -> RunningRtrService
|
|||||||
&config.ssh_authorized_keys_path,
|
&config.ssh_authorized_keys_path,
|
||||||
&config.ssh_username,
|
&config.ssh_username,
|
||||||
&config.ssh_subsystem_name,
|
&config.ssh_subsystem_name,
|
||||||
|
config.ssh_auth_mode,
|
||||||
config.ssh_password.as_deref(),
|
config.ssh_password.as_deref(),
|
||||||
)
|
)
|
||||||
} else if config.enable_tls {
|
} else if config.enable_tls {
|
||||||
@ -388,6 +400,7 @@ fn start_servers(config: &AppConfig, service: &RtrService) -> RunningRtrService
|
|||||||
&config.ssh_authorized_keys_path,
|
&config.ssh_authorized_keys_path,
|
||||||
&config.ssh_username,
|
&config.ssh_username,
|
||||||
&config.ssh_subsystem_name,
|
&config.ssh_subsystem_name,
|
||||||
|
config.ssh_auth_mode,
|
||||||
config.ssh_password.as_deref(),
|
config.ssh_password.as_deref(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -505,6 +518,7 @@ fn log_startup_config(config: &AppConfig) {
|
|||||||
);
|
);
|
||||||
info!("ssh_username={}", config.ssh_username);
|
info!("ssh_username={}", config.ssh_username);
|
||||||
info!("ssh_subsystem_name={}", config.ssh_subsystem_name);
|
info!("ssh_subsystem_name={}", config.ssh_subsystem_name);
|
||||||
|
info!("ssh_auth_mode={}", config.ssh_auth_mode.as_str());
|
||||||
info!("ssh_password_enabled={}", config.ssh_password.is_some());
|
info!("ssh_password_enabled={}", config.ssh_password.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
38
src/rtr/cache/core.rs
vendored
38
src/rtr/cache/core.rs
vendored
@ -65,7 +65,7 @@ pub struct VersionState {
|
|||||||
|
|
||||||
impl VersionState {
|
impl VersionState {
|
||||||
fn new(session_id: u16, serial: u32, snapshot: Snapshot, max_delta: u8) -> Self {
|
fn new(session_id: u16, serial: u32, snapshot: Snapshot, max_delta: u8) -> Self {
|
||||||
let rtr_payloads = Arc::new(snapshot.payloads_for_rtr());
|
let rtr_payloads = snapshot.rtr_payloads_for_rtr_arc();
|
||||||
Self {
|
Self {
|
||||||
session_id,
|
session_id,
|
||||||
serial,
|
serial,
|
||||||
@ -199,7 +199,7 @@ impl RtrCacheBuilder {
|
|||||||
VersionState {
|
VersionState {
|
||||||
session_id: session_ids.as_array()[idx],
|
session_id: session_ids.as_array()[idx],
|
||||||
serial: serials[idx],
|
serial: serials[idx],
|
||||||
rtr_payloads: Arc::new(snapshot.payloads_for_rtr()),
|
rtr_payloads: snapshot.rtr_payloads_for_rtr_arc(),
|
||||||
snapshot: Arc::new(snapshot),
|
snapshot: Arc::new(snapshot),
|
||||||
deltas: deltas[idx].clone(),
|
deltas: deltas[idx].clone(),
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ impl RtrCache {
|
|||||||
self.availability = CacheAvailability::NoDataAvailable;
|
self.availability = CacheAvailability::NoDataAvailable;
|
||||||
for version_state in &mut self.versions {
|
for version_state in &mut self.versions {
|
||||||
version_state.snapshot = Arc::new(Snapshot::empty());
|
version_state.snapshot = Arc::new(Snapshot::empty());
|
||||||
version_state.rtr_payloads = Arc::new(Vec::new());
|
version_state.rtr_payloads = version_state.snapshot.rtr_payloads_for_rtr_arc();
|
||||||
version_state.deltas.clear();
|
version_state.deltas.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,7 +247,7 @@ impl RtrCache {
|
|||||||
state.session_id = new_session_ids.get(v);
|
state.session_id = new_session_ids.get(v);
|
||||||
state.serial = 1;
|
state.serial = 1;
|
||||||
state.snapshot = Arc::new(project_snapshot_for_version(source_snapshot, v));
|
state.snapshot = Arc::new(project_snapshot_for_version(source_snapshot, v));
|
||||||
state.rtr_payloads = Arc::new(state.snapshot.as_ref().payloads_for_rtr());
|
state.rtr_payloads = state.snapshot.rtr_payloads_for_rtr_arc();
|
||||||
state.deltas.clear();
|
state.deltas.clear();
|
||||||
}
|
}
|
||||||
self.last_update_end = DualTime::now();
|
self.last_update_end = DualTime::now();
|
||||||
@ -362,7 +362,7 @@ impl RtrCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state.snapshot = Arc::new(projected);
|
state.snapshot = Arc::new(projected);
|
||||||
state.rtr_payloads = Arc::new(state.snapshot.as_ref().payloads_for_rtr());
|
state.rtr_payloads = state.snapshot.rtr_payloads_for_rtr_arc();
|
||||||
Self::push_delta(
|
Self::push_delta(
|
||||||
state,
|
state,
|
||||||
self.max_delta,
|
self.max_delta,
|
||||||
@ -578,33 +578,7 @@ fn merge_deltas_minimally(current_serial: u32, deltas: &[Arc<Delta>]) -> Delta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn project_snapshot_for_version(snapshot: &Snapshot, version: u8) -> Snapshot {
|
fn project_snapshot_for_version(snapshot: &Snapshot, version: u8) -> Snapshot {
|
||||||
let mut payloads = Vec::new();
|
snapshot.project_for_version(version)
|
||||||
for payload in snapshot.payloads() {
|
|
||||||
if let Some(projected) = project_payload_for_version(&payload, version) {
|
|
||||||
payloads.push(projected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Snapshot::from_payloads(payloads)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn project_payload_for_version(payload: &Payload, version: u8) -> Option<Payload> {
|
|
||||||
match payload {
|
|
||||||
Payload::RouteOrigin(origin) => Some(Payload::RouteOrigin(origin.clone())),
|
|
||||||
Payload::RouterKey(key) => {
|
|
||||||
if version >= 1 {
|
|
||||||
Some(Payload::RouterKey(key.clone()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Payload::Aspa(aspa) => {
|
|
||||||
if version >= 2 {
|
|
||||||
Some(Payload::Aspa(aspa.clone()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn estimate_snapshot_payload_wire_size(snapshot: &Snapshot) -> usize {
|
fn estimate_snapshot_payload_wire_size(snapshot: &Snapshot) -> usize {
|
||||||
|
|||||||
157
src/rtr/cache/model.rs
vendored
157
src/rtr/cache/model.rs
vendored
@ -1,4 +1,4 @@
|
|||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::BTreeMap;
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
@ -69,9 +69,9 @@ impl<'de> Deserialize<'de> for DualTime {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Snapshot {
|
pub struct Snapshot {
|
||||||
origins: BTreeSet<RouteOrigin>,
|
origins: Arc<Vec<RouteOrigin>>,
|
||||||
router_keys: BTreeSet<RouterKey>,
|
router_keys: Arc<Vec<RouterKey>>,
|
||||||
aspas: BTreeSet<Aspa>,
|
aspas: Arc<Vec<Aspa>>,
|
||||||
created_at: DualTime,
|
created_at: DualTime,
|
||||||
origins_hash: [u8; 32],
|
origins_hash: [u8; 32],
|
||||||
router_keys_hash: [u8; 32],
|
router_keys_hash: [u8; 32],
|
||||||
@ -83,14 +83,26 @@ pub struct Snapshot {
|
|||||||
|
|
||||||
impl Snapshot {
|
impl Snapshot {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
origins: BTreeSet<RouteOrigin>,
|
origins: Vec<RouteOrigin>,
|
||||||
router_keys: BTreeSet<RouterKey>,
|
router_keys: Vec<RouterKey>,
|
||||||
aspas: BTreeSet<Aspa>,
|
aspas: Vec<Aspa>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from_shared_parts(
|
||||||
|
Arc::new(sorted_dedup(origins)),
|
||||||
|
Arc::new(sorted_dedup(router_keys)),
|
||||||
|
Arc::new(normalize_aspas(aspas)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_shared_parts(
|
||||||
|
origins: Arc<Vec<RouteOrigin>>,
|
||||||
|
router_keys: Arc<Vec<RouterKey>>,
|
||||||
|
aspas: Arc<Vec<Aspa>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut snapshot = Snapshot {
|
let mut snapshot = Snapshot {
|
||||||
origins,
|
origins,
|
||||||
router_keys,
|
router_keys,
|
||||||
aspas: normalize_aspas(aspas),
|
aspas,
|
||||||
created_at: DualTime::now(),
|
created_at: DualTime::now(),
|
||||||
origins_hash: [0u8; 32],
|
origins_hash: [0u8; 32],
|
||||||
router_keys_hash: [0u8; 32],
|
router_keys_hash: [0u8; 32],
|
||||||
@ -105,21 +117,21 @@ impl Snapshot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::new(BTreeSet::new(), BTreeSet::new(), BTreeSet::new())
|
Self::new(Vec::new(), Vec::new(), Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_payloads(payloads: Vec<Payload>) -> Self {
|
pub fn from_payloads(payloads: Vec<Payload>) -> Self {
|
||||||
let mut origins = BTreeSet::new();
|
let mut origins = Vec::new();
|
||||||
let mut router_keys = BTreeSet::new();
|
let mut router_keys = Vec::new();
|
||||||
let mut aspas = Vec::new();
|
let mut aspas = Vec::new();
|
||||||
|
|
||||||
for p in payloads {
|
for p in payloads {
|
||||||
match p {
|
match p {
|
||||||
Payload::RouteOrigin(o) => {
|
Payload::RouteOrigin(o) => {
|
||||||
origins.insert(o);
|
origins.push(o);
|
||||||
}
|
}
|
||||||
Payload::RouterKey(k) => {
|
Payload::RouterKey(k) => {
|
||||||
router_keys.insert(k);
|
router_keys.push(k);
|
||||||
}
|
}
|
||||||
Payload::Aspa(a) => {
|
Payload::Aspa(a) => {
|
||||||
aspas.push(a);
|
aspas.push(a);
|
||||||
@ -130,6 +142,21 @@ impl Snapshot {
|
|||||||
Snapshot::new(origins, router_keys, normalize_aspas(aspas))
|
Snapshot::new(origins, router_keys, normalize_aspas(aspas))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn project_for_version(&self, version: u8) -> Self {
|
||||||
|
let router_keys = if version >= 1 {
|
||||||
|
self.router_keys.clone()
|
||||||
|
} else {
|
||||||
|
Arc::new(Vec::new())
|
||||||
|
};
|
||||||
|
let aspas = if version >= 2 {
|
||||||
|
self.aspas.clone()
|
||||||
|
} else {
|
||||||
|
Arc::new(Vec::new())
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::from_shared_parts(self.origins.clone(), router_keys, aspas)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn recompute_hashes(&mut self) {
|
pub fn recompute_hashes(&mut self) {
|
||||||
self.origins_hash = self.compute_origins_hash();
|
self.origins_hash = self.compute_origins_hash();
|
||||||
self.router_keys_hash = self.compute_router_keys_hash();
|
self.router_keys_hash = self.compute_router_keys_hash();
|
||||||
@ -182,21 +209,23 @@ impl Snapshot {
|
|||||||
let mut withdrawn = Vec::new();
|
let mut withdrawn = Vec::new();
|
||||||
|
|
||||||
if !self.same_origins(new_snapshot) {
|
if !self.same_origins(new_snapshot) {
|
||||||
for origin in new_snapshot.origins.difference(&self.origins) {
|
diff_sorted(
|
||||||
announced.push(Payload::RouteOrigin(origin.clone()));
|
self.origins.as_slice(),
|
||||||
}
|
new_snapshot.origins.as_slice(),
|
||||||
for origin in self.origins.difference(&new_snapshot.origins) {
|
&mut announced,
|
||||||
withdrawn.push(Payload::RouteOrigin(origin.clone()));
|
&mut withdrawn,
|
||||||
}
|
Payload::RouteOrigin,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.same_router_keys(new_snapshot) {
|
if !self.same_router_keys(new_snapshot) {
|
||||||
for key in new_snapshot.router_keys.difference(&self.router_keys) {
|
diff_sorted(
|
||||||
announced.push(Payload::RouterKey(key.clone()));
|
self.router_keys.as_slice(),
|
||||||
}
|
new_snapshot.router_keys.as_slice(),
|
||||||
for key in self.router_keys.difference(&new_snapshot.router_keys) {
|
&mut announced,
|
||||||
withdrawn.push(Payload::RouterKey(key.clone()));
|
&mut withdrawn,
|
||||||
}
|
Payload::RouterKey,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.same_aspas(new_snapshot) {
|
if !self.same_aspas(new_snapshot) {
|
||||||
@ -268,16 +297,16 @@ impl Snapshot {
|
|||||||
self.snapshot_hash == other.snapshot_hash
|
self.snapshot_hash == other.snapshot_hash
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn origins(&self) -> &BTreeSet<RouteOrigin> {
|
pub fn origins(&self) -> &[RouteOrigin] {
|
||||||
&self.origins
|
self.origins.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn router_keys(&self) -> &BTreeSet<RouterKey> {
|
pub fn router_keys(&self) -> &[RouterKey] {
|
||||||
&self.router_keys
|
self.router_keys.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aspas(&self) -> &BTreeSet<Aspa> {
|
pub fn aspas(&self) -> &[Aspa] {
|
||||||
&self.aspas
|
self.aspas.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
@ -369,15 +398,15 @@ fn build_snapshot_payloads_for_rtr(snapshot: &Snapshot) -> Vec<Payload> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dedup_payloads(payloads: &mut Vec<Payload>) {
|
fn dedup_payloads(payloads: &mut Vec<Payload>) {
|
||||||
let mut seen = BTreeSet::new();
|
payloads.sort();
|
||||||
payloads.retain(|p| seen.insert(p.clone()));
|
payloads.dedup();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalize_aspas<I>(aspas: I) -> BTreeSet<Aspa>
|
fn normalize_aspas<I>(aspas: I) -> Vec<Aspa>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = Aspa>,
|
I: IntoIterator<Item = Aspa>,
|
||||||
{
|
{
|
||||||
let mut by_customer = BTreeMap::<u32, BTreeSet<_>>::new();
|
let mut by_customer = BTreeMap::<u32, Vec<_>>::new();
|
||||||
|
|
||||||
for aspa in aspas {
|
for aspa in aspas {
|
||||||
let providers = by_customer
|
let providers = by_customer
|
||||||
@ -386,17 +415,19 @@ where
|
|||||||
providers.extend(aspa.provider_asns().iter().copied());
|
providers.extend(aspa.provider_asns().iter().copied());
|
||||||
}
|
}
|
||||||
|
|
||||||
by_customer
|
let mut normalized = by_customer
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(customer_asn, providers)| {
|
.map(|(customer_asn, providers)| {
|
||||||
Aspa::new(customer_asn.into(), providers.into_iter().collect())
|
Aspa::new(customer_asn.into(), providers)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect::<Vec<_>>();
|
||||||
|
normalized.sort();
|
||||||
|
normalized
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_aspas(
|
fn diff_aspas(
|
||||||
current: &BTreeSet<Aspa>,
|
current: &[Aspa],
|
||||||
next: &BTreeSet<Aspa>,
|
next: &[Aspa],
|
||||||
announced: &mut Vec<Payload>,
|
announced: &mut Vec<Payload>,
|
||||||
withdrawn: &mut Vec<Payload>,
|
withdrawn: &mut Vec<Payload>,
|
||||||
) {
|
) {
|
||||||
@ -413,7 +444,7 @@ fn diff_aspas(
|
|||||||
.keys()
|
.keys()
|
||||||
.chain(next.keys())
|
.chain(next.keys())
|
||||||
.copied()
|
.copied()
|
||||||
.collect::<BTreeSet<_>>();
|
.collect::<std::collections::BTreeSet<_>>();
|
||||||
|
|
||||||
for customer in customers {
|
for customer in customers {
|
||||||
match (current.get(&customer), next.get(&customer)) {
|
match (current.get(&customer), next.get(&customer)) {
|
||||||
@ -426,3 +457,47 @@ fn diff_aspas(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sorted_dedup<T: Ord>(mut items: Vec<T>) -> Vec<T> {
|
||||||
|
items.sort();
|
||||||
|
items.dedup();
|
||||||
|
items
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diff_sorted<T, F>(
|
||||||
|
current: &[T],
|
||||||
|
next: &[T],
|
||||||
|
announced: &mut Vec<Payload>,
|
||||||
|
withdrawn: &mut Vec<Payload>,
|
||||||
|
wrap: F,
|
||||||
|
) where
|
||||||
|
T: Ord + Clone,
|
||||||
|
F: Fn(T) -> Payload,
|
||||||
|
{
|
||||||
|
let mut i = 0usize;
|
||||||
|
let mut j = 0usize;
|
||||||
|
while i < current.len() && j < next.len() {
|
||||||
|
match current[i].cmp(&next[j]) {
|
||||||
|
std::cmp::Ordering::Less => {
|
||||||
|
withdrawn.push(wrap(current[i].clone()));
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
std::cmp::Ordering::Greater => {
|
||||||
|
announced.push(wrap(next[j].clone()));
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
std::cmp::Ordering::Equal => {
|
||||||
|
i += 1;
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while i < current.len() {
|
||||||
|
withdrawn.push(wrap(current[i].clone()));
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
while j < next.len() {
|
||||||
|
announced.push(wrap(next[j].clone()));
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
11
src/rtr/cache/store.rs
vendored
11
src/rtr/cache/store.rs
vendored
@ -213,14 +213,5 @@ fn persist_update_job(job: StoreSyncJob) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn project_snapshot_for_version(snapshot: &Snapshot, version: u8) -> Snapshot {
|
fn project_snapshot_for_version(snapshot: &Snapshot, version: u8) -> Snapshot {
|
||||||
let mut payloads = Vec::new();
|
snapshot.project_for_version(version)
|
||||||
for payload in snapshot.payloads() {
|
|
||||||
match payload {
|
|
||||||
Payload::RouteOrigin(_) => payloads.push(payload),
|
|
||||||
Payload::RouterKey(_) if version >= 1 => payloads.push(payload),
|
|
||||||
Payload::Aspa(_) if version >= 2 => payloads.push(payload),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Snapshot::from_payloads(payloads)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ use crate::rtr::cache::SharedRtrCache;
|
|||||||
use crate::rtr::server::config::RtrServiceConfig;
|
use crate::rtr::server::config::RtrServiceConfig;
|
||||||
use crate::rtr::server::listener::RtrServer;
|
use crate::rtr::server::listener::RtrServer;
|
||||||
use crate::rtr::server::notifier::RtrNotifier;
|
use crate::rtr::server::notifier::RtrNotifier;
|
||||||
use crate::rtr::server::ssh::load_rtr_ssh_runtime_config;
|
use crate::rtr::server::ssh::{SshAuthMode, load_rtr_ssh_runtime_config};
|
||||||
|
|
||||||
pub struct RtrService {
|
pub struct RtrService {
|
||||||
cache: SharedRtrCache,
|
cache: SharedRtrCache,
|
||||||
@ -167,6 +167,7 @@ impl RtrService {
|
|||||||
authorized_keys_path: impl AsRef<Path>,
|
authorized_keys_path: impl AsRef<Path>,
|
||||||
username: &str,
|
username: &str,
|
||||||
subsystem_name: &str,
|
subsystem_name: &str,
|
||||||
|
auth_mode: SshAuthMode,
|
||||||
password: Option<&str>,
|
password: Option<&str>,
|
||||||
) -> JoinHandle<()> {
|
) -> JoinHandle<()> {
|
||||||
let host_key_path = host_key_path.as_ref().to_path_buf();
|
let host_key_path = host_key_path.as_ref().to_path_buf();
|
||||||
@ -184,6 +185,7 @@ impl RtrService {
|
|||||||
&authorized_keys_path,
|
&authorized_keys_path,
|
||||||
&username,
|
&username,
|
||||||
&subsystem_name,
|
&subsystem_name,
|
||||||
|
auth_mode,
|
||||||
password.as_deref(),
|
password.as_deref(),
|
||||||
inactivity_timeout,
|
inactivity_timeout,
|
||||||
keepalive_interval,
|
keepalive_interval,
|
||||||
@ -213,6 +215,7 @@ impl RtrService {
|
|||||||
authorized_keys_path: impl AsRef<Path>,
|
authorized_keys_path: impl AsRef<Path>,
|
||||||
username: &str,
|
username: &str,
|
||||||
subsystem_name: &str,
|
subsystem_name: &str,
|
||||||
|
auth_mode: SshAuthMode,
|
||||||
password: Option<&str>,
|
password: Option<&str>,
|
||||||
) -> RunningRtrService {
|
) -> RunningRtrService {
|
||||||
let tcp_handle = self.spawn_tcp(tcp_bind_addr);
|
let tcp_handle = self.spawn_tcp(tcp_bind_addr);
|
||||||
@ -222,6 +225,7 @@ impl RtrService {
|
|||||||
authorized_keys_path,
|
authorized_keys_path,
|
||||||
username,
|
username,
|
||||||
subsystem_name,
|
subsystem_name,
|
||||||
|
auth_mode,
|
||||||
password,
|
password,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -244,6 +248,7 @@ impl RtrService {
|
|||||||
authorized_keys_path: impl AsRef<Path>,
|
authorized_keys_path: impl AsRef<Path>,
|
||||||
username: &str,
|
username: &str,
|
||||||
subsystem_name: &str,
|
subsystem_name: &str,
|
||||||
|
auth_mode: SshAuthMode,
|
||||||
password: Option<&str>,
|
password: Option<&str>,
|
||||||
) -> RunningRtrService {
|
) -> RunningRtrService {
|
||||||
let tcp_handle = self.spawn_tcp(tcp_bind_addr);
|
let tcp_handle = self.spawn_tcp(tcp_bind_addr);
|
||||||
@ -255,6 +260,7 @@ impl RtrService {
|
|||||||
authorized_keys_path,
|
authorized_keys_path,
|
||||||
username,
|
username,
|
||||||
subsystem_name,
|
subsystem_name,
|
||||||
|
auth_mode,
|
||||||
password,
|
password,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,32 @@ use russh::keys::ssh_key::{self, AuthorizedKeys};
|
|||||||
use russh::server::Config as RusshServerConfig;
|
use russh::server::Config as RusshServerConfig;
|
||||||
use russh::{MethodKind, MethodSet};
|
use russh::{MethodKind, MethodSet};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum SshAuthMode {
|
||||||
|
Key,
|
||||||
|
Password,
|
||||||
|
Both,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SshAuthMode {
|
||||||
|
pub fn parse(value: &str) -> Option<Self> {
|
||||||
|
match value.trim().to_ascii_lowercase().as_str() {
|
||||||
|
"key" | "publickey" => Some(Self::Key),
|
||||||
|
"password" => Some(Self::Password),
|
||||||
|
"both" => Some(Self::Both),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Key => "key",
|
||||||
|
Self::Password => "password",
|
||||||
|
Self::Both => "both",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RtrSshRuntimeConfig {
|
pub struct RtrSshRuntimeConfig {
|
||||||
pub server_config: Arc<RusshServerConfig>,
|
pub server_config: Arc<RusshServerConfig>,
|
||||||
@ -23,6 +49,7 @@ pub fn load_rtr_ssh_runtime_config(
|
|||||||
authorized_keys_path: impl AsRef<Path>,
|
authorized_keys_path: impl AsRef<Path>,
|
||||||
username: &str,
|
username: &str,
|
||||||
subsystem_name: &str,
|
subsystem_name: &str,
|
||||||
|
auth_mode: SshAuthMode,
|
||||||
password: Option<&str>,
|
password: Option<&str>,
|
||||||
inactivity_timeout: Option<Duration>,
|
inactivity_timeout: Option<Duration>,
|
||||||
keepalive_interval: Option<Duration>,
|
keepalive_interval: Option<Duration>,
|
||||||
@ -35,12 +62,21 @@ pub fn load_rtr_ssh_runtime_config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let host_key = load_host_key(host_key_path.as_ref())?;
|
let host_key = load_host_key(host_key_path.as_ref())?;
|
||||||
let authorized_keys = load_authorized_keys(authorized_keys_path.as_ref())?;
|
let authorized_keys = if matches!(auth_mode, SshAuthMode::Key | SshAuthMode::Both) {
|
||||||
|
load_authorized_keys(authorized_keys_path.as_ref())?
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
let password = password.map(str::trim).filter(|value| !value.is_empty());
|
let password = password.map(str::trim).filter(|value| !value.is_empty());
|
||||||
|
if matches!(auth_mode, SshAuthMode::Password | SshAuthMode::Both) && password.is_none() {
|
||||||
|
bail!("SSH auth mode '{}' requires non-empty password", auth_mode.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
let mut methods = MethodSet::empty();
|
let mut methods = MethodSet::empty();
|
||||||
methods.push(MethodKind::PublicKey);
|
if matches!(auth_mode, SshAuthMode::Key | SshAuthMode::Both) {
|
||||||
if password.is_some() {
|
methods.push(MethodKind::PublicKey);
|
||||||
|
}
|
||||||
|
if matches!(auth_mode, SshAuthMode::Password | SshAuthMode::Both) {
|
||||||
methods.push(MethodKind::Password);
|
methods.push(MethodKind::Password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ use tokio_rustls::TlsConnector;
|
|||||||
use rpki::rtr::cache::{RtrCacheBuilder, SessionIds, SharedRtrCache};
|
use rpki::rtr::cache::{RtrCacheBuilder, SessionIds, SharedRtrCache};
|
||||||
use rpki::rtr::payload::Timing;
|
use rpki::rtr::payload::Timing;
|
||||||
use rpki::rtr::pdu::{CacheResponse, EndOfDataV1, ResetQuery};
|
use rpki::rtr::pdu::{CacheResponse, EndOfDataV1, ResetQuery};
|
||||||
|
use rpki::rtr::server::ssh::SshAuthMode;
|
||||||
use rpki::rtr::server::RtrService;
|
use rpki::rtr::server::RtrService;
|
||||||
use russh::client;
|
use russh::client;
|
||||||
use russh::keys;
|
use russh::keys;
|
||||||
@ -201,6 +202,7 @@ async fn unified_server_ssh_opens_listener_and_emits_banner() {
|
|||||||
&authorized_keys_path,
|
&authorized_keys_path,
|
||||||
"rpki-rtr",
|
"rpki-rtr",
|
||||||
"rpki-rtr",
|
"rpki-rtr",
|
||||||
|
SshAuthMode::Key,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
wait_for_port(ssh_addr).await;
|
wait_for_port(ssh_addr).await;
|
||||||
@ -249,6 +251,7 @@ async fn unified_server_ssh_accepts_password_when_configured() {
|
|||||||
&authorized_keys_path,
|
&authorized_keys_path,
|
||||||
"rpki-rtr",
|
"rpki-rtr",
|
||||||
"rpki-rtr",
|
"rpki-rtr",
|
||||||
|
SshAuthMode::Both,
|
||||||
Some("test-password"),
|
Some("test-password"),
|
||||||
);
|
);
|
||||||
wait_for_port(ssh_addr).await;
|
wait_for_port(ssh_addr).await;
|
||||||
@ -323,6 +326,7 @@ async fn unified_server_ssh_rejects_password_when_not_configured() {
|
|||||||
&authorized_keys_path,
|
&authorized_keys_path,
|
||||||
"rpki-rtr",
|
"rpki-rtr",
|
||||||
"rpki-rtr",
|
"rpki-rtr",
|
||||||
|
SshAuthMode::Key,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
wait_for_port(ssh_addr).await;
|
wait_for_port(ssh_addr).await;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user