mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-04-22 16:17:23 +08:00
fix: listener parsing (#2143)
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build_web (push) Blocked by required conditions
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-24.04, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-24.04-arm, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-24.04, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-24.04, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-24.04, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-24.04, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-loongarch64, ubuntu-24.04, loongarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-24.04, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-24.04, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-riscv64, ubuntu-24.04, riscv64gc-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-24.04, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-arm64, windows-11-arm, aarch64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / build (windows-i686, windows-latest, i686-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / build_magisk (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-24.04-arm, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-24.04, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-arm64, aarch64-pc-windows-msvc, windows-11-arm, aarch64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-i686, i686-pc-windows-msvc, windows-latest, i686-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (aarch64, aarch64-linux-android) (push) Blocked by required conditions
EasyTier Mobile / build-mobile (armv7, armv7-linux-androideabi) (push) Blocked by required conditions
EasyTier Mobile / build-mobile (i686, i686-linux-android) (push) Blocked by required conditions
EasyTier Mobile / build-mobile (x86_64, x86_64-linux-android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
Nix Check / check-full-shell (push) Waiting to run
EasyTier OHOS / cargo_fmt_check (push) Waiting to run
EasyTier OHOS / pre_job (push) Waiting to run
EasyTier OHOS / build-ohos (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / Run linters & check (push) Blocked by required conditions
EasyTier Test / Build test (push) Blocked by required conditions
EasyTier Test / Test (easytier) (push) Blocked by required conditions
EasyTier Test / Test (three_node) (push) Blocked by required conditions
EasyTier Test / Test (three_node::subnet_proxy_three_node_test) (push) Blocked by required conditions
EasyTier Test / test (push) Blocked by required conditions
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build_web (push) Blocked by required conditions
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-24.04, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-24.04-arm, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-24.04, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-24.04, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-24.04, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-24.04, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-loongarch64, ubuntu-24.04, loongarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-24.04, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-24.04, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-riscv64, ubuntu-24.04, riscv64gc-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-24.04, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-arm64, windows-11-arm, aarch64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / build (windows-i686, windows-latest, i686-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / build_magisk (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-24.04-arm, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-24.04, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-arm64, aarch64-pc-windows-msvc, windows-11-arm, aarch64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-i686, i686-pc-windows-msvc, windows-latest, i686-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (aarch64, aarch64-linux-android) (push) Blocked by required conditions
EasyTier Mobile / build-mobile (armv7, armv7-linux-androideabi) (push) Blocked by required conditions
EasyTier Mobile / build-mobile (i686, i686-linux-android) (push) Blocked by required conditions
EasyTier Mobile / build-mobile (x86_64, x86_64-linux-android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
Nix Check / check-full-shell (push) Waiting to run
EasyTier OHOS / cargo_fmt_check (push) Waiting to run
EasyTier OHOS / pre_job (push) Waiting to run
EasyTier OHOS / build-ohos (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / Run linters & check (push) Blocked by required conditions
EasyTier Test / Build test (push) Blocked by required conditions
EasyTier Test / Test (easytier) (push) Blocked by required conditions
EasyTier Test / Test (three_node) (push) Blocked by required conditions
EasyTier Test / Test (three_node::subnet_proxy_three_node_test) (push) Blocked by required conditions
EasyTier Test / test (push) Blocked by required conditions
Fixes a CLI listener parsing regression where url crate special-casing for ws/wss could misinterpret inputs like ws:11011, and adds coverage to prevent future regressions. Changes: Refactors listener parsing to avoid url::Url parsing for proto:port forms and to support additional shorthand inputs (port-only / IP-only / SocketAddr). Centralizes “expand to all IpScheme variants” logic in a helper (gen_listeners) while preserving the “port=0 is dynamic” behavior. Adds unit tests covering valid/invalid listener inputs and expansion behavior.
This commit is contained in:
+150
-49
@@ -1,12 +1,5 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::{
|
|
||||||
net::{IpAddr, SocketAddr},
|
|
||||||
path::PathBuf,
|
|
||||||
process::ExitCode,
|
|
||||||
sync::{Arc, atomic::AtomicBool},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ShellType,
|
ShellType,
|
||||||
common::{
|
common::{
|
||||||
@@ -30,6 +23,12 @@ use anyhow::Context;
|
|||||||
use cidr::IpCidr;
|
use cidr::IpCidr;
|
||||||
use clap::{CommandFactory, Parser};
|
use clap::{CommandFactory, Parser};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
use std::{
|
||||||
|
net::{IpAddr, SocketAddr},
|
||||||
|
path::PathBuf,
|
||||||
|
process::ExitCode,
|
||||||
|
sync::{Arc, atomic::AtomicBool},
|
||||||
|
};
|
||||||
use strum::VariantArray;
|
use strum::VariantArray;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
@@ -744,55 +743,69 @@ struct RpcPortalOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Cli {
|
impl Cli {
|
||||||
|
fn gen_listeners(addr: SocketAddr) -> impl Iterator<Item = String> {
|
||||||
|
let dynamic = addr.port() == 0;
|
||||||
|
IpScheme::VARIANTS.iter().map(move |proto| {
|
||||||
|
let mut addr = addr;
|
||||||
|
if !dynamic {
|
||||||
|
addr.set_port(addr.port() + proto.port_offset());
|
||||||
|
}
|
||||||
|
format!("{}://{}", proto, addr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_listeners(no_listener: bool, listeners: Vec<String>) -> anyhow::Result<Vec<String>> {
|
fn parse_listeners(no_listener: bool, listeners: Vec<String>) -> anyhow::Result<Vec<String>> {
|
||||||
if no_listener || listeners.is_empty() {
|
if no_listener || listeners.is_empty() {
|
||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if listeners.len() == 1
|
let mut parsed = vec![];
|
||||||
&& let Ok(port) = listeners[0].parse::<u16>()
|
|
||||||
{
|
for l in listeners.into_iter() {
|
||||||
let listeners = IpScheme::VARIANTS
|
if let Ok(port) = l.parse::<u16>() {
|
||||||
.iter()
|
parsed.extend(Self::gen_listeners(SocketAddr::new(
|
||||||
.map(|proto| {
|
"0.0.0.0".parse()?,
|
||||||
format!(
|
port,
|
||||||
"{}://0.0.0.0:{}",
|
)));
|
||||||
proto,
|
continue;
|
||||||
if port == 0 {
|
}
|
||||||
0
|
|
||||||
} else {
|
if let Ok(ip) = l.trim_matches(|c| c == '[' || c == ']').parse::<IpAddr>() {
|
||||||
port + proto.port_offset()
|
parsed.extend(Self::gen_listeners(SocketAddr::new(ip, 11010)));
|
||||||
}
|
continue;
|
||||||
)
|
}
|
||||||
})
|
|
||||||
.collect();
|
if let Ok(addr) = l.parse::<SocketAddr>() {
|
||||||
return Ok(listeners);
|
parsed.extend(Self::gen_listeners(addr));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (scheme, rest) = l.split_once(':').unwrap_or((&l, ""));
|
||||||
|
let Ok(scheme) = scheme.parse::<IpScheme>() else {
|
||||||
|
anyhow::bail!("invalid listener: {}", l);
|
||||||
|
};
|
||||||
|
|
||||||
|
if rest.is_empty() {
|
||||||
|
parsed.push(format!(
|
||||||
|
"{}://0.0.0.0:{}",
|
||||||
|
scheme,
|
||||||
|
11010 + scheme.port_offset()
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(port) = rest.parse::<u16>() {
|
||||||
|
parsed.push(format!("{}://0.0.0.0:{}", scheme, port));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !l.parse::<url::Url>()?.has_authority() {
|
||||||
|
anyhow::bail!("invalid listener: {}", l);
|
||||||
|
}
|
||||||
|
parsed.push(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
listeners
|
Ok(parsed)
|
||||||
.into_iter()
|
|
||||||
.map(|l| {
|
|
||||||
let l = l
|
|
||||||
.parse::<url::Url>()
|
|
||||||
.or_else(|_| url::Url::parse(&format!("{}:", l)))?;
|
|
||||||
|
|
||||||
if l.has_authority() {
|
|
||||||
return Ok(l.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
let scheme: IpScheme = l.scheme().parse()?;
|
|
||||||
let port = {
|
|
||||||
let port = l.path();
|
|
||||||
if port.is_empty() {
|
|
||||||
11010 + scheme.port_offset()
|
|
||||||
} else {
|
|
||||||
port.parse::<u16>()
|
|
||||||
.with_context(|| format!("invalid port: {}", port))?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(format!("{}://0.0.0.0:{}", scheme, port))
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1594,3 +1607,91 @@ async fn validate_config(cli: &Cli) -> anyhow::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_listeners() {
|
||||||
|
type IpSchemeMap = fn(&IpScheme) -> String;
|
||||||
|
|
||||||
|
let cases: [(&str, IpSchemeMap); _] = [
|
||||||
|
("0", |s| format!("{}://0.0.0.0:0", s)),
|
||||||
|
("11010", |s| {
|
||||||
|
format!("{}://0.0.0.0:{}", s, 11010 + s.port_offset())
|
||||||
|
}),
|
||||||
|
("1.1.1.1", |s| {
|
||||||
|
format!("{}://1.1.1.1:{}", s, 11010 + s.port_offset())
|
||||||
|
}),
|
||||||
|
("1.1.1.1:50000", |s| {
|
||||||
|
format!("{}://1.1.1.1:{}", s, 50000 + s.port_offset())
|
||||||
|
}),
|
||||||
|
("[::1]", |s| {
|
||||||
|
format!("{}://[::1]:{}", s, 11010 + s.port_offset())
|
||||||
|
}),
|
||||||
|
("[::1]:50000", |s| {
|
||||||
|
format!("{}://[::1]:{}", s, 50000 + s.port_offset())
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (input, output) in cases {
|
||||||
|
assert_eq!(
|
||||||
|
Cli::parse_listeners(false, vec![input.to_string()]).unwrap(),
|
||||||
|
IpScheme::VARIANTS.iter().map(output).collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = cases.iter().map(|(i, _)| i.to_string()).collect::<Vec<_>>();
|
||||||
|
let output = cases
|
||||||
|
.iter()
|
||||||
|
.flat_map(|(_, o)| IpScheme::VARIANTS.iter().map(o))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(Cli::parse_listeners(false, input).unwrap(), output);
|
||||||
|
|
||||||
|
let cases: [(IpSchemeMap, IpSchemeMap); _] = [
|
||||||
|
(
|
||||||
|
|s| format!("{}", s),
|
||||||
|
|s| format!("{}://0.0.0.0:{}", s, 11010 + s.port_offset()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
|s| format!("{}:50000", s),
|
||||||
|
|s| format!("{}://0.0.0.0:50000", s),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
|s| format!("{}://1.1.1.1:50000", s),
|
||||||
|
|s| format!("{}://1.1.1.1:50000", s),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (input, output) in cases {
|
||||||
|
assert_eq!(
|
||||||
|
Cli::parse_listeners(
|
||||||
|
false,
|
||||||
|
IpScheme::VARIANTS.iter().map(input).collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
IpScheme::VARIANTS.iter().map(output).collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = cases
|
||||||
|
.iter()
|
||||||
|
.flat_map(|(i, _)| IpScheme::VARIANTS.iter().map(i))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let output = cases
|
||||||
|
.iter()
|
||||||
|
.flat_map(|(_, o)| IpScheme::VARIANTS.iter().map(o))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(Cli::parse_listeners(false, input).unwrap(), output);
|
||||||
|
|
||||||
|
let cases = ["tcp://[::1", "xxx", "tcp:/abc", "tcp:abc"];
|
||||||
|
for input in cases {
|
||||||
|
assert!(
|
||||||
|
Cli::parse_listeners(false, vec![input.to_string()]).is_err(),
|
||||||
|
"input: {}",
|
||||||
|
input
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user