inn_network/codec/
mod.rs

1//-------------------------------------------------------------------
2// MIT License
3// Copyright (c) 2022 black-mongo
4// @author CameronYang
5// @doc
6//
7// @end
8// Created : 2022-04-15T16:32:29+08:00
9//-------------------------------------------------------------------
10use actix_codec::Decoder;
11use actix_codec::Encoder;
12use actix_web::web::BytesMut;
13use byteorder::BigEndian;
14use byteorder::ByteOrder;
15use log::trace;
16use std::io::Error;
17use std::io::ErrorKind;
18
19use crate::codec::cli::CliCodec;
20use crate::codec::socks::SocksCodec;
21mod cli;
22pub mod forward;
23pub mod socks;
24trait VisitorDecoder {
25    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<VisitorRequest>, Error>;
26}
27pub struct VisitorCodec {
28    proto: Proto,
29    handler: Option<Box<dyn VisitorDecoder>>,
30}
31impl Default for VisitorCodec {
32    fn default() -> Self {
33        VisitorCodec {
34            proto: Proto::Undefined,
35            handler: None,
36        }
37    }
38}
39#[allow(dead_code)]
40#[derive(Debug, PartialEq, Clone)]
41pub(crate) enum State {
42    Undefined,
43    Greeting,
44    Auth,
45    Forward,
46}
47#[derive(Debug, PartialEq, Clone)]
48pub enum Proto {
49    Undefined,
50    Socks5,
51    Cli,
52}
53#[derive(Debug, PartialEq)]
54pub enum Cmd {
55    Connection,
56    Binding,
57    AssociateUdp,
58}
59#[derive(Debug, PartialEq, Clone)]
60pub enum T {
61    IPv4,
62    Domain,
63}
64#[derive(Debug, PartialEq, Clone)]
65pub struct DstAddress {
66    pub(crate) t: T,
67    pub(crate) addr: String,
68    pub(crate) port: u16,
69}
70impl DstAddress {
71    pub fn new(t: T, addr: &str, port: u16) -> Self {
72        DstAddress {
73            t,
74            addr: addr.into(),
75            port,
76        }
77    }
78}
79impl DstAddress {
80    fn port(&self) -> Vec<u8> {
81        let mut rs = [0; 2];
82        BigEndian::write_u16(&mut rs, self.port);
83        rs.to_vec()
84    }
85    fn address(&self) -> Vec<u8> {
86        let mut rs = vec![];
87        match self.t {
88            T::IPv4 => {
89                rs.push(0x01);
90                for row in self.addr.split('.') {
91                    rs.push(row.parse::<u8>().unwrap());
92                }
93            }
94            T::Domain => {
95                rs.push(0x03);
96                rs.push(self.addr.len() as u8);
97                rs.extend(self.addr.as_bytes());
98            }
99        }
100        rs
101    }
102}
103impl From<DstAddress> for Vec<u8> {
104    fn from(addr: DstAddress) -> Vec<u8> {
105        let mut rs = vec![];
106        rs.extend(addr.address());
107        rs.extend(addr.port());
108        rs
109    }
110}
111#[derive(Debug, PartialEq)]
112pub enum VisitorRequest {
113    Greeting { proto: Proto, auth: Vec<u8> },
114    Auth { id: String, pwd: String },
115    Connection { cmd: Cmd, address: DstAddress },
116    Forward(Vec<u8>),
117    Cli(inn_common::cli::Cli),
118}
119#[derive(Debug, PartialEq)]
120pub enum AuthChoice {
121    NoAuth,
122    UserNamePwd,
123    NoAcceptable,
124}
125impl From<AuthChoice> for u8 {
126    fn from(choice: AuthChoice) -> u8 {
127        match choice {
128            AuthChoice::NoAcceptable => 0xFF,
129            AuthChoice::UserNamePwd => 0x02,
130            AuthChoice::NoAuth => 0x00,
131        }
132    }
133}
134impl From<u8> for AuthChoice {
135    fn from(v: u8) -> Self {
136        match v {
137            0x02 => AuthChoice::UserNamePwd,
138            0x00 => AuthChoice::NoAuth,
139            _ => AuthChoice::NoAcceptable,
140        }
141    }
142}
143#[derive(Debug, PartialEq, Clone)]
144pub enum BindStatus {
145    Granted,
146    Failure,
147    NotAllowedRuleSet,
148    NetWorkUnReachable,
149    HostUnReachable,
150    ConnectionRefuse,
151    TTLExpired,
152    CommandNotSupported,
153    AddressTypeNotSupported,
154}
155impl From<BindStatus> for u8 {
156    fn from(status: BindStatus) -> u8 {
157        match status {
158            BindStatus::Granted => 0x00,
159            BindStatus::Failure => 0x01,
160            BindStatus::NotAllowedRuleSet => 0x02,
161            BindStatus::NetWorkUnReachable => 0x03,
162            BindStatus::HostUnReachable => 0x04,
163            BindStatus::ConnectionRefuse => 0x05,
164            BindStatus::TTLExpired => 0x06,
165            BindStatus::CommandNotSupported => 0x07,
166            BindStatus::AddressTypeNotSupported => 0x08,
167        }
168    }
169}
170#[derive(Debug, PartialEq)]
171pub enum VisitorResponse {
172    Choice(AuthChoice),
173    AuthRespSuccess,
174    AuthRespError,
175    BindResp {
176        status: BindStatus,
177        address: Option<DstAddress>,
178    },
179    Forward(Vec<u8>),
180    Cli(inn_common::cli::Cli),
181}
182impl From<VisitorResponse> for Vec<u8> {
183    #[allow(clippy::vec_init_then_push)]
184    fn from(resp: VisitorResponse) -> Vec<u8> {
185        match resp {
186            VisitorResponse::Choice(choice) => {
187                let mut rs = vec![];
188                rs.push(0x5);
189                rs.push(choice.into());
190                rs
191            }
192            VisitorResponse::AuthRespSuccess => {
193                vec![0x5, 0x00]
194            }
195            VisitorResponse::AuthRespError => {
196                vec![0x5, 0x01]
197            }
198            VisitorResponse::BindResp { status, address } => {
199                let mut rs = vec![];
200                rs.push(0x05);
201                rs.push(status.clone().into());
202                if status == BindStatus::Granted {
203                    if let Some(address) = address {
204                        rs.push(0x00);
205                        let addr: Vec<u8> = address.into();
206                        rs.extend(addr);
207                    }
208                }
209                rs
210            }
211            VisitorResponse::Forward(data) => data,
212            VisitorResponse::Cli(cli) => cli.into(),
213        }
214    }
215}
216impl Decoder for VisitorCodec {
217    type Item = VisitorRequest;
218    type Error = Error;
219    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
220        trace!("Client data:{:?}", src.to_vec());
221        if src.is_empty() {
222            return Ok(None);
223        }
224        // check_proto
225        if self.proto == Proto::Undefined {
226            if src.as_ref()[0] == 0x05 {
227                self.proto = Proto::Socks5;
228                self.handler = Some(Box::new(SocksCodec::default()))
229            } else if src.as_ref()[0] == b'*'
230                || src.as_ref()[0] == b'+'
231                || src.as_ref()[0] == b'-'
232                || src.as_ref()[0] == b':'
233                || src.as_ref()[0] == b'$'
234            {
235                self.proto = Proto::Cli;
236                self.handler = Some(Box::new(CliCodec::default()))
237            }
238        }
239        match &mut self.handler {
240            Some(handler) => handler.decode(src),
241            _ => Err(Error::new(ErrorKind::Other, "Invalid protocol")),
242        }
243    }
244}
245impl Encoder<VisitorResponse> for VisitorCodec {
246    type Error = Error;
247    fn encode(&mut self, item: VisitorResponse, dst: &mut BytesMut) -> Result<(), Self::Error> {
248        trace!("proto={:?}, VisitorResponse = {:?}", self.proto, item);
249        let buf: Vec<u8> = item.into();
250        dst.extend_from_slice(buf.as_slice());
251        Ok(())
252    }
253}
254
255#[cfg(test)]
256mod test {
257    use super::*;
258    #[test]
259    fn visitor_response_encode() {
260        check_visitor_response(VisitorResponse::AuthRespError, vec![0x05, 0x01]);
261        check_visitor_response(VisitorResponse::AuthRespSuccess, vec![0x05, 0x00]);
262        check_visitor_response(
263            VisitorResponse::Choice(AuthChoice::NoAuth),
264            vec![0x05, 0x00],
265        );
266        check_visitor_response(
267            VisitorResponse::Choice(AuthChoice::UserNamePwd),
268            vec![0x05, 0x02],
269        );
270        check_visitor_response(
271            VisitorResponse::Choice(AuthChoice::NoAcceptable),
272            vec![0x05, 0xFF],
273        );
274        check_visitor_response(
275            VisitorResponse::BindResp {
276                status: BindStatus::Failure,
277                address: None,
278            },
279            vec![0x05, 0x01],
280        );
281        check_visitor_response(
282            VisitorResponse::BindResp {
283                status: BindStatus::Granted,
284                address: Some(DstAddress::new(T::IPv4, "127.0.0.1", 80)),
285            },
286            vec![0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0, 80],
287        );
288        check_visitor_response(
289            VisitorResponse::BindResp {
290                status: BindStatus::Granted,
291                address: Some(DstAddress::new(T::Domain, "abc", 80)),
292            },
293            vec![0x05, 0x00, 0x00, 0x03, 0x03, 97, 98, 99, 0, 80],
294        );
295        check_visitor_response(
296            VisitorResponse::Forward(vec![1, 2, 3, 4, 5]),
297            vec![1, 2, 3, 4, 5],
298        );
299    }
300    fn check_visitor_response(resp: VisitorResponse, expected: Vec<u8>) {
301        let rs: Vec<u8> = resp.into();
302        assert_eq!(rs, expected);
303    }
304    #[test]
305    fn socks5_decode() {
306        check_none(vec![5]);
307        check_none(vec![5, 1]);
308        check_none(vec![5, 2, 0]);
309        check_greeting(
310            vec![5, 1, 1],
311            VisitorRequest::Greeting {
312                proto: Proto::Socks5,
313                auth: vec![1],
314            },
315            vec![],
316        );
317        check_greeting(
318            vec![5, 2, 0, 1],
319            VisitorRequest::Greeting {
320                proto: Proto::Socks5,
321                auth: vec![0, 1],
322            },
323            vec![],
324        );
325        check_greeting(
326            vec![5, 2, 0, 1, 4],
327            VisitorRequest::Greeting {
328                proto: Proto::Socks5,
329                auth: vec![0, 1],
330            },
331            vec![4],
332        );
333        check_auth_none(vec![5, 3, 97, 98, 99, 1], vec![5, 3, 97, 98, 99, 1]);
334        check_auth_none(vec![5, 3, 97, 98, 99], vec![5, 3, 97, 98, 99]);
335        check_auth_none(vec![5, 3, 97, 98], vec![5, 3, 97, 98]);
336        check_auth_none(vec![5, 3], vec![5, 3]);
337        check_auth_none(vec![5], vec![5]);
338        check_auth_none(vec![], vec![]);
339        // ID=abc,PWD=d
340        check_auth(
341            vec![5, 3, 97, 98, 99, 1, 100],
342            VisitorRequest::Auth {
343                id: "abc".into(),
344                pwd: "d".into(),
345            },
346            vec![],
347        );
348        // ID=abc,PWD=d
349        check_auth(
350            vec![5, 3, 97, 98, 99, 1, 100, 200],
351            VisitorRequest::Auth {
352                id: "abc".into(),
353                pwd: "d".into(),
354            },
355            vec![200],
356        );
357        check_connection_none(
358            vec![5, 1, 0, 1, 192, 168, 1, 1, 0],
359            vec![5, 1, 0, 1, 192, 168, 1, 1, 0],
360        );
361        check_connection_none(
362            vec![5, 1, 0, 1, 192, 168, 1, 1],
363            vec![5, 1, 0, 1, 192, 168, 1, 1],
364        );
365        check_connection_none(vec![5, 1, 0, 1, 192, 168], vec![5, 1, 0, 1, 192, 168]);
366        check_connection_none(vec![5, 1, 0, 1], vec![5, 1, 0, 1]);
367        check_connection_none(vec![5, 1, 0], vec![5, 1, 0]);
368
369        check_connection_none(
370            vec![5, 1, 0, 3, 3, 97, 97, 98, 0],
371            vec![5, 1, 0, 3, 3, 97, 97, 98, 0],
372        );
373        check_connection_none(vec![5, 1, 0, 3, 3, 97, 97], vec![5, 1, 0, 3, 3, 97, 97]);
374        check_connection_none(vec![5, 1, 0, 3, 3], vec![5, 1, 0, 3, 3]);
375        check_connection_none(vec![5, 1, 0, 3], vec![5, 1, 0, 3]);
376        check_connection_none(vec![5, 1, 0], vec![5, 1, 0]);
377        check_connection_none(vec![], vec![]);
378        // Client connection request
379        // IPv4
380        check_connection(
381            vec![5, 1, 0, 1, 192, 168, 1, 1, 0, 80],
382            VisitorRequest::Connection {
383                cmd: Cmd::Connection,
384                address: DstAddress::new(T::IPv4, "192.168.1.1", 80),
385            },
386            vec![],
387        );
388        // Domain
389        check_connection(
390            vec![5, 1, 0, 3, 3, 97, 97, 98, 0, 80],
391            VisitorRequest::Connection {
392                cmd: Cmd::Connection,
393                address: DstAddress::new(T::Domain, "aab", 80),
394            },
395            vec![],
396        );
397    }
398    fn check_none(input: Vec<u8>) {
399        let mut codec = SocksCodec::default();
400        let mut bytes = BytesMut::from(input.as_slice());
401        let rs = codec.decode(&mut bytes).unwrap();
402        assert_eq!(rs, None);
403        assert_eq!(bytes.to_vec(), input);
404    }
405    fn check_greeting(input: Vec<u8>, greeting: VisitorRequest, remain: Vec<u8>) {
406        let mut codec = SocksCodec::default();
407        let mut bytes = BytesMut::from(input.as_slice());
408        let rs = codec.decode(&mut bytes).unwrap();
409        assert_eq!(codec.state, State::Greeting);
410        assert_eq!(rs, Some(greeting));
411        assert_eq!(bytes.to_vec(), remain);
412    }
413    fn check_auth(input: Vec<u8>, auth: VisitorRequest, remain: Vec<u8>) {
414        let mut codec = SocksCodec::default();
415        let mut bytes = BytesMut::from(input.as_slice());
416        codec.state = State::Greeting;
417        let rs = codec.decode(&mut bytes).unwrap();
418        assert_eq!(codec.state, State::Auth);
419        assert_eq!(rs, Some(auth));
420        assert_eq!(bytes.to_vec(), remain);
421    }
422    fn check_auth_none(input: Vec<u8>, remain: Vec<u8>) {
423        let mut codec = SocksCodec::default();
424        let mut bytes = BytesMut::from(input.as_slice());
425        codec.state = State::Greeting;
426        let rs = codec.decode(&mut bytes).unwrap();
427        assert_eq!(codec.state, State::Greeting);
428        assert_eq!(rs, None);
429        assert_eq!(bytes.to_vec(), remain);
430    }
431    fn check_connection(input: Vec<u8>, connection: VisitorRequest, remain: Vec<u8>) {
432        let mut codec = SocksCodec::default();
433        let mut bytes = BytesMut::from(input.as_slice());
434        codec.state = State::Auth;
435        let rs = codec.decode(&mut bytes).unwrap();
436        assert_eq!(codec.state, State::Forward);
437        assert_eq!(rs, Some(connection));
438        assert_eq!(bytes.to_vec(), remain);
439    }
440    fn check_connection_none(input: Vec<u8>, remain: Vec<u8>) {
441        let mut codec = SocksCodec::default();
442        let mut bytes = BytesMut::from(input.as_slice());
443        codec.state = State::Auth;
444        let rs = codec.decode(&mut bytes).unwrap();
445        assert_eq!(codec.state, State::Auth);
446        assert_eq!(rs, None);
447        assert_eq!(bytes.to_vec(), remain);
448    }
449}