Use Option type for credentials

This commit applys the diff by @ssrlive from
3223ca4e22 (commitcomment-105521241).
This commit is contained in:
B. Blechschmidt 2023-03-22 12:18:41 +01:00
parent 8dd075a7f4
commit 2f295c3fdc
7 changed files with 40 additions and 35 deletions

View file

@ -35,7 +35,7 @@ impl HttpConnection {
server_outbuf.extend(b" HTTP/1.1\r\nHost: ".iter()); server_outbuf.extend(b" HTTP/1.1\r\nHost: ".iter());
server_outbuf.extend(connection.dst.to_string().as_bytes()); server_outbuf.extend(connection.dst.to_string().as_bytes());
server_outbuf.extend(b"\r\n".iter()); server_outbuf.extend(b"\r\n".iter());
if credentials.authenticate { if let Some(credentials) = credentials {
server_outbuf.extend(b"Proxy-Authorization: Basic "); server_outbuf.extend(b"Proxy-Authorization: Basic ");
let mut auth_plain = credentials.username.clone(); let mut auth_plain = credentials.username.clone();
auth_plain.extend(b":".iter()); auth_plain.extend(b":".iter());
@ -165,7 +165,7 @@ impl TcpProxy for HttpConnection {
pub struct HttpManager { pub struct HttpManager {
server: std::net::SocketAddr, server: std::net::SocketAddr,
credentials: Credentials, credentials: Option<Credentials>,
} }
impl ConnectionManager for HttpManager { impl ConnectionManager for HttpManager {
@ -192,13 +192,13 @@ impl ConnectionManager for HttpManager {
self.server self.server
} }
fn get_credentials(&self) -> &Credentials { fn get_credentials(&self) -> &Option<Credentials> {
&self.credentials &self.credentials
} }
} }
impl HttpManager { impl HttpManager {
pub fn new(server: SocketAddr, credentials: Credentials) -> std::rc::Rc<Self> { pub fn new(server: SocketAddr, credentials: Option<Credentials>) -> std::rc::Rc<Self> {
std::rc::Rc::new(Self { std::rc::Rc::new(Self {
server, server,
credentials, credentials,

View file

@ -13,7 +13,21 @@ pub enum ProxyType {
Http, Http,
} }
pub fn main_entry(tun: &str, addr: SocketAddr, proxy_type: ProxyType, credentials: Credentials) { impl std::fmt::Display for ProxyType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ProxyType::Socks5 => write!(f, "socks5"),
ProxyType::Http => write!(f, "http"),
}
}
}
pub fn main_entry(
tun: &str,
addr: SocketAddr,
proxy_type: ProxyType,
credentials: Option<Credentials>,
) {
let mut ttp = TunToProxy::new(tun); let mut ttp = TunToProxy::new(tun);
match proxy_type { match proxy_type {
ProxyType::Socks5 => { ProxyType::Socks5 => {

View file

@ -23,7 +23,7 @@ struct Args {
struct ArgProxy { struct ArgProxy {
proxy_type: ProxyType, proxy_type: ProxyType,
addr: SocketAddr, addr: SocketAddr,
credentials: Credentials, credentials: Option<Credentials>,
} }
fn proxy_url_parser(s: &str) -> Result<ArgProxy, String> { fn proxy_url_parser(s: &str) -> Result<ArgProxy, String> {
@ -46,12 +46,11 @@ fn proxy_url_parser(s: &str) -> Result<ArgProxy, String> {
.ok_or(format!("`{host}` does not resolve to a usable IP address"))?; .ok_or(format!("`{host}` does not resolve to a usable IP address"))?;
let credentials = if url.username() == "" && url.password().is_none() { let credentials = if url.username() == "" && url.password().is_none() {
Credentials::none() None
} else { } else {
Credentials::new( let username = String::from(url.username());
String::from(url.username()), let password = String::from(url.password().unwrap_or(""));
String::from(url.password().unwrap_or("")), Some(Credentials::new(&username, &password))
)
}; };
let scheme = url.scheme(); let scheme = url.scheme();
@ -75,12 +74,8 @@ fn main() {
let args = Args::parse(); let args = Args::parse();
let addr = args.proxy.addr; let addr = args.proxy.addr;
log::info!("Proxy server: {addr}"); let proxy_type = args.proxy.proxy_type;
log::info!("Proxy {proxy_type} server: {addr}");
main_entry( main_entry(&args.tun, addr, proxy_type, args.proxy.credentials);
&args.tun,
args.proxy.addr,
args.proxy.proxy_type,
args.proxy.credentials,
);
} }

View file

@ -82,7 +82,7 @@ impl SocksConnection {
fn send_client_hello(&mut self) { fn send_client_hello(&mut self) {
let credentials = self.manager.get_credentials(); let credentials = self.manager.get_credentials();
if credentials.authenticate { if credentials.is_some() {
self.server_outbuf.extend(&[5u8, 1, 2]); self.server_outbuf.extend(&[5u8, 1, 2]);
} else { } else {
self.server_outbuf.extend(&[5u8, 1, 0]); self.server_outbuf.extend(&[5u8, 1, 0]);
@ -100,8 +100,8 @@ impl SocksConnection {
)); ));
} }
if self.server_inbuf[1] != 0 && !self.manager.get_credentials().authenticate if self.server_inbuf[1] != 0 && self.manager.get_credentials().is_none()
|| self.server_inbuf[1] != 2 && self.manager.get_credentials().authenticate || self.server_inbuf[1] != 2 && self.manager.get_credentials().is_some()
{ {
return Err(ProxyError::new( return Err(ProxyError::new(
"SOCKS server requires an unsupported authentication method.".into(), "SOCKS server requires an unsupported authentication method.".into(),
@ -110,7 +110,7 @@ impl SocksConnection {
self.server_inbuf.drain(0..2); self.server_inbuf.drain(0..2);
if self.manager.get_credentials().authenticate { if self.manager.get_credentials().is_some() {
self.state = SocksState::SendAuthData; self.state = SocksState::SendAuthData;
} else { } else {
self.state = SocksState::SendRequest; self.state = SocksState::SendRequest;
@ -119,7 +119,8 @@ impl SocksConnection {
} }
fn send_auth_data(&mut self) -> Result<(), ProxyError> { fn send_auth_data(&mut self) -> Result<(), ProxyError> {
let credentials = self.manager.get_credentials(); let tmp = Credentials::default();
let credentials = self.manager.get_credentials().as_ref().unwrap_or(&tmp);
self.server_outbuf self.server_outbuf
.extend(&[1u8, credentials.username.len() as u8]); .extend(&[1u8, credentials.username.len() as u8]);
self.server_outbuf.extend(&credentials.username); self.server_outbuf.extend(&credentials.username);
@ -285,7 +286,7 @@ impl TcpProxy for SocksConnection {
pub struct Socks5Manager { pub struct Socks5Manager {
server: std::net::SocketAddr, server: std::net::SocketAddr,
credentials: Credentials, credentials: Option<Credentials>,
} }
impl ConnectionManager for Socks5Manager { impl ConnectionManager for Socks5Manager {
@ -312,13 +313,13 @@ impl ConnectionManager for Socks5Manager {
self.server self.server
} }
fn get_credentials(&self) -> &Credentials { fn get_credentials(&self) -> &Option<Credentials> {
&self.credentials &self.credentials
} }
} }
impl Socks5Manager { impl Socks5Manager {
pub fn new(server: SocketAddr, credentials: Credentials) -> std::rc::Rc<Self> { pub fn new(server: SocketAddr, credentials: Option<Credentials>) -> std::rc::Rc<Self> {
std::rc::Rc::new(Self { std::rc::Rc::new(Self {
server, server,
credentials, credentials,

View file

@ -164,23 +164,17 @@ struct ConnectionState {
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct Credentials { pub struct Credentials {
pub(crate) authenticate: bool,
pub(crate) username: Vec<u8>, pub(crate) username: Vec<u8>,
pub(crate) password: Vec<u8>, pub(crate) password: Vec<u8>,
} }
impl Credentials { impl Credentials {
pub fn new(username: String, password: String) -> Self { pub fn new(username: &str, password: &str) -> Self {
Self { Self {
authenticate: true,
username: username.as_bytes().to_vec(), username: username.as_bytes().to_vec(),
password: password.as_bytes().to_vec(), password: password.as_bytes().to_vec(),
} }
} }
pub fn none() -> Self {
Default::default()
}
} }
pub(crate) trait TcpProxy { pub(crate) trait TcpProxy {
@ -199,7 +193,7 @@ pub(crate) trait ConnectionManager {
) -> Option<std::boxed::Box<dyn TcpProxy>>; ) -> Option<std::boxed::Box<dyn TcpProxy>>;
fn close_connection(&self, connection: &Connection); fn close_connection(&self, connection: &Connection);
fn get_server(&self) -> SocketAddr; fn get_server(&self) -> SocketAddr;
fn get_credentials(&self) -> &Credentials; fn get_credentials(&self) -> &Option<Credentials>;
} }
pub(crate) struct TunToProxy<'a> { pub(crate) struct TunToProxy<'a> {

1
tests/password.secret Normal file
View file

@ -0,0 +1 @@
JLFE$kz$wJf%&^StSH&D7D5s

View file

@ -140,7 +140,7 @@ mod tests {
} }
Ok(Fork::Child) => { Ok(Fork::Child) => {
prctl::set_death_signal(signal::SIGKILL as isize).unwrap(); // 9 == SIGKILL prctl::set_death_signal(signal::SIGKILL as isize).unwrap(); // 9 == SIGKILL
main_entry(TUN_TEST_DEVICE, address, ProxyType::Socks5); main_entry(TUN_TEST_DEVICE, address, ProxyType::Socks5, None);
} }
Err(_) => assert!(false), Err(_) => assert!(false),
} }