inn_network/codec/
socks.rs

1use byteorder::BigEndian;
2use byteorder::ByteOrder;
3use bytes::BytesMut;
4
5use crate::server::ProxyServer;
6
7use super::AuthChoice;
8use super::Cmd;
9use super::DstAddress;
10use super::T;
11//-------------------------------------------------------------------
12// MIT License
13// Copyright (c) 2022 black-mongo
14// @author CameronYang
15// @doc
16//
17// @end
18// Created : 2022-04-19T09:49:23+08:00
19//-------------------------------------------------------------------
20use super::VisitorDecoder;
21use super::VisitorRequest;
22
23use super::Proto;
24use super::State;
25use std::io::{Error, ErrorKind};
26pub(crate) struct SocksCodec {
27    pub state: State,
28}
29impl Default for SocksCodec {
30    fn default() -> Self {
31        SocksCodec {
32            state: State::Undefined,
33        }
34    }
35}
36
37impl VisitorDecoder for SocksCodec {
38    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<VisitorRequest>, Error> {
39        if src.len() < 3 {
40            return Ok(None);
41        }
42        match &self.state {
43            State::Undefined => {
44                let buf = src.as_ref();
45                if buf[0] == 0x05 {
46                    let nauth = buf[1] as usize;
47                    if src.len() < (nauth + 2) {
48                        Ok(None)
49                    } else {
50                        let _ = src.split_to(2);
51                        let buf = src.split_to(nauth as usize);
52                        self.state = State::Auth;
53                        match ProxyServer::auth_choice(&buf.to_vec()) {
54                            AuthChoice::NoAcceptable => self.state = State::Greeting,
55                            AuthChoice::UserNamePwd => self.state = State::Greeting,
56                            AuthChoice::NoAuth => self.state = State::Auth,
57                        }
58                        Ok(Some(VisitorRequest::Greeting {
59                            proto: Proto::Socks5,
60                            auth: buf.to_vec(),
61                        }))
62                    }
63                } else {
64                    let msg: String = "Invalid socks5 protocol".into();
65                    Err(Error::new(ErrorKind::Other, msg))
66                }
67            }
68            State::Greeting => {
69                // remove ver 0x05
70                if src.len() < 2 {
71                    return Ok(None);
72                }
73                let buf = src.as_ref();
74                let id_len = buf[1] as usize;
75                if src.len() < id_len + 3 {
76                    return Ok(None);
77                }
78                let pwd_len = buf[id_len + 2] as usize;
79                if src.len() < pwd_len + id_len + 3 {
80                    return Ok(None);
81                }
82                let _ = src.split_to(2);
83                let id = src.split_to(id_len);
84                let _ = src.split_to(1);
85                let pwd = src.split_to(pwd_len);
86                self.state = State::Auth;
87                Ok(Some(VisitorRequest::Auth {
88                    id: String::from_utf8(id.to_vec()).unwrap(),
89                    pwd: String::from_utf8(pwd.to_vec()).unwrap(),
90                }))
91            }
92            State::Auth => {
93                // Client connection Request
94                if src.len() < 5 {
95                    return Ok(None);
96                }
97                let buf = src.as_ref();
98                if buf[1] != 0x01 {
99                    return Err(Error::new(
100                        ErrorKind::Other,
101                        "Client connection Request only support stream Connection",
102                    ));
103                }
104                let addr_type = buf[3];
105                match addr_type {
106                    // IPV4
107                    0x01 => {
108                        if src.len() < 10 {
109                            return Ok(None);
110                        }
111                        let _ = src.split_to(4);
112                        let ip = src.split_to(4);
113                        let port = BigEndian::read_u16(src.as_ref());
114                        self.state = State::Forward;
115                        let _ = src.split_to(2);
116                        return Ok(Some(VisitorRequest::Connection {
117                            cmd: Cmd::Connection,
118                            address: DstAddress::new(
119                                T::IPv4,
120                                &format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3]),
121                                port,
122                            ),
123                        }));
124                    }
125                    // Domain
126                    0x03 => {
127                        let name_len = buf[4] as usize;
128                        if src.len() < name_len + 7 {
129                            return Ok(None);
130                        }
131                        let _ = src.split_to(5);
132                        let name = src.split_to(name_len);
133                        let port = BigEndian::read_u16(src.as_ref());
134                        let _ = src.split_to(2);
135                        self.state = State::Forward;
136                        if let Ok(name) = String::from_utf8(name.to_vec()) {
137                            Ok(Some(VisitorRequest::Connection {
138                                cmd: Cmd::Connection,
139                                address: DstAddress::new(T::Domain, &name, port),
140                            }))
141                        } else {
142                            Err(Error::new(
143                                ErrorKind::Other,
144                                "Client connection Request Domain invalid",
145                            ))
146                        }
147                    }
148                    _ => Err(Error::new(
149                        ErrorKind::Other,
150                        "Client connection Request only support IPv4 or Domain",
151                    )),
152                }
153            }
154            // forward
155            State::Forward => Ok(Some(VisitorRequest::Forward(
156                src.split_to(src.len()).to_vec(),
157            ))),
158        }
159    }
160}