You've already forked OpenIntegrations
mirror of
https://github.com/Bayselonarrend/OpenIntegrations.git
synced 2025-08-10 22:41:43 +02:00
FTP: Переработка HTTP прокси
This commit is contained in:
7
src/addins/ftp/Cargo.lock
generated
7
src/addins/ftp/Cargo.lock
generated
@@ -276,6 +276,12 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.61"
|
version = "0.1.61"
|
||||||
@@ -441,6 +447,7 @@ dependencies = [
|
|||||||
"addin1c",
|
"addin1c",
|
||||||
"base64",
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"httparse",
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-pemfile",
|
"rustls-pemfile",
|
||||||
"serde",
|
"serde",
|
||||||
|
@@ -23,4 +23,5 @@ base64 = "0.22.1"
|
|||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
webpki-roots = "1.0.1"
|
webpki-roots = "1.0.1"
|
||||||
rustls = { version = "0.23.28", features = ["ring"] }
|
rustls = { version = "0.23.28", features = ["ring"] }
|
||||||
rustls-pemfile = "2.2.0"
|
rustls-pemfile = "2.2.0"
|
||||||
|
httparse = "1.10.1"
|
@@ -1,9 +1,9 @@
|
|||||||
"MAIN ---"
|
"MAIN ---"
|
||||||
linux-vdso.so.1 (0x00007ffe4c948000)
|
linux-vdso.so.1 (0x00007ffc20c91000)
|
||||||
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000759ff8e00000)
|
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007776c2000000)
|
||||||
libc.so.6 => /lib64/libc.so.6 (0x0000759ff8a00000)
|
libc.so.6 => /lib64/libc.so.6 (0x00007776c1c00000)
|
||||||
libdl.so.2 => /lib64/libdl.so.2 (0x0000759ff8600000)
|
libdl.so.2 => /lib64/libdl.so.2 (0x00007776c1800000)
|
||||||
/lib64/ld-linux-x86-64.so.2 (0x0000759ff9400000)
|
/lib64/ld-linux-x86-64.so.2 (0x00007776c2600000)
|
||||||
GLIBC_2.2.5
|
GLIBC_2.2.5
|
||||||
GLIBC_2.3
|
GLIBC_2.3
|
||||||
GLIBC_2.3.4
|
GLIBC_2.3.4
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
use std::io::{BufRead, BufReader, Write};
|
use std::io::{Read, Write};
|
||||||
use std::net::{SocketAddr, TcpStream};
|
use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use socks::{Socks4Stream, Socks5Stream};
|
use socks::{Socks4Stream, Socks5Stream};
|
||||||
use base64::{Engine as _, engine::general_purpose};
|
use base64::{Engine as _, engine::general_purpose};
|
||||||
use suppaftp::FtpError;
|
use suppaftp::FtpError;
|
||||||
use crate::component::configuration::{FtpProxySettings, FtpSettings};
|
use crate::component::configuration::{FtpProxySettings, FtpSettings};
|
||||||
|
use std::fmt::Write as FmtWrite;
|
||||||
|
|
||||||
pub fn make_passive_proxy_stream(
|
pub fn make_passive_proxy_stream(
|
||||||
ftp_settings: &FtpSettings,
|
ftp_settings: &FtpSettings,
|
||||||
@@ -122,62 +123,60 @@ fn connect_via_socks4(proxy_settings: &FtpProxySettings, target_addr: (&str, u16
|
|||||||
.map_err(|e| format!("SOCKS4 error: {}", e))
|
.map_err(|e| format!("SOCKS4 error: {}", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_via_http_proxy(proxy_settings: &FtpProxySettings, target_addr: (&str, u16)) -> Result<TcpStream, String> {
|
pub fn connect_via_http_proxy(proxy_settings: &FtpProxySettings, target_addr: (&str, u16)) -> Result<TcpStream, String> {
|
||||||
|
|
||||||
let proxy_addr = format!("{}:{}", proxy_settings.server, proxy_settings.port);
|
let proxy_addr = format!("{}:{}", proxy_settings.server, proxy_settings.port);
|
||||||
|
|
||||||
let mut stream = TcpStream::connect(proxy_addr)
|
let mut stream = TcpStream::connect(
|
||||||
.map_err(|e| format!("Failed to connect to HTTP proxy: {}", e))?;
|
proxy_addr.to_socket_addrs()
|
||||||
|
.map_err(|e| format!("Failed to resolve proxy address: {}", e))?
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| "Proxy address resolution returned no results".to_string())?
|
||||||
|
).map_err(|e| format!("Failed to connect to HTTP proxy: {}", e))?;
|
||||||
|
|
||||||
|
// Установим таймауты для стабильности
|
||||||
|
stream.set_read_timeout(Some(Duration::from_secs(10))).ok();
|
||||||
|
stream.set_write_timeout(Some(Duration::from_secs(10))).ok();
|
||||||
|
|
||||||
|
// Формируем CONNECT-запрос
|
||||||
let host_port = format!("{}:{}", target_addr.0, target_addr.1);
|
let host_port = format!("{}:{}", target_addr.0, target_addr.1);
|
||||||
let request = format!(
|
let mut request = format!(
|
||||||
"CONNECT {} HTTP/1.1\r\nHost: {}\r\n",
|
"CONNECT {} HTTP/1.1\r\nHost: {}\r\nConnection: keep-alive\r\n",
|
||||||
host_port, host_port
|
host_port, host_port
|
||||||
);
|
);
|
||||||
|
|
||||||
let request = if let (Some(user), Some(pass)) = (&proxy_settings.login, &proxy_settings.password) {
|
// Добавляем Proxy-Authorization при необходимости
|
||||||
let auth = general_purpose::STANDARD.encode(&format!("{}:{}", user, pass));
|
if let (Some(user), Some(pass)) = (&proxy_settings.login, &proxy_settings.password) {
|
||||||
format!("{}Proxy-Authorization: Basic {}\r\n\r\n", request, auth)
|
let auth = general_purpose::STANDARD.encode(format!("{}:{}", user, pass));
|
||||||
} else {
|
write!(request, "Proxy-Authorization: Basic {}\r\n", auth).unwrap();
|
||||||
request + "\r\n"
|
}
|
||||||
};
|
request.push_str("\r\n");
|
||||||
|
|
||||||
|
// Отправляем запрос
|
||||||
stream.write_all(request.as_bytes())
|
stream.write_all(request.as_bytes())
|
||||||
.map_err(|e| format!("Failed to send CONNECT request: {}", e))?;
|
.map_err(|e| format!("Failed to send CONNECT request: {}", e))?;
|
||||||
|
|
||||||
let mut reader = BufReader::new(stream);
|
// Читаем ответ прокси
|
||||||
|
let mut buf = [0u8; 4096];
|
||||||
|
let n = stream.read(&mut buf)
|
||||||
|
.map_err(|e| format!("Failed to read proxy response: {}", e))?;
|
||||||
|
|
||||||
let mut status_line = String::new();
|
let mut headers = [httparse::EMPTY_HEADER; 16];
|
||||||
reader.read_line(&mut status_line)
|
let mut response = httparse::Response::new(&mut headers);
|
||||||
.map_err(|e| format!("Failed to read status line: {}", e))?;
|
match response.parse(&buf[..n]) {
|
||||||
|
Ok(httparse::Status::Complete(_)) => {},
|
||||||
if !status_line.starts_with("HTTP/") {
|
Ok(httparse::Status::Partial) => return Err("Incomplete proxy response".to_string()),
|
||||||
return Err(format!("Invalid response: {}", status_line));
|
Err(e) => return Err(format!("Failed to parse proxy response: {:?}", e)),
|
||||||
}
|
}
|
||||||
|
|
||||||
let status_code = status_line.split_whitespace().nth(1)
|
let code = response.code.ok_or_else(|| "Missing HTTP status code in proxy response".to_string())?;
|
||||||
.ok_or_else(|| "Malformed status line")?;
|
match code {
|
||||||
|
200 => Ok(stream),
|
||||||
match status_code {
|
407 => Err("Proxy authentication required (HTTP 407)".to_string()),
|
||||||
"200" => {}
|
_ => {
|
||||||
"407" => return Err("Proxy authentication required".to_string()),
|
let resp_str = String::from_utf8_lossy(&buf[..n]);
|
||||||
code => return Err(format!("Proxy error: {}", code)),
|
Err(format!("Proxy error: HTTP {}\nFull response:\n{}", code, resp_str))
|
||||||
}
|
|
||||||
|
|
||||||
// Пропускаем заголовки
|
|
||||||
let mut header_line = String::new();
|
|
||||||
loop {
|
|
||||||
header_line.clear();
|
|
||||||
reader.read_line(&mut header_line)
|
|
||||||
.map_err(|e| format!("Failed to read header: {}", e))?;
|
|
||||||
|
|
||||||
if header_line.trim().is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream = reader.into_inner();
|
|
||||||
Ok(stream)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_direct(addr: (&str, u16)) -> Result<TcpStream, String> {
|
fn connect_direct(addr: (&str, u16)) -> Result<TcpStream, String> {
|
||||||
|
BIN
src/en/OInt/addins/OPI_FTP.zip
vendored
BIN
src/en/OInt/addins/OPI_FTP.zip
vendored
Binary file not shown.
Binary file not shown.
BIN
src/ru/OInt/addins/OPI_FTP.zip
vendored
BIN
src/ru/OInt/addins/OPI_FTP.zip
vendored
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user