use base64::{Engine as _, engine::general_purpose};
use httparse::{Response, EMPTY_HEADER};
use crate::{
prelude::*,
error::*,
target::{Target, TargetHost, ToTarget},
proxy::{Auth, HTTPProxy, SOCKS5Command},
};
pub(crate) fn make_http_connect_request(addr: &impl ToTarget, proxy: &HTTPProxy) -> Result<String> {
let addr = addr.to_target()?.to_string();
let mut request = format!(
"CONNECT {0} HTTP/1.1\r\n\
Host: {0}\r\n\
User-Agent: proxie/0.0\r\n\
Proxy-Connection: Keep-Alive\r\n",
addr
);
match &proxy.auth {
Some(auth) => {
let raw_auth = format!("{}:{}", auth.username, auth.password);
let encoded_auth: String = general_purpose::STANDARD.encode(raw_auth.as_bytes());
request.push_str(&format!("Proxy-Authorization: Basic {}\r\n", encoded_auth));
},
None => {},
};
request.push_str("\r\n");
Ok(request)
}
pub(crate) fn parse_http_response(buffer: &[u8]) -> Result<()> {
let mut headers = [EMPTY_HEADER; 64];
let mut response = Response::new(&mut headers);
response.parse(&buffer)?;
match response.code {
Some(code) => {
if code != 200 {
return Err(Box::new(HTTPNotOKError {
code: Some(code),
}));
}
},
None => return Err(Box::new(HTTPNotOKError {
code: None,
})),
};
Ok(())
}
pub(crate) fn make_socks5_initial_request(auth: &Option<Auth>) -> Vec<u8> {
let mut request = vec![];
request.push(0x05);
match auth {
Some(_) => {
request.push(2u8); request.push(0x00); request.push(0x02); },
None => {
request.push(1u8); request.push(0x00); }
}
request
}
pub(crate) fn make_socks5_authentication_request(auth: &Auth) -> Vec<u8> {
let mut request = vec![];
request.push(0x01);
let u_len = auth.username.len();
request.push(u_len as u8); for c in auth.username.chars() {
request.push(c as u8); }
let p_len = auth.password.len();
request.push(p_len as u8); for c in auth.password.chars() {
request.push(c as u8); }
request
}
pub(crate) fn make_socks5_request(cmd: SOCKS5Command, target: &Target) -> Result<Vec<u8>> {
let mut request = vec![];
request.push(0x05);
let cmd = match cmd {
SOCKS5Command::CONNECT => 0x01 };
request.push(cmd);
request.push(0x00);
match &target.host {
TargetHost::IPv4(ip) => {
request.push(0x01);
let ip_bytes = ip.octets();
for byte in ip_bytes {
request.push(byte); }
},
TargetHost::IPv6(ip) => {
request.push(0x04);
let ip_bytes = ip.octets();
for byte in ip_bytes {
request.push(byte); }
},
TargetHost::Hostname(host) => {
request.push(0x03);
let len = host.len();
request.push(len as u8);
for c in host.chars() {
request.push(c as u8); }
},
};
request.push((target.port >> 8) as u8); request.push((target.port & 0x00FF) as u8);
Ok(request)
}