1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
23
24#[macro_use]
31extern crate amplify;
32
33mod encoding;
34mod error;
35
36use std::io;
37
38use cypheraddr::{Host, HostName, NetAddr};
39pub use error::ServerError;
40
41use crate::encoding::{Encoding, EncodingError, DOMAIN, IPV4, IPV6};
42
43#[derive(Debug, Display, Error, From)]
44#[display(inner)]
45pub enum Error {
46 #[from]
47 Server(ServerError),
48 #[from]
49 Encoding(EncodingError),
50
51 InvalidReply,
53
54 VersionNotSupported(u8),
56
57 AuthRequired,
59
60 Completed,
62
63 Closed,
65}
66
67#[derive(Debug)]
68pub enum Socks5 {
69 Initial(NetAddr<HostName>, bool),
70 Connected(NetAddr<HostName>),
71 Awaiting,
72 Reading(u8, u8),
73 Active(NetAddr<HostName>),
74 Rejected(ServerError, u8, u8),
75 Failed(Error),
76}
77
78impl Socks5 {
79 pub fn with(addr: impl Into<NetAddr<HostName>>, force_proxy: bool) -> Self {
80 Self::Initial(addr.into(), force_proxy)
81 }
82
83 pub fn advance(&mut self, input: &[u8]) -> Result<Vec<u8>, Error> {
84 match self {
85 Socks5::Initial(addr, false) if !addr.requires_proxy() => {
86 *self = Socks5::Active(addr.clone());
87 Ok(vec![])
88 }
89 Socks5::Initial(addr, _) => {
90 debug_assert!(input.is_empty());
91 let out = vec![0x05, 0x01, 0x00];
92 *self = Socks5::Connected(addr.clone());
93 Ok(out)
94 }
95 Socks5::Connected(addr) => {
96 debug_assert_eq!(input.len(), 2);
97 if input[0] != 0x05 {
98 *self = Socks5::Failed(Error::VersionNotSupported(input[0]));
99 return Err(Error::VersionNotSupported(input[0]));
100 }
101 if input[1] != 0x00 {
102 *self = Socks5::Failed(Error::AuthRequired);
103 return Err(Error::AuthRequired);
104 }
105
106 let mut out = vec![0x05, 0x01, 0x00];
107 addr.encode(&mut out)?;
108 *self = Socks5::Awaiting;
109 Ok(out)
110 }
111 Socks5::Awaiting => {
112 debug_assert_eq!(input.len(), 5);
113 if input[0] != 0x05 {
114 *self = Socks5::Failed(Error::VersionNotSupported(input[0]));
115 return Err(Error::VersionNotSupported(input[0]));
116 }
117 if input[1] != 0x00 {
118 let err = ServerError::from(input[1]);
119 *self = Socks5::Rejected(err, input[3], input[4]);
120 } else {
121 *self = Socks5::Reading(input[3], input[4]);
122 }
123 Ok(vec![])
124 }
125 Socks5::Reading(code1, code2) => {
126 let mut vec = Vec::with_capacity(input.len() + 2);
127 vec.extend_from_slice(&[*code1, *code2]);
128 vec.extend_from_slice(input);
129 let mut cursor = io::Cursor::new(vec);
130 let addr = NetAddr::<HostName>::decode(&mut cursor)?;
131 *self = Socks5::Active(addr);
132 Ok(vec![])
133 }
134 Socks5::Active(_) => Err(Error::Completed),
135 Socks5::Rejected(_, _, _) | Socks5::Failed(_) => Err(Error::Closed),
136 }
137 }
138
139 pub fn next_read_len(&self) -> usize {
140 match self {
141 Socks5::Initial(_, _) => 0,
142 Socks5::Connected(_) => 2,
143 Socks5::Awaiting => 5,
144 Socks5::Reading(ty, _) | Socks5::Rejected(_, ty, _) if *ty == IPV4 => 5,
145 Socks5::Reading(ty, _) | Socks5::Rejected(_, ty, _) if *ty == IPV6 => 17,
146 Socks5::Reading(ty, len) | Socks5::Rejected(_, ty, len) if *ty == DOMAIN => {
147 *len as usize + 1
148 }
149 Socks5::Reading(_, _) | Socks5::Rejected(_, _, _) => 1,
150 Socks5::Active(_) | Socks5::Failed(_) => 0,
151 }
152 }
153}