Skip to content

Commit

Permalink
Merge pull request #362 from ramajd/features/http-proxy-support
Browse files Browse the repository at this point in the history
Features/http proxy support
  • Loading branch information
tarkah authored Apr 30, 2024
2 parents 1d82fc4 + 0648a03 commit 09d55ac
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Added:
- Support for IRCv3 CAP NEW and CAP DEL subcommands
- Enable support for IRCv3 `multi-prefix`
- Added support for `socks5` proxy configuration (see [proxy configuration](https://halloy.squidowl.org/configuration/proxy.html))
- Added support for `http` proxy configuration (see [proxy configuration](https://halloy.squidowl.org/configuration/proxy.html))

Changed:

Expand Down
27 changes: 23 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions book/src/configuration/proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ host = "<string>"
port = <integer>
```

| Key | Description | Default |
| :--------- | :------------------------------------------------ | :---------- |
| `type` | Proxy type. Only `socks5` is currently supported. | `""` |
| `host` | Proxy host to connect to | `""` |
| `port` | Proxy port to connect on | `""` |
| `username` | Proxy username, optional | `""` |
| `password` | Proxy password, optional | `""` |
| Key | Description | Default |
| :--------- | :------------------------------------------------------- | :---------- |
| `type` | Proxy type. `http` and `socks5` are currently supported. | `""` |
| `host` | Proxy host to connect to | `""` |
| `port` | Proxy port to connect on | `""` |
| `username` | Proxy username, optional | `""` |
| `password` | Proxy password, optional | `""` |
7 changes: 7 additions & 0 deletions data/src/config/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Kind {
Http,
Socks5,
}

Expand All @@ -19,6 +20,12 @@ pub struct Proxy {
impl From<Proxy> for irc::connection::Proxy {
fn from(proxy: Proxy) -> irc::connection::Proxy {
match proxy.kind {
Kind::Http => irc::connection::Proxy::Http {
host: proxy.host,
port: proxy.port,
username: proxy.username,
password: proxy.password,
},
Kind::Socks5 => irc::connection::Proxy::Socks5 {
host: proxy.host,
port: proxy.port,
Expand Down
1 change: 1 addition & 0 deletions irc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
async-http-proxy = { version = "1.2.5", features = ["runtime-tokio", "basic-auth"] }
bytes = "1.4.0"
fast-socks5 = "0.9.6"
futures = "0.3.28"
Expand Down
17 changes: 1 addition & 16 deletions irc/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,7 @@ impl<Codec> Connection<Codec> {
pub async fn new(config: Config<'_>, codec: Codec) -> Result<Self, Error> {
let tcp = match config.proxy {
None => TcpStream::connect((config.server, config.port)).await?,
Some(Proxy::Socks5 {
host,
port,
username,
password,
}) => {
proxy::connect_socks5(
host,
port,
config.server.to_string(),
config.port,
username,
password,
)
.await?
}
Some(proxy) => proxy.connect(config.server, config.port).await?,
};

if let Security::Secured {
Expand Down
74 changes: 74 additions & 0 deletions irc/src/connection/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
use async_http_proxy::{http_connect_tokio, http_connect_tokio_with_basic_auth};
use fast_socks5::client::{Config as Socks5Config, Socks5Stream};
use thiserror::Error;
use tokio::net::TcpStream;

#[derive(Debug, Clone)]
pub enum Proxy {
Http {
host: String,
port: u16,
username: Option<String>,
password: Option<String>,
},
Socks5 {
host: String,
port: u16,
Expand All @@ -12,6 +19,69 @@ pub enum Proxy {
},
}

impl Proxy {
pub async fn connect(&self, target_server: &str, target_port: u16) -> Result<TcpStream, Error> {
match self {
Proxy::Http {
host,
port,
username,
password,
} => {
connect_http(
host,
*port,
target_server,
target_port,
username.to_owned(),
password.to_owned(),
)
.await
}
Proxy::Socks5 {
host,
port,
username,
password,
} => {
connect_socks5(
host.to_string(),
*port,
target_server.to_string(),
target_port,
username.to_owned(),
password.to_owned(),
)
.await
}
}
}
}

pub async fn connect_http(
proxy_server: &str,
proxy_port: u16,
target_server: &str,
target_port: u16,
username: Option<String>,
password: Option<String>,
) -> Result<TcpStream, Error> {
let mut stream = TcpStream::connect((proxy_server, proxy_port)).await?;
if let Some((username, password)) = username.zip(password) {
http_connect_tokio_with_basic_auth(
&mut stream,
target_server,
target_port,
&username,
&password,
)
.await?;
} else {
http_connect_tokio(&mut stream, target_server, target_port).await?;
}
Ok(stream)
}

pub async fn connect_socks5(
proxy_server: String,
proxy_port: u16,
Expand Down Expand Up @@ -47,6 +117,10 @@ pub async fn connect_socks5(

#[derive(Debug, Error)]
pub enum Error {
#[error("http error: {0}")]
Http(#[from] async_http_proxy::HttpError),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("socks5 error: {0}")]
Socks5(#[from] fast_socks5::SocksError),
}

0 comments on commit 09d55ac

Please sign in to comment.