mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-04-25 16:26:04 +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::{
|
use crate::tun2proxy::{
|
||||||
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection,
|
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection,
|
||||||
OutgoingDataEvent, OutgoingDirection, ProxyError, TcpProxy,
|
OutgoingDataEvent, OutgoingDirection, TcpProxy,
|
||||||
};
|
};
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use std::collections::VecDeque;
|
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 {
|
match self.state {
|
||||||
HttpState::ExpectStatusCode if self.server_inbuf.len() >= "HTTP/1.1 200 ".len() => {
|
HttpState::ExpectStatusCode if self.server_inbuf.len() >= "HTTP/1.1 200 ".len() => {
|
||||||
let status_line: Vec<u8> = self
|
let status_line: Vec<u8> = self
|
||||||
|
@ -72,11 +73,9 @@ impl HttpConnection {
|
||||||
{
|
{
|
||||||
let status_str =
|
let status_str =
|
||||||
String::from_utf8_lossy(&status_line.as_slice()[0.."HTTP/1.1 200".len()]);
|
String::from_utf8_lossy(&status_line.as_slice()[0.."HTTP/1.1 200".len()]);
|
||||||
return Err(ProxyError::new(
|
let e =
|
||||||
"Expected success status code. Server replied with ".to_owned()
|
format!("Expected success status code. Server replied with {status_str}.");
|
||||||
+ &*status_str
|
return Err(e.into());
|
||||||
+ ".",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
self.state = HttpState::ExpectResponse;
|
self.state = HttpState::ExpectResponse;
|
||||||
return self.state_change();
|
return self.state_change();
|
||||||
|
@ -118,7 +117,7 @@ impl HttpConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TcpProxy for 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 direction = event.direction;
|
||||||
let buffer = event.buffer;
|
let buffer = event.buffer;
|
||||||
match direction {
|
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::tun2proxy::Credentials;
|
||||||
use crate::{http::HttpManager, socks5::Socks5Manager, tun2proxy::TunToProxy};
|
use crate::{http::HttpManager, socks5::Socks5Manager, tun2proxy::TunToProxy};
|
||||||
use std::net::{SocketAddr, ToSocketAddrs};
|
use std::net::{SocketAddr, ToSocketAddrs};
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
pub mod http;
|
pub mod http;
|
||||||
pub mod socks5;
|
pub mod socks5;
|
||||||
pub mod tun2proxy;
|
pub mod tun2proxy;
|
||||||
|
@ -15,24 +17,23 @@ pub struct Proxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Proxy {
|
impl Proxy {
|
||||||
pub fn from_url(s: &str) -> Result<Proxy, String> {
|
pub fn from_url(s: &str) -> Result<Proxy, Error> {
|
||||||
let url = url::Url::parse(s).map_err(|_| format!("`{s}` is not a valid proxy URL"))?;
|
let e = format!("`{s}` is not a valid proxy URL");
|
||||||
let host = url
|
let url = url::Url::parse(s).map_err(|_| s2e(&e))?;
|
||||||
.host_str()
|
let e = format!("`{s}` does not contain a host");
|
||||||
.ok_or(format!("`{s}` does not contain a host"))?;
|
let host = url.host_str().ok_or(s2e(&e))?;
|
||||||
|
|
||||||
let mut url_host = String::from(host);
|
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(':');
|
||||||
url_host.push_str(port.to_string().as_str());
|
url_host.push_str(port.to_string().as_str());
|
||||||
|
|
||||||
let mut addr_iter = url_host
|
let e = format!("`{host}` could not be resolved");
|
||||||
.to_socket_addrs()
|
let mut addr_iter = url_host.to_socket_addrs().map_err(|_| s2e(&e))?;
|
||||||
.map_err(|_| format!("`{host}` could not be resolved"))?;
|
|
||||||
|
|
||||||
let addr = addr_iter
|
let e = format!("`{host}` does not resolve to a usable IP address");
|
||||||
.next()
|
let addr = addr_iter.next().ok_or(s2e(&e))?;
|
||||||
.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() {
|
||||||
None
|
None
|
||||||
|
@ -49,7 +50,7 @@ impl Proxy {
|
||||||
"http" => Some(ProxyType::Http),
|
"http" => Some(ProxyType::Http),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
.ok_or(format!("`{scheme}` is an invalid proxy type"))?;
|
.ok_or(s2e(&format!("`{scheme}` is an invalid proxy type")))?;
|
||||||
|
|
||||||
Ok(Proxy {
|
Ok(Proxy {
|
||||||
proxy_type,
|
proxy_type,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use crate::error::Error;
|
||||||
use crate::tun2proxy::{
|
use crate::tun2proxy::{
|
||||||
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection,
|
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection,
|
||||||
OutgoingDataEvent, OutgoingDirection, ProxyError, TcpProxy,
|
OutgoingDataEvent, OutgoingDirection, TcpProxy,
|
||||||
};
|
};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
@ -90,22 +91,18 @@ impl SocksConnection {
|
||||||
self.state = SocksState::ServerHello;
|
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 {
|
if self.server_inbuf.len() < 2 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if self.server_inbuf[0] != 5 {
|
if self.server_inbuf[0] != 5 {
|
||||||
return Err(ProxyError::new(
|
return Err("SOCKS server replied with an unexpected version.".into());
|
||||||
"SOCKS server replied with an unexpected version.".into(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.server_inbuf[1] != 0 && self.manager.get_credentials().is_none()
|
if self.server_inbuf[1] != 0 && self.manager.get_credentials().is_none()
|
||||||
|| self.server_inbuf[1] != 2 && self.manager.get_credentials().is_some()
|
|| self.server_inbuf[1] != 2 && self.manager.get_credentials().is_some()
|
||||||
{
|
{
|
||||||
return Err(ProxyError::new(
|
return Err("SOCKS server requires an unsupported authentication method.".into());
|
||||||
"SOCKS server requires an unsupported authentication method.".into(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.server_inbuf.drain(0..2);
|
self.server_inbuf.drain(0..2);
|
||||||
|
@ -118,7 +115,7 @@ impl SocksConnection {
|
||||||
self.state_change()
|
self.state_change()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_auth_data(&mut self) -> Result<(), ProxyError> {
|
fn send_auth_data(&mut self) -> Result<(), Error> {
|
||||||
let tmp = Credentials::default();
|
let tmp = Credentials::default();
|
||||||
let credentials = self.manager.get_credentials().as_ref().unwrap_or(&tmp);
|
let credentials = self.manager.get_credentials().as_ref().unwrap_or(&tmp);
|
||||||
self.server_outbuf
|
self.server_outbuf
|
||||||
|
@ -131,19 +128,19 @@ impl SocksConnection {
|
||||||
self.state_change()
|
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 {
|
if self.server_inbuf.len() < 2 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if self.server_inbuf[0] != 1 || self.server_inbuf[1] != 0 {
|
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.server_inbuf.drain(0..2);
|
||||||
self.state = SocksState::SendRequest;
|
self.state = SocksState::SendRequest;
|
||||||
self.state_change()
|
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 {
|
if self.server_inbuf.len() < 4 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -153,22 +150,18 @@ impl SocksConnection {
|
||||||
let atyp = self.server_inbuf[3];
|
let atyp = self.server_inbuf[3];
|
||||||
|
|
||||||
if ver != 5 {
|
if ver != 5 {
|
||||||
return Err(ProxyError::new(
|
return Err("SOCKS server replied with an unexpected version.".into());
|
||||||
"SOCKS server replied with an unexpected version.".into(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if rep != 0 {
|
if rep != 0 {
|
||||||
return Err(ProxyError::new("SOCKS connection unsuccessful.".into()));
|
return Err("SOCKS connection unsuccessful.".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if atyp != SocksAddressType::Ipv4 as u8
|
if atyp != SocksAddressType::Ipv4 as u8
|
||||||
&& atyp != SocksAddressType::Ipv6 as u8
|
&& atyp != SocksAddressType::Ipv6 as u8
|
||||||
&& atyp != SocksAddressType::DomainName as u8
|
&& atyp != SocksAddressType::DomainName as u8
|
||||||
{
|
{
|
||||||
return Err(ProxyError::new(
|
return Err("SOCKS server replied with unrecognized address type.".into());
|
||||||
"SOCKS server replied with unrecognized address type.".into(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if atyp == SocksAddressType::DomainName as u8 && self.server_inbuf.len() < 5 {
|
if atyp == SocksAddressType::DomainName as u8 && self.server_inbuf.len() < 5 {
|
||||||
|
@ -197,7 +190,7 @@ impl SocksConnection {
|
||||||
self.state_change()
|
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 dst_ip = self.connection.dst.ip();
|
||||||
let cmd = if dst_ip.is_ipv4() { 1 } else { 4 };
|
let cmd = if dst_ip.is_ipv4() { 1 } else { 4 };
|
||||||
self.server_outbuf.extend(&[5u8, 1, 0, cmd]);
|
self.server_outbuf.extend(&[5u8, 1, 0, cmd]);
|
||||||
|
@ -213,7 +206,7 @@ impl SocksConnection {
|
||||||
self.state_change()
|
self.state_change()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state_change(&mut self) -> Result<(), ProxyError> {
|
pub fn state_change(&mut self) -> Result<(), Error> {
|
||||||
match self.state {
|
match self.state {
|
||||||
SocksState::ServerHello => self.receive_server_hello(),
|
SocksState::ServerHello => self.receive_server_hello(),
|
||||||
|
|
||||||
|
@ -239,7 +232,7 @@ impl SocksConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TcpProxy for 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 direction = event.direction;
|
||||||
let buffer = event.buffer;
|
let buffer = event.buffer;
|
||||||
match direction {
|
match direction {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::error::Error;
|
||||||
use crate::virtdevice::VirtualTunDevice;
|
use crate::virtdevice::VirtualTunDevice;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use mio::event::Event;
|
use mio::event::Event;
|
||||||
|
@ -18,20 +19,6 @@ use std::net::Shutdown::Both;
|
||||||
use std::net::{IpAddr, Shutdown, SocketAddr};
|
use std::net::{IpAddr, Shutdown, SocketAddr};
|
||||||
use std::os::unix::io::AsRawFd;
|
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)]
|
#[derive(Hash, Clone, Copy, Eq, PartialEq)]
|
||||||
pub struct Connection {
|
pub struct Connection {
|
||||||
pub src: std::net::SocketAddr,
|
pub src: std::net::SocketAddr,
|
||||||
|
@ -178,7 +165,7 @@ impl Credentials {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait TcpProxy {
|
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 consume_data(&mut self, dir: OutgoingDirection, size: usize);
|
||||||
fn peek_data(&mut self, dir: OutgoingDirection) -> OutgoingDataEvent;
|
fn peek_data(&mut self, dir: OutgoingDirection) -> OutgoingDataEvent;
|
||||||
fn connection_established(&self) -> bool;
|
fn connection_established(&self) -> bool;
|
||||||
|
@ -302,10 +289,6 @@ impl<'a> TunToProxy<'a> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_error(error: ProxyError) {
|
|
||||||
error!("{}", error.message());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tunsocket_read_and_forward(&mut self, connection: &Connection) {
|
fn tunsocket_read_and_forward(&mut self, connection: &Connection) {
|
||||||
if let Some(state) = self.connections.get_mut(connection) {
|
if let Some(state) = self.connections.get_mut(connection) {
|
||||||
let closed = {
|
let closed = {
|
||||||
|
@ -329,7 +312,7 @@ impl<'a> TunToProxy<'a> {
|
||||||
match error {
|
match error {
|
||||||
Ok(_) => socket.state() == smoltcp::socket::tcp::State::CloseWait,
|
Ok(_) => socket.state() == smoltcp::socket::tcp::State::CloseWait,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
Self::print_error(e);
|
log::error!("{e}");
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -512,7 +495,7 @@ impl<'a> TunToProxy<'a> {
|
||||||
socket.close();
|
socket.close();
|
||||||
}
|
}
|
||||||
self.expect_smoltcp_send();
|
self.expect_smoltcp_send();
|
||||||
Self::print_error(error);
|
log::error! {"{error}"};
|
||||||
self.remove_connection(&connection.clone());
|
self.remove_connection(&connection.clone());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue