move error handler to a separate module

This commit is contained in:
ssrlive 2023-03-22 22:19:00 +08:00 committed by B. Blechschmidt
parent 5cbb13247f
commit e637a55e6a
5 changed files with 90 additions and 64 deletions

50
src/error.rs Normal file
View file

@ -0,0 +1,50 @@
#[derive(Debug)]
pub struct Error {
message: String,
}
pub fn s2e(s: &str) -> Error {
Error::from(s)
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Self {
message: err.to_string(),
}
}
}
impl From<&str> for Error {
fn from(err: &str) -> Self {
Self {
message: err.to_string(),
}
}
}
impl From<String> for Error {
fn from(err: String) -> Self {
Self { message: err }
}
}
impl From<&String> for Error {
fn from(err: &String) -> Self {
Self {
message: err.to_string(),
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
&self.message
}
}

View file

@ -1,6 +1,7 @@
use crate::error::Error;
use crate::tun2proxy::{
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection,
OutgoingDataEvent, OutgoingDirection, ProxyError, TcpProxy,
OutgoingDataEvent, OutgoingDirection, TcpProxy,
};
use base64::Engine;
use std::collections::VecDeque;
@ -58,7 +59,7 @@ impl HttpConnection {
}
}
fn state_change(&mut self) -> Result<(), ProxyError> {
fn state_change(&mut self) -> Result<(), Error> {
match self.state {
HttpState::ExpectStatusCode if self.server_inbuf.len() >= "HTTP/1.1 200 ".len() => {
let status_line: Vec<u8> = self
@ -72,11 +73,9 @@ impl HttpConnection {
{
let status_str =
String::from_utf8_lossy(&status_line.as_slice()[0.."HTTP/1.1 200".len()]);
return Err(ProxyError::new(
"Expected success status code. Server replied with ".to_owned()
+ &*status_str
+ ".",
));
let e =
format!("Expected success status code. Server replied with {status_str}.");
return Err(e.into());
}
self.state = HttpState::ExpectResponse;
return self.state_change();
@ -118,7 +117,7 @@ impl HttpConnection {
}
impl TcpProxy for HttpConnection {
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), ProxyError> {
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), Error> {
let direction = event.direction;
let buffer = event.buffer;
match direction {

View file

@ -1,7 +1,9 @@
use crate::error::{s2e, Error};
use crate::tun2proxy::Credentials;
use crate::{http::HttpManager, socks5::Socks5Manager, tun2proxy::TunToProxy};
use std::net::{SocketAddr, ToSocketAddrs};
pub mod error;
pub mod http;
pub mod socks5;
pub mod tun2proxy;
@ -15,24 +17,23 @@ pub struct Proxy {
}
impl Proxy {
pub fn from_url(s: &str) -> Result<Proxy, String> {
let url = url::Url::parse(s).map_err(|_| format!("`{s}` is not a valid proxy URL"))?;
let host = url
.host_str()
.ok_or(format!("`{s}` does not contain a host"))?;
pub fn from_url(s: &str) -> Result<Proxy, Error> {
let e = format!("`{s}` is not a valid proxy URL");
let url = url::Url::parse(s).map_err(|_| s2e(&e))?;
let e = format!("`{s}` does not contain a host");
let host = url.host_str().ok_or(s2e(&e))?;
let mut url_host = String::from(host);
let port = url.port().ok_or(format!("`{s}` does not contain a port"))?;
let e = format!("`{s}` does not contain a port");
let port = url.port().ok_or(s2e(&e))?;
url_host.push(':');
url_host.push_str(port.to_string().as_str());
let mut addr_iter = url_host
.to_socket_addrs()
.map_err(|_| format!("`{host}` could not be resolved"))?;
let e = format!("`{host}` could not be resolved");
let mut addr_iter = url_host.to_socket_addrs().map_err(|_| s2e(&e))?;
let addr = addr_iter
.next()
.ok_or(format!("`{host}` does not resolve to a usable IP address"))?;
let e = format!("`{host}` does not resolve to a usable IP address");
let addr = addr_iter.next().ok_or(s2e(&e))?;
let credentials = if url.username() == "" && url.password().is_none() {
None
@ -49,7 +50,7 @@ impl Proxy {
"http" => Some(ProxyType::Http),
_ => None,
}
.ok_or(format!("`{scheme}` is an invalid proxy type"))?;
.ok_or(s2e(&format!("`{scheme}` is an invalid proxy type")))?;
Ok(Proxy {
proxy_type,

View file

@ -1,6 +1,7 @@
use crate::error::Error;
use crate::tun2proxy::{
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection,
OutgoingDataEvent, OutgoingDirection, ProxyError, TcpProxy,
OutgoingDataEvent, OutgoingDirection, TcpProxy,
};
use std::collections::VecDeque;
use std::net::{IpAddr, SocketAddr};
@ -90,22 +91,18 @@ impl SocksConnection {
self.state = SocksState::ServerHello;
}
fn receive_server_hello(&mut self) -> Result<(), ProxyError> {
fn receive_server_hello(&mut self) -> Result<(), Error> {
if self.server_inbuf.len() < 2 {
return Ok(());
}
if self.server_inbuf[0] != 5 {
return Err(ProxyError::new(
"SOCKS server replied with an unexpected version.".into(),
));
return Err("SOCKS server replied with an unexpected version.".into());
}
if self.server_inbuf[1] != 0 && self.manager.get_credentials().is_none()
|| self.server_inbuf[1] != 2 && self.manager.get_credentials().is_some()
{
return Err(ProxyError::new(
"SOCKS server requires an unsupported authentication method.".into(),
));
return Err("SOCKS server requires an unsupported authentication method.".into());
}
self.server_inbuf.drain(0..2);
@ -118,7 +115,7 @@ impl SocksConnection {
self.state_change()
}
fn send_auth_data(&mut self) -> Result<(), ProxyError> {
fn send_auth_data(&mut self) -> Result<(), Error> {
let tmp = Credentials::default();
let credentials = self.manager.get_credentials().as_ref().unwrap_or(&tmp);
self.server_outbuf
@ -131,19 +128,19 @@ impl SocksConnection {
self.state_change()
}
fn receive_auth_data(&mut self) -> Result<(), ProxyError> {
fn receive_auth_data(&mut self) -> Result<(), Error> {
if self.server_inbuf.len() < 2 {
return Ok(());
}
if self.server_inbuf[0] != 1 || self.server_inbuf[1] != 0 {
return Err(ProxyError::new("SOCKS authentication failed.".into()));
return Err("SOCKS authentication failed.".into());
}
self.server_inbuf.drain(0..2);
self.state = SocksState::SendRequest;
self.state_change()
}
fn receive_connection_status(&mut self) -> Result<(), ProxyError> {
fn receive_connection_status(&mut self) -> Result<(), Error> {
if self.server_inbuf.len() < 4 {
return Ok(());
}
@ -153,22 +150,18 @@ impl SocksConnection {
let atyp = self.server_inbuf[3];
if ver != 5 {
return Err(ProxyError::new(
"SOCKS server replied with an unexpected version.".into(),
));
return Err("SOCKS server replied with an unexpected version.".into());
}
if rep != 0 {
return Err(ProxyError::new("SOCKS connection unsuccessful.".into()));
return Err("SOCKS connection unsuccessful.".into());
}
if atyp != SocksAddressType::Ipv4 as u8
&& atyp != SocksAddressType::Ipv6 as u8
&& atyp != SocksAddressType::DomainName as u8
{
return Err(ProxyError::new(
"SOCKS server replied with unrecognized address type.".into(),
));
return Err("SOCKS server replied with unrecognized address type.".into());
}
if atyp == SocksAddressType::DomainName as u8 && self.server_inbuf.len() < 5 {
@ -197,7 +190,7 @@ impl SocksConnection {
self.state_change()
}
fn send_request(&mut self) -> Result<(), ProxyError> {
fn send_request(&mut self) -> Result<(), Error> {
let dst_ip = self.connection.dst.ip();
let cmd = if dst_ip.is_ipv4() { 1 } else { 4 };
self.server_outbuf.extend(&[5u8, 1, 0, cmd]);
@ -213,7 +206,7 @@ impl SocksConnection {
self.state_change()
}
pub fn state_change(&mut self) -> Result<(), ProxyError> {
pub fn state_change(&mut self) -> Result<(), Error> {
match self.state {
SocksState::ServerHello => self.receive_server_hello(),
@ -239,7 +232,7 @@ impl SocksConnection {
}
impl TcpProxy for SocksConnection {
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), ProxyError> {
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), Error> {
let direction = event.direction;
let buffer = event.buffer;
match direction {

View file

@ -1,3 +1,4 @@
use crate::error::Error;
use crate::virtdevice::VirtualTunDevice;
use log::{error, info};
use mio::event::Event;
@ -18,20 +19,6 @@ use std::net::Shutdown::Both;
use std::net::{IpAddr, Shutdown, SocketAddr};
use std::os::unix::io::AsRawFd;
pub struct ProxyError {
message: String,
}
impl ProxyError {
pub fn new(message: String) -> Self {
Self { message }
}
pub fn message(&self) -> String {
self.message.clone()
}
}
#[derive(Hash, Clone, Copy, Eq, PartialEq)]
pub struct Connection {
pub src: std::net::SocketAddr,
@ -178,7 +165,7 @@ impl Credentials {
}
pub(crate) trait TcpProxy {
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), ProxyError>;
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), Error>;
fn consume_data(&mut self, dir: OutgoingDirection, size: usize);
fn peek_data(&mut self, dir: OutgoingDirection) -> OutgoingDataEvent;
fn connection_established(&self) -> bool;
@ -302,10 +289,6 @@ impl<'a> TunToProxy<'a> {
None
}
fn print_error(error: ProxyError) {
error!("{}", error.message());
}
fn tunsocket_read_and_forward(&mut self, connection: &Connection) {
if let Some(state) = self.connections.get_mut(connection) {
let closed = {
@ -329,7 +312,7 @@ impl<'a> TunToProxy<'a> {
match error {
Ok(_) => socket.state() == smoltcp::socket::tcp::State::CloseWait,
Err(e) => {
Self::print_error(e);
log::error!("{e}");
true
}
}
@ -512,7 +495,7 @@ impl<'a> TunToProxy<'a> {
socket.close();
}
self.expect_smoltcp_send();
Self::print_error(error);
log::error! {"{error}"};
self.remove_connection(&connection.clone());
return;
}