mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-04-25 00:06:05 +00:00
move error handler to a separate module
This commit is contained in:
parent
5cbb13247f
commit
e637a55e6a
5 changed files with 90 additions and 64 deletions
50
src/error.rs
Normal file
50
src/error.rs
Normal 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
|
||||
}
|
||||
}
|
15
src/http.rs
15
src/http.rs
|
@ -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 {
|
||||
|
|
27
src/lib.rs
27
src/lib.rs
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue