feat(core): implement StaticConfig/DynamicConfig split with ArcSwap hot-reload
Split alknet-core configuration into StaticConfig (immutable after startup) and DynamicConfig (hot-reloadable at runtime via ArcSwap). - Add StaticConfig struct in config/static_config.rs with all fields per ADR-030 - Add DynamicConfig struct with AuthPolicy, ForwardingPolicy, RateLimitConfig - Add ForwardingPolicy with allow_all()/deny_all() defaults (ADR-031) - Add ConfigReloadHandle with reload() method for runtime config updates - Replace Arc<ServerAuthConfig> with Arc<ArcSwap<DynamicConfig>> in ServerHandler - Add config_reload_handle() to Server for obtaining reload handles - Add AuthPolicy with authenticate_publickey/authenticate_certificate methods - All existing tests pass with the new config structure - Default DynamicConfig produces identical behavior to current code
This commit is contained in:
@@ -52,9 +52,7 @@ impl<C: ChannelOpener> Socks5Server<C> {
|
||||
}
|
||||
|
||||
pub fn with_addr(channel_opener: C, addr: &str) -> Self {
|
||||
let listen_addr: SocketAddr = addr
|
||||
.parse()
|
||||
.expect("invalid SOCKS5 listen address");
|
||||
let listen_addr: SocketAddr = addr.parse().expect("invalid SOCKS5 listen address");
|
||||
Self {
|
||||
listen_addr,
|
||||
channel_opener: Arc::new(channel_opener),
|
||||
@@ -80,10 +78,7 @@ impl<C: ChannelOpener> Socks5Server<C> {
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_socks5_connection<S, C>(
|
||||
mut socket: S,
|
||||
opener: Arc<C>,
|
||||
) -> Result<(), Socks5Error>
|
||||
async fn handle_socks5_connection<S, C>(mut socket: S, opener: Arc<C>) -> Result<(), Socks5Error>
|
||||
where
|
||||
S: AsyncRead + AsyncWrite + Unpin,
|
||||
C: ChannelOpener,
|
||||
@@ -173,7 +168,11 @@ impl<H: russh::client::Handler> HandleChannelOpener<H> {
|
||||
impl<H: russh::client::Handler + Send + Sync + 'static> ChannelOpener for HandleChannelOpener<H> {
|
||||
type Stream = russh::ChannelStream<russh::client::Msg>;
|
||||
|
||||
async fn open_channel(&self, host: String, port: u16) -> Result<Self::Stream, ChannelOpenError> {
|
||||
async fn open_channel(
|
||||
&self,
|
||||
host: String,
|
||||
port: u16,
|
||||
) -> Result<Self::Stream, ChannelOpenError> {
|
||||
let handle = self.handle.lock().await;
|
||||
if handle.is_closed() {
|
||||
return Err(ChannelOpenError::SessionClosed);
|
||||
@@ -241,7 +240,10 @@ mod tests {
|
||||
}
|
||||
|
||||
async fn do_handshake(client: &mut DuplexStream) -> [u8; 2] {
|
||||
client.write_all(&build_socks5_greeting(&[0x00])).await.unwrap();
|
||||
client
|
||||
.write_all(&build_socks5_greeting(&[0x00]))
|
||||
.await
|
||||
.unwrap();
|
||||
client.flush().await.unwrap();
|
||||
let mut resp = [0u8; 2];
|
||||
client.read_exact(&mut resp).await.unwrap();
|
||||
@@ -264,9 +266,8 @@ mod tests {
|
||||
let (mut client, server) = duplex(4096);
|
||||
let opener = MockChannelOpener { fail: false };
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
handle_socks5_connection(server, Arc::new(opener)).await
|
||||
});
|
||||
let server_handle =
|
||||
tokio::spawn(async move { handle_socks5_connection(server, Arc::new(opener)).await });
|
||||
|
||||
let resp = do_handshake(&mut client).await;
|
||||
assert_eq!(resp, [0x05, 0x00]);
|
||||
@@ -284,9 +285,8 @@ mod tests {
|
||||
let (mut client, server) = duplex(4096);
|
||||
let opener = MockChannelOpener { fail: false };
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
handle_socks5_connection(server, Arc::new(opener)).await
|
||||
});
|
||||
let server_handle =
|
||||
tokio::spawn(async move { handle_socks5_connection(server, Arc::new(opener)).await });
|
||||
|
||||
client
|
||||
.write_all(&build_socks5_greeting(&[0x02]))
|
||||
@@ -301,10 +301,7 @@ mod tests {
|
||||
drop(client);
|
||||
let result = server_handle.await.unwrap();
|
||||
assert!(result.is_err());
|
||||
assert!(matches!(
|
||||
result.unwrap_err(),
|
||||
Socks5Error::NoAcceptableAuth
|
||||
));
|
||||
assert!(matches!(result.unwrap_err(), Socks5Error::NoAcceptableAuth));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -312,9 +309,8 @@ mod tests {
|
||||
let (mut client, server) = duplex(4096);
|
||||
let opener = MockChannelOpener { fail: false };
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
handle_socks5_connection(server, Arc::new(opener)).await
|
||||
});
|
||||
let server_handle =
|
||||
tokio::spawn(async move { handle_socks5_connection(server, Arc::new(opener)).await });
|
||||
|
||||
do_handshake(&mut client).await;
|
||||
let reply_buf = do_connect_ipv4(&mut client, [10, 0, 0, 1], 443).await;
|
||||
@@ -329,9 +325,8 @@ mod tests {
|
||||
let (mut client, server) = duplex(4096);
|
||||
let opener = MockChannelOpener { fail: false };
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
handle_socks5_connection(server, Arc::new(opener)).await
|
||||
});
|
||||
let server_handle =
|
||||
tokio::spawn(async move { handle_socks5_connection(server, Arc::new(opener)).await });
|
||||
|
||||
do_handshake(&mut client).await;
|
||||
|
||||
@@ -354,9 +349,8 @@ mod tests {
|
||||
let (mut client, server) = duplex(4096);
|
||||
let opener = MockChannelOpener { fail: false };
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
handle_socks5_connection(server, Arc::new(opener)).await
|
||||
});
|
||||
let server_handle =
|
||||
tokio::spawn(async move { handle_socks5_connection(server, Arc::new(opener)).await });
|
||||
|
||||
do_handshake(&mut client).await;
|
||||
|
||||
@@ -381,9 +375,8 @@ mod tests {
|
||||
let (mut client, server) = duplex(4096);
|
||||
let opener = MockChannelOpener { fail: true };
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
handle_socks5_connection(server, Arc::new(opener)).await
|
||||
});
|
||||
let server_handle =
|
||||
tokio::spawn(async move { handle_socks5_connection(server, Arc::new(opener)).await });
|
||||
|
||||
do_handshake(&mut client).await;
|
||||
let reply_buf = do_connect_ipv4(&mut client, [10, 0, 0, 1], 80).await;
|
||||
@@ -399,9 +392,8 @@ mod tests {
|
||||
let (mut client, server) = duplex(4096);
|
||||
let opener = MockChannelOpener { fail: false };
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
handle_socks5_connection(server, Arc::new(opener)).await
|
||||
});
|
||||
let server_handle =
|
||||
tokio::spawn(async move { handle_socks5_connection(server, Arc::new(opener)).await });
|
||||
|
||||
do_handshake(&mut client).await;
|
||||
|
||||
@@ -450,9 +442,10 @@ mod tests {
|
||||
stream: Arc::clone(&ssh_stream),
|
||||
};
|
||||
|
||||
let server_handle = tokio::spawn(async move {
|
||||
handle_socks5_connection(server_sock, Arc::new(opener)).await
|
||||
});
|
||||
let server_handle =
|
||||
tokio::spawn(
|
||||
async move { handle_socks5_connection(server_sock, Arc::new(opener)).await },
|
||||
);
|
||||
|
||||
do_handshake(&mut client_sock).await;
|
||||
let reply_buf = do_connect_ipv4(&mut client_sock, [127, 0, 0, 1], 80).await;
|
||||
@@ -494,4 +487,4 @@ mod tests {
|
||||
let server = Socks5Server::with_addr(opener, "127.0.0.1:9050");
|
||||
assert_eq!(server.listen_addr(), "127.0.0.1:9050".parse().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,10 +169,7 @@ mod tests {
|
||||
let req = Socks5Request::read_from(&mut cursor).await.unwrap();
|
||||
assert_eq!(req.version, 0x05);
|
||||
assert_eq!(req.command, 0x01);
|
||||
assert_eq!(
|
||||
req.address,
|
||||
Socks5Address::Ipv4(Ipv4Addr::new(10, 0, 0, 1))
|
||||
);
|
||||
assert_eq!(req.address, Socks5Address::Ipv4(Ipv4Addr::new(10, 0, 0, 1)));
|
||||
assert_eq!(req.port, 443);
|
||||
}
|
||||
|
||||
@@ -201,7 +198,10 @@ mod tests {
|
||||
let req = Socks5Request::read_from(&mut cursor).await.unwrap();
|
||||
assert_eq!(req.version, 0x05);
|
||||
assert_eq!(req.command, 0x01);
|
||||
assert_eq!(req.address, Socks5Address::Domain("example.com".to_string()));
|
||||
assert_eq!(
|
||||
req.address,
|
||||
Socks5Address::Domain("example.com".to_string())
|
||||
);
|
||||
assert_eq!(req.port, 443);
|
||||
}
|
||||
|
||||
@@ -301,4 +301,4 @@ mod tests {
|
||||
let port = cursor.read_u16().await.unwrap();
|
||||
assert_eq!(port, 8080);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user