swith socks5-impl

This commit is contained in:
ssrlive 2023-07-23 02:03:15 +08:00 committed by B. Blechschmidt
parent ab9f8011f0
commit c61b6c74cd
11 changed files with 163 additions and 301 deletions

View file

@ -1,7 +1,6 @@
#![cfg(target_os = "android")]
use crate::tun2proxy::TunToProxy;
use crate::{error::Error, tun_to_proxy, NetworkInterface, Options, Proxy};
use crate::{error::Error, tun2proxy::TunToProxy, tun_to_proxy, NetworkInterface, Options, Proxy};
use jni::{
objects::{JClass, JString},
sys::{jboolean, jint},

View file

@ -1,19 +1,22 @@
use crate::error::Error;
use crate::tun2proxy::{
Connection, ConnectionManager, Destination, Direction, IncomingDataEvent, IncomingDirection,
OutgoingDataEvent, OutgoingDirection, TcpProxy,
use crate::{
error::Error,
tun2proxy::{
Connection, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection,
OutgoingDataEvent, OutgoingDirection, TcpProxy,
},
};
use crate::Credentials;
use base64::Engine;
use httparse::Response;
use smoltcp::wire::IpProtocol;
use std::cell::RefCell;
use std::collections::hash_map::RandomState;
use std::collections::{HashMap, VecDeque};
use std::iter::FromIterator;
use std::net::SocketAddr;
use std::rc::Rc;
use std::str;
use socks5_impl::protocol::{Address, UserKey};
use std::{
cell::RefCell,
collections::{hash_map::RandomState, HashMap, VecDeque},
iter::FromIterator,
net::SocketAddr,
rc::Rc,
str,
};
use unicase::UniCase;
#[derive(Eq, PartialEq, Debug)]
@ -48,8 +51,8 @@ pub struct HttpConnection {
skip: usize,
digest_state: Rc<RefCell<Option<DigestState>>>,
before: bool,
credentials: Option<Credentials>,
destination: Destination,
credentials: Option<UserKey>,
destination: Address,
}
static PROXY_AUTHENTICATE: &str = "Proxy-Authenticate";
@ -66,11 +69,11 @@ impl HttpConnection {
) -> Result<Self, Error> {
let mut res = Self {
state: HttpState::ExpectResponseHeaders,
client_inbuf: Default::default(),
server_inbuf: Default::default(),
client_outbuf: Default::default(),
server_outbuf: Default::default(),
data_buf: Default::default(),
client_inbuf: VecDeque::default(),
server_inbuf: VecDeque::default(),
client_outbuf: VecDeque::default(),
server_outbuf: VecDeque::default(),
data_buf: VecDeque::default(),
skip: 0,
counter: 0,
crlf_state: 0,
@ -110,7 +113,7 @@ impl HttpConnection {
match scheme {
AuthenticationScheme::Digest => {
let uri = format!("{}:{}", self.destination.host, self.destination.port);
let uri = self.destination.to_string();
let context = digest_auth::AuthContext::new_with_method(
&credentials.username,
@ -386,7 +389,7 @@ impl TcpProxy for HttpConnection {
pub(crate) struct HttpManager {
server: SocketAddr,
credentials: Option<Credentials>,
credentials: Option<UserKey>,
digest_state: Rc<RefCell<Option<DigestState>>>,
}
@ -416,13 +419,13 @@ impl ConnectionManager for HttpManager {
self.server
}
fn get_credentials(&self) -> &Option<Credentials> {
fn get_credentials(&self) -> &Option<UserKey> {
&self.credentials
}
}
impl HttpManager {
pub fn new(server: SocketAddr, credentials: Option<Credentials>) -> Rc<Self> {
pub fn new(server: SocketAddr, credentials: Option<UserKey>) -> Rc<Self> {
Rc::new(Self {
server,
credentials,

View file

@ -1,6 +1,8 @@
use crate::error::Error;
use crate::socks::SocksVersion;
use crate::{http::HttpManager, socks::SocksManager, tun2proxy::TunToProxy};
use crate::{
error::Error, http::HttpManager, socks::SocksManager, socks::SocksVersion,
tun2proxy::TunToProxy,
};
use socks5_impl::protocol::UserKey;
use std::net::{SocketAddr, ToSocketAddrs};
mod android;
@ -16,7 +18,7 @@ mod virtdns;
pub struct Proxy {
pub proxy_type: ProxyType,
pub addr: SocketAddr,
pub credentials: Option<Credentials>,
pub credentials: Option<UserKey>,
}
pub enum NetworkInterface {
@ -48,7 +50,7 @@ impl Proxy {
} else {
let username = String::from(url.username());
let password = String::from(url.password().unwrap_or(""));
Some(Credentials::new(&username, &password))
Some(UserKey::new(username, password))
};
let scheme = url.scheme();
@ -94,7 +96,7 @@ pub struct Options {
impl Options {
pub fn new() -> Self {
Default::default()
Options::default()
}
pub fn with_virtual_dns(mut self) -> Self {
@ -108,21 +110,6 @@ impl Options {
}
}
#[derive(Default, Clone, Debug)]
pub struct Credentials {
pub(crate) username: String,
pub(crate) password: String,
}
impl Credentials {
pub fn new(username: &str, password: &str) -> Self {
Self {
username: String::from(username),
password: String::from(password),
}
}
}
pub fn tun_to_proxy<'a>(
interface: &NetworkInterface,
proxy: &Proxy,

View file

@ -1,12 +1,7 @@
use clap::Parser;
use env_logger::Env;
use std::net::IpAddr;
use std::process::ExitCode;
use tun2proxy::error::Error;
use tun2proxy::{main_entry, Proxy};
use tun2proxy::{NetworkInterface, Options};
use std::{net::IpAddr, process::ExitCode};
use tun2proxy::{error::Error, main_entry, NetworkInterface, Options, Proxy};
#[cfg(target_os = "linux")]
use tun2proxy::setup::{get_default_cidrs, Setup};
@ -45,9 +40,9 @@ struct Args {
#[arg(short, long, value_name = "method", value_enum)]
setup: Option<ArgSetup>,
/// Public proxy IP used in routing setup
/// Public proxy IP used in routing setup which should bypassing the tunnel
#[arg(long, value_name = "IP")]
setup_ip: Option<IpAddr>,
bypass_ip: Option<IpAddr>,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
@ -83,12 +78,12 @@ fn main() -> ExitCode {
}
};
if let Err(e) = (|| -> Result<(), Error> {
let block = || -> Result<(), Error> {
#[cfg(target_os = "linux")]
{
let mut setup: Setup;
if args.setup == Some(ArgSetup::Auto) {
let bypass_tun_ip = match args.setup_ip {
let bypass_tun_ip = match args.bypass_ip {
Some(addr) => addr,
None => args.proxy.addr.ip(),
};
@ -96,7 +91,7 @@ fn main() -> ExitCode {
&args.tun,
&bypass_tun_ip,
get_default_cidrs(),
args.setup_ip.is_some(),
args.bypass_ip.is_some(),
);
setup.configure()?;
@ -108,10 +103,11 @@ fn main() -> ExitCode {
main_entry(&interface, &args.proxy, options)?;
Ok(())
})() {
};
if let Err(e) = block() {
log::error!("{e}");
return ExitCode::FAILURE;
};
}
ExitCode::SUCCESS
}

View file

@ -1,20 +1,17 @@
#![cfg(target_os = "linux")]
use crate::error::Error;
use smoltcp::wire::IpCidr;
use std::convert::TryFrom;
use std::ffi::OsStr;
use std::io::BufRead;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::os::unix::io::RawFd;
use std::process::{Command, Output};
use std::str::FromStr;
use fork::Fork;
use smoltcp::wire::IpCidr;
use std::{
convert::TryFrom,
ffi::OsStr,
io::BufRead,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
os::unix::io::RawFd,
process::{Command, Output},
str::FromStr,
};
#[derive(Clone)]
pub struct Setup {
@ -320,7 +317,7 @@ impl Setup {
if self.tunnel_bypass_addr.is_loopback() && !self.allow_private {
log::warn!(
"The proxy address {} is a loopback address. You may need to manually \
provide --setup-ip to specify the server IP bypassing the tunnel",
provide --bypass-ip to specify the server IP bypassing the tunnel",
self.tunnel_bypass_addr
)
}

View file

@ -1,16 +1,13 @@
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::net::{IpAddr, SocketAddr};
use std::rc::Rc;
use smoltcp::wire::IpProtocol;
use crate::error::Error;
use crate::tun2proxy::{
Connection, ConnectionManager, DestinationHost, Direction, IncomingDataEvent,
IncomingDirection, OutgoingDataEvent, OutgoingDirection, TcpProxy,
use crate::{
error::Error,
tun2proxy::{
Connection, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection,
OutgoingDataEvent, OutgoingDirection, TcpProxy,
},
};
use crate::Credentials;
use smoltcp::wire::IpProtocol;
use socks5_impl::protocol::{self, Address, AddressType, UserKey};
use std::{collections::VecDeque, convert::TryFrom, net::SocketAddr, rc::Rc};
#[derive(Eq, PartialEq, Debug)]
#[allow(dead_code)]
@ -24,32 +21,6 @@ enum SocksState {
Established,
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)]
enum SocksAddressType {
Ipv4 = 1,
DomainName = 3,
Ipv6 = 4,
}
impl TryFrom<u8> for SocksAddressType {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(SocksAddressType::Ipv4),
3 => Ok(SocksAddressType::DomainName),
4 => Ok(SocksAddressType::Ipv6),
_ => Err(format!("Unknown address type: {}", value).into()),
}
}
}
impl From<SocksAddressType> for u8 {
fn from(value: SocksAddressType) -> Self {
value as u8
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum SocksVersion {
@ -57,15 +28,6 @@ pub enum SocksVersion {
V5 = 5,
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)]
#[allow(dead_code)]
pub enum SocksCommand {
Connect = 1,
Bind = 2,
UdpAssociate = 3,
}
#[allow(dead_code)]
enum SocksAuthentication {
None = 0,
@ -105,7 +67,7 @@ pub(crate) struct SocksConnection {
server_outbuf: VecDeque<u8>,
data_buf: VecDeque<u8>,
version: SocksVersion,
credentials: Option<Credentials>,
credentials: Option<UserKey>,
}
impl SocksConnection {
@ -133,22 +95,20 @@ impl SocksConnection {
let credentials = &self.credentials;
match self.version {
SocksVersion::V4 => {
self.server_outbuf.extend(&[
self.version as u8,
SocksCommand::Connect as u8,
(self.connection.dst.port >> 8) as u8,
(self.connection.dst.port & 0xff) as u8,
]);
self.server_outbuf
.extend(&[self.version as u8, protocol::Command::Connect.into()]);
self.server_outbuf
.extend(self.connection.dst.port().to_be_bytes());
let mut ip_vec = Vec::<u8>::new();
let mut name_vec = Vec::<u8>::new();
match &self.connection.dst.host {
DestinationHost::Address(dst_ip) => {
match dst_ip {
IpAddr::V4(ip) => ip_vec.extend(ip.octets().as_ref()),
IpAddr::V6(_) => return Err("SOCKS4 does not support IPv6".into()),
};
match &self.connection.dst {
Address::SocketAddress(SocketAddr::V4(addr)) => {
ip_vec.extend(addr.ip().octets().as_ref());
}
DestinationHost::Hostname(host) => {
Address::SocketAddress(SocketAddr::V6(_)) => {
return Err("SOCKS4 does not support IPv6".into());
}
Address::DomainAddress(host, _) => {
ip_vec.extend(&[0, 0, 0, host.len() as u8]);
name_vec.extend(host.as_bytes());
name_vec.push(0);
@ -246,7 +206,7 @@ impl SocksConnection {
}
fn send_auth_data(&mut self) -> Result<(), Error> {
let tmp = Credentials::default();
let tmp = UserKey::default();
let credentials = self.credentials.as_ref().unwrap_or(&tmp);
self.server_outbuf
.extend(&[1u8, credentials.username.len() as u8]);
@ -287,8 +247,8 @@ impl SocksConnection {
return Err("SOCKS5 connection unsuccessful.".into());
}
let message_length = match SocksAddressType::try_from(atyp)? {
SocksAddressType::DomainName => {
let message_length = match AddressType::try_from(atyp)? {
AddressType::Domain => {
if self.server_inbuf.len() < 5 {
return Ok(());
}
@ -297,8 +257,8 @@ impl SocksConnection {
}
7 + (self.server_inbuf[4] as usize)
}
SocksAddressType::Ipv4 => 10,
SocksAddressType::Ipv6 => 22,
AddressType::IPv4 => 10,
AddressType::IPv6 => 22,
};
self.server_inbuf.drain(0..message_length);
@ -310,30 +270,8 @@ impl SocksConnection {
}
fn send_request(&mut self) -> Result<(), Error> {
self.server_outbuf.extend(&[5u8, 1, 0]);
match &self.connection.dst.host {
DestinationHost::Address(dst_ip) => {
let cmd = if dst_ip.is_ipv4() {
SocksAddressType::Ipv4
} else {
SocksAddressType::Ipv6
};
self.server_outbuf.extend(&[u8::from(cmd)]);
match dst_ip {
IpAddr::V4(ip) => self.server_outbuf.extend(ip.octets().as_ref()),
IpAddr::V6(ip) => self.server_outbuf.extend(ip.octets().as_ref()),
};
}
DestinationHost::Hostname(host) => {
self.server_outbuf
.extend(&[u8::from(SocksAddressType::DomainName), host.len() as u8]);
self.server_outbuf.extend(host.as_bytes());
}
}
self.server_outbuf.extend(&[
(self.connection.dst.port >> 8) as u8,
(self.connection.dst.port & 0xff) as u8,
]);
protocol::Request::new(protocol::Command::Connect, self.connection.dst.clone())
.write_to_stream(&mut self.server_outbuf)?;
self.state = SocksState::ReceiveResponse;
self.state_change()
}
@ -432,7 +370,7 @@ impl TcpProxy for SocksConnection {
pub struct SocksManager {
server: SocketAddr,
credentials: Option<Credentials>,
credentials: Option<UserKey>,
version: SocksVersion,
}
@ -462,7 +400,7 @@ impl ConnectionManager for SocksManager {
self.server
}
fn get_credentials(&self) -> &Option<Credentials> {
fn get_credentials(&self) -> &Option<UserKey> {
&self.credentials
}
}
@ -471,7 +409,7 @@ impl SocksManager {
pub fn new(
server: SocketAddr,
version: SocksVersion,
credentials: Option<Credentials>,
credentials: Option<UserKey>,
) -> Rc<Self> {
Rc::new(Self {
server,

View file

@ -1,91 +1,35 @@
use crate::error::Error;
use crate::virtdevice::VirtualTunDevice;
use crate::{Credentials, NetworkInterface, Options};
use log::{error, info};
use mio::event::Event;
use mio::net::TcpStream;
use mio::unix::SourceFd;
use mio::{Events, Interest, Poll, Token};
use smoltcp::iface::{Config, Interface, SocketHandle, SocketSet};
use smoltcp::phy::{Device, Medium, RxToken, TunTapInterface, TxToken};
use smoltcp::socket::tcp::State;
use smoltcp::socket::udp::UdpMetadata;
use smoltcp::socket::{tcp, udp};
use smoltcp::time::Instant;
use smoltcp::wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket};
use std::collections::{HashMap, HashSet};
use std::convert::{From, TryFrom};
use std::io::{Read, Write};
use std::net::Shutdown::Both;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use std::str::FromStr;
#[derive(Hash, Clone, Eq, PartialEq, Debug)]
pub(crate) enum DestinationHost {
Address(IpAddr),
Hostname(String),
}
impl std::fmt::Display for DestinationHost {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DestinationHost::Address(addr) => addr.fmt(f),
DestinationHost::Hostname(name) => name.fmt(f),
}
}
}
#[derive(Hash, Clone, Eq, PartialEq, Debug)]
pub(crate) struct Destination {
pub(crate) host: DestinationHost,
pub(crate) port: u16,
}
impl TryFrom<Destination> for SocketAddr {
type Error = Error;
fn try_from(value: Destination) -> Result<Self, Self::Error> {
let ip = match value.host {
DestinationHost::Address(addr) => addr,
DestinationHost::Hostname(e) => {
return Err(e.into());
}
};
Ok(SocketAddr::new(ip, value.port))
}
}
impl From<SocketAddr> for Destination {
fn from(addr: SocketAddr) -> Self {
Self {
host: DestinationHost::Address(addr.ip()),
port: addr.port(),
}
}
}
impl std::fmt::Display for Destination {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let DestinationHost::Address(IpAddr::V6(addr)) = self.host {
write!(f, "[{}]:{}", addr, self.port)
} else {
write!(f, "{}:{}", self.host, self.port)
}
}
}
use crate::{error::Error, virtdevice::VirtualTunDevice, NetworkInterface, Options};
use mio::{event::Event, net::TcpStream, unix::SourceFd, Events, Interest, Poll, Token};
use smoltcp::{
iface::{Config, Interface, SocketHandle, SocketSet},
phy::{Device, Medium, RxToken, TunTapInterface, TxToken},
socket::{tcp, tcp::State, udp, udp::UdpMetadata},
time::Instant,
wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket},
};
use socks5_impl::protocol::{Address, UserKey};
use std::{
collections::{HashMap, HashSet},
convert::{From, TryFrom},
io::{Read, Write},
net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, Shutdown::Both, SocketAddr},
os::unix::io::AsRawFd,
rc::Rc,
str::FromStr,
};
#[derive(Hash, Clone, Eq, PartialEq, Debug)]
pub(crate) struct Connection {
pub(crate) src: SocketAddr,
pub(crate) dst: Destination,
pub(crate) dst: Address,
pub(crate) proto: IpProtocol,
}
impl Connection {
fn to_named(&self, name: String) -> Self {
let mut result = self.clone();
result.dst.host = DestinationHost::Hostname(name);
result.dst = Address::from((name, result.dst.port()));
log::trace!("Replace dst \"{}\" -> \"{}\"", self.dst, result.dst);
result
}
}
@ -160,7 +104,7 @@ fn connection_tuple(frame: &[u8]) -> Option<(Connection, bool, usize, usize)> {
if let Ok(packet) = Ipv4Packet::new_checked(frame) {
let proto = packet.next_header();
let mut a: [u8; 4] = Default::default();
let mut a = [0_u8; 4];
a.copy_from_slice(packet.src_addr().as_bytes());
let src_addr = IpAddr::from(a);
a.copy_from_slice(packet.dst_addr().as_bytes());
@ -187,7 +131,7 @@ fn connection_tuple(frame: &[u8]) -> Option<(Connection, bool, usize, usize)> {
// TODO: Support extension headers.
let proto = packet.next_header();
let mut a: [u8; 16] = Default::default();
let mut a = [0_u8; 16];
a.copy_from_slice(packet.src_addr().as_bytes());
let src_addr = IpAddr::from(a);
a.copy_from_slice(packet.dst_addr().as_bytes());
@ -241,7 +185,7 @@ pub(crate) trait ConnectionManager {
) -> Result<Option<Box<dyn TcpProxy>>, Error>;
fn close_connection(&self, connection: &Connection);
fn get_server(&self) -> SocketAddr;
fn get_credentials(&self) -> &Option<Credentials>;
fn get_credentials(&self) -> &Option<UserKey>;
}
const TUN_TOKEN: Token = Token(0);
@ -354,7 +298,7 @@ impl<'a> TunToProxy<'a> {
self.token_to_connection.remove(token);
self.sockets.remove(conn.smoltcp_handle);
_ = self.poll.registry().deregister(&mut conn.mio_stream);
info!("CLOSE {}", connection);
log::info!("CLOSE {}", connection);
}
Ok(())
}
@ -479,9 +423,7 @@ impl<'a> TunToProxy<'a> {
// A raw packet was received on the tunnel interface.
fn receive_tun(&mut self, frame: &mut [u8]) -> Result<(), Error> {
if let Some((connection, first_packet, _payload_offset, _payload_size)) =
connection_tuple(frame)
{
if let Some((connection, first_packet, offset, size)) = connection_tuple(frame) {
let resolved_conn = match &mut self.options.virtdns {
None => connection.clone(),
Some(virt_dns) => {
@ -494,7 +436,7 @@ impl<'a> TunToProxy<'a> {
}
};
let dst = connection.dst;
(|| -> Result<(), Error> {
let handler = || -> Result<(), Error> {
if resolved_conn.proto == IpProtocol::Tcp {
let cm = self.get_connection_manager(&resolved_conn);
if cm.is_none() {
@ -540,7 +482,7 @@ impl<'a> TunToProxy<'a> {
self.connections.insert(resolved_conn.clone(), state);
info!("CONNECT {}", resolved_conn,);
log::info!("CONNECT {}", resolved_conn,);
break;
}
}
@ -562,9 +504,9 @@ impl<'a> TunToProxy<'a> {
// The connection handler builds up the connection or encapsulates the data.
// Therefore, we now expect it to write data to the server.
self.write_to_server(&resolved_conn)?;
} else if resolved_conn.proto == IpProtocol::Udp && resolved_conn.dst.port == 53 {
} else if resolved_conn.proto == IpProtocol::Udp && resolved_conn.dst.port() == 53 {
if let Some(virtual_dns) = &mut self.options.virtdns {
let payload = &frame[_payload_offset.._payload_offset + _payload_size];
let payload = &frame[offset..offset + size];
if let Some(response) = virtual_dns.receive_query(payload) {
let rx_buffer = udp::PacketBuffer::new(
vec![udp::PacketMetadata::EMPTY],
@ -590,12 +532,11 @@ impl<'a> TunToProxy<'a> {
}
// Otherwise, UDP is not yet supported.
}
Ok(())
})()
.or_else(|error| {
log::error! {"{error}"}
Ok::<(), Error>(())
})?;
};
if let Err(error) = handler() {
log::error!("{}", error);
}
}
Ok(())
}
@ -709,7 +650,7 @@ impl<'a> TunToProxy<'a> {
.unwrap()
.get_server();
(|| -> Result<(), Error> {
let mut block = || -> Result<(), Error> {
if event.is_readable() || event.is_read_closed() {
{
let state = self.connections.get_mut(&connection).ok_or(e)?;
@ -721,7 +662,7 @@ impl<'a> TunToProxy<'a> {
Ok(read_result) => read_result,
Err(error) => {
if error.kind() != std::io::ErrorKind::WouldBlock {
error!("Read from proxy: {}", error);
log::error!("Read from proxy: {}", error);
}
vecbuf.len()
}
@ -752,7 +693,7 @@ impl<'a> TunToProxy<'a> {
// Closes the connection with the proxy
state.mio_stream.shutdown(Both)?;
info!("RESET {}", connection);
log::info!("RESET {}", connection);
state.mio_stream = TcpStream::connect(server)?;
@ -785,14 +726,13 @@ impl<'a> TunToProxy<'a> {
if event.is_writable() {
self.write_to_server(&connection)?;
}
Ok(())
})()
.or_else(|error| {
log::error! {"{error}"}
Ok::<(), Error>(())
};
if let Err(error) = block() {
log::error!("{}", error);
self.remove_connection(&connection)?;
Ok(())
})
}
Ok(())
}
fn udp_event(&mut self, _event: &Event) {}
@ -816,10 +756,10 @@ impl<'a> TunToProxy<'a> {
self.send_to_smoltcp()?;
}
Err(e) => {
if e.kind() != std::io::ErrorKind::Interrupted {
return Err(e.into());
if e.kind() == std::io::ErrorKind::Interrupted {
log::warn!("Poll interrupted: \"{e}\", ignored, continue polling");
} else {
log::warn!("Poll interrupted: {e}")
return Err(e.into());
}
}
}

View file

@ -1,6 +1,7 @@
use smoltcp::phy;
use smoltcp::phy::{Device, DeviceCapabilities};
use smoltcp::time::Instant;
use smoltcp::{
phy::{self, Device, DeviceCapabilities},
time::Instant,
};
#[derive(Default)]
pub struct VirtualTunDevice {
@ -72,7 +73,7 @@ impl VirtualTunDevice {
pub fn new(capabilities: DeviceCapabilities) -> Self {
Self {
capabilities,
..Default::default()
..VirtualTunDevice::default()
}
}
}

View file

@ -1,11 +1,12 @@
use hashlink::linked_hash_map::RawEntryMut;
use hashlink::LruCache;
use hashlink::{linked_hash_map::RawEntryMut, LruCache};
use smoltcp::wire::Ipv4Cidr;
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use std::time::{Duration, Instant};
use std::{
collections::HashMap,
convert::{TryFrom, TryInto},
net::{IpAddr, Ipv4Addr, Ipv6Addr},
str::FromStr,
time::{Duration, Instant},
};
const DNS_TTL: u8 = 30; // TTL in DNS replies in seconds
const MAPPING_TIMEOUT: u64 = 60; // Mapping timeout in seconds
@ -43,7 +44,7 @@ impl Default for VirtualDns {
Self {
next_addr: start_addr.into(),
name_to_ip: Default::default(),
name_to_ip: HashMap::default(),
network_addr: IpAddr::try_from(cidr.network().address().into_address()).unwrap(),
broadcast_addr: IpAddr::try_from(cidr.broadcast().unwrap().into_address()).unwrap(),
lru_cache: LruCache::new_unbounded(),
@ -53,7 +54,7 @@ impl Default for VirtualDns {
impl VirtualDns {
pub fn new() -> Self {
Default::default()
VirtualDns::default()
}
pub fn receive_query(&mut self, data: &[u8]) -> Option<Vec<u8>> {
@ -66,18 +67,17 @@ impl VirtualDns {
// bit 7: Message is not truncated (0)
// bit 8: Recursion desired (1)
let is_supported_query = (data[2] & 0b11111011) == 0b00000001;
let num_queries = (data[4] as u16) << 8 | data[5] as u16;
let num_queries = u16::from_be_bytes(data[4..6].try_into().ok()?);
if !is_supported_query || num_queries != 1 {
return None;
}
let result = VirtualDns::parse_qname(data, 12);
let (qname, offset) = result?;
let (qname, offset) = VirtualDns::parse_qname(data, 12)?;
if offset + 3 >= data.len() {
return None;
}
let qtype = (data[offset] as u16) << 8 | data[offset + 1] as u16;
let qclass = (data[offset + 2] as u16) << 8 | data[offset + 3] as u16;
let qtype = u16::from_be_bytes(data[offset..offset + 2].try_into().ok()?);
let qclass = u16::from_be_bytes(data[offset + 2..offset + 4].try_into().ok()?);
if qtype != DnsRecordType::A as u16 && qtype != DnsRecordType::AAAA as u16
|| qclass != DnsClass::IN as u16
@ -121,7 +121,7 @@ impl VirtualDns {
0, 0, 0, DNS_TTL, // TTL
0, 4, // Data length: 4 bytes
]);
match ip as IpAddr {
match ip {
IpAddr::V4(ip) => response.extend(ip.octets().as_ref()),
IpAddr::V6(ip) => response.extend(ip.octets().as_ref()),
};
@ -191,11 +191,10 @@ impl VirtualDns {
let now = Instant::now();
loop {
let p = self.lru_cache.iter().next();
if p.is_none() {
break;
}
let (ip, entry) = p.unwrap();
let (ip, entry) = match self.lru_cache.iter().next() {
None => break,
Some((ip, entry)) => (ip, entry),
};
if now > entry.expiry {
let name = entry.name.clone();
self.lru_cache.remove(&ip.clone());