use core::convert::TryFrom;
use core::fmt;
use bytes::BytesMut;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use snafu::Snafu;
pub use addr::{Addr as SocksAddr, HasAddr};
pub use cmd_rep::{CmdRepr, Packet as CmdPacket, Packet as RepPacket, RepRepr};
pub use method_selection::{
ReplyPacket as MethodPacket, ReplyRepr as MethodRepr, RequestPacket as MethodsPacket,
RequestRepr as MethodsRepr,
};
pub use rfc1929::{
ReplyPacket as AuthReplyPacket, ReplyRepr as AuthReplyRepr, RequestPacket as UserPassPacket,
RequestRepr as UserPassRepr, Status, Ver as Rfc1929Ver,
};
pub use udp::{Frag as UdpFrag, Packet as UdpPacket, Repr as UdpRepr};
mod addr;
mod cmd_rep;
mod method_selection;
mod rfc1929;
mod udp;
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
Malformed,
Truncated,
#[cfg(not(all(feature = "proto-ipv4", feature = "proto-ipv6")))]
UnsupportedAtyp,
AddrParseError,
}
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:#?}", self)
}
}
impl From<std::str::Utf8Error> for Error {
fn from(_val: std::str::Utf8Error) -> Self {
Error::Malformed
}
}
impl From<smolsocket::Error> for Error {
fn from(_val: smolsocket::Error) -> Self {
Error::AddrParseError
}
}
pub(crate) type Result<T> = core::result::Result<T, Error>;
mod field {
use crate::field::*;
pub const VER: usize = 0;
pub const NMETHODS: usize = 1;
pub const METHODS: Rest = 2..;
pub fn methods(nmethods: u8) -> Field {
2..2 + nmethods as usize
}
pub const METHOD: usize = 1;
pub const CMD_OR_REP: usize = 1;
pub const RSV: usize = 2;
pub const ATYP: usize = 3;
pub const ADDR_PORT: Rest = 4..;
pub const UDP_RSV: Field = 0..2;
pub const UDP_FRAG: usize = 2;
pub const ULEN: usize = 1;
pub const UNAME_PLEN_PASSWD: Rest = 2..;
pub const STATUS: usize = 1;
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, FromPrimitive, Hash, PartialEq, Serialize, Snafu)]
#[repr(u8)]
pub enum Ver {
#[snafu(display("Socks4"))]
SOCKS4 = 0x04,
#[snafu(display("Socks5"))]
SOCKS5 = 0x05,
}
impl TryFrom<u8> for Ver {
type Error = Error;
fn try_from(val: u8) -> Result<Self> {
FromPrimitive::from_u8(val).ok_or(Error::Malformed)
}
}
impl Into<u8> for &Ver {
fn into(self) -> u8 {
*self as u8
}
}
impl From<Ver> for u8 {
fn from(val: Ver) -> Self {
val as u8
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, FromPrimitive, Hash, PartialEq, Serialize, Snafu)]
#[repr(u8)]
pub enum Method {
#[snafu(display("NO AUTHENTICATION REQUIRED"))]
NoAuth = 0x00,
#[snafu(display("GSSAPI"))]
GssApi = 0x01,
#[snafu(display("USERNAME/PASSWORD"))]
UserPass = 0x02,
#[snafu(display("NO ACCEPTABLE METHODS"))]
NoMethods = 0xFF,
}
impl Method {
pub fn try_from_slice(methods: &[u8]) -> Result<Vec<Method>> {
let mut result = Vec::with_capacity(methods.len());
for var in methods {
result.push(Method::try_from(*var)?);
}
Ok(result)
}
}
impl TryFrom<u8> for Method {
type Error = Error;
fn try_from(val: u8) -> Result<Self> {
FromPrimitive::from_u8(val).ok_or(Error::Malformed)
}
}
impl From<Method> for u8 {
fn from(val: Method) -> Self {
val as u8
}
}
impl From<&Method> for u8 {
fn from(val: &Method) -> Self {
*val as u8
}
}
trait ToU8Vec<T> {
fn to_u8_vec(&self) -> Vec<u8>;
}
impl ToU8Vec<Method> for &[Method] {
fn to_u8_vec(&self) -> Vec<u8> {
self.iter().map(|&m| m as u8).collect()
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, FromPrimitive, Hash, PartialEq, Serialize, Snafu)]
#[repr(u8)]
pub enum Cmd {
#[snafu(display("Connect"))]
Connect = 0x01,
#[snafu(display("Bind"))]
Bind = 0x02,
#[snafu(display("UDP associate"))]
UdpAssociate = 0x03,
}
impl TryFrom<u8> for Cmd {
type Error = Error;
fn try_from(val: u8) -> Result<Self> {
FromPrimitive::from_u8(val).ok_or(Error::Malformed)
}
}
impl From<Cmd> for u8 {
fn from(val: Cmd) -> Self {
val as u8
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, FromPrimitive, Hash, PartialEq, Serialize, Snafu)]
#[repr(u8)]
pub enum Atyp {
#[snafu(display("IPv4"))]
V4 = 0x01,
#[snafu(display("Domain"))]
Domain = 0x03,
#[snafu(display("IPv6"))]
V6 = 0x04,
}
impl TryFrom<u8> for Atyp {
type Error = Error;
fn try_from(val: u8) -> Result<Self> {
FromPrimitive::from_u8(val).ok_or(Error::Malformed)
}
}
impl From<Atyp> for u8 {
fn from(val: Atyp) -> Self {
val as u8
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, FromPrimitive, Hash, PartialEq, Serialize, Snafu)]
#[repr(u8)]
pub enum Rep {
#[snafu(display("Succeeded"))]
Success = 0x00,
#[snafu(display("General SOCKS server failure"))]
Failure = 0x01,
#[snafu(display("Connection not allowed by ruleset"))]
RuleFailure = 0x02,
#[snafu(display("Network unreachable"))]
NetworkUnreachable = 0x03,
#[snafu(display("Host unreachable"))]
HostUnreachable = 0x04,
#[snafu(display("Connection refused"))]
ConnectionRefused = 0x05,
#[snafu(display("TTL expired"))]
TtlExpired = 0x06,
#[snafu(display("Command not supported"))]
CommandNotSupported = 0x07,
#[snafu(display("Address type not supported"))]
AddrTypeNotSupported = 0x08,
}
impl TryFrom<u8> for Rep {
type Error = Error;
fn try_from(val: u8) -> Result<Self> {
FromPrimitive::from_u8(val).ok_or(Error::Malformed)
}
}
impl From<Rep> for u8 {
fn from(val: Rep) -> Self {
val as u8
}
}
pub(crate) trait Encodable {
fn encode_into(&self, dst: &mut BytesMut);
}
pub trait Encoder<Item> {
fn encode(item: &Item, dst: &mut BytesMut);
}
pub trait Decoder<Item> {
fn decode(src: &mut BytesMut) -> Result<Option<Item>>;
}