mirror of
https://github.com/orbien-org/orbien.git
synced 2026-09-22 00:01:31 +00:00
refactor: remove custom requestHeaders
This commit is contained in:
@@ -11,7 +11,6 @@ use tokio_rustls::TlsAcceptor;
|
||||
pub struct TlsTermPlugin {
|
||||
local_addr: String,
|
||||
host_header_rewrite: String,
|
||||
request_headers: Vec<(String, String)>,
|
||||
acceptor: TlsAcceptor,
|
||||
}
|
||||
|
||||
@@ -30,13 +29,6 @@ impl TlsTermPlugin {
|
||||
let tls_cfg = load_or_generate_https_server_config(&cfg.cert_file, &cfg.key_file, &cn)?;
|
||||
let acceptor = TlsAcceptor::from(tls_cfg);
|
||||
|
||||
let request_headers: Vec<(String, String)> = cfg
|
||||
.request_headers
|
||||
.set
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
.collect();
|
||||
|
||||
tracing::info!(
|
||||
tunnel = %ctx.name,
|
||||
%local_addr,
|
||||
@@ -47,7 +39,6 @@ impl TlsTermPlugin {
|
||||
Ok(Self {
|
||||
local_addr,
|
||||
host_header_rewrite: cfg.host_header_rewrite.clone(),
|
||||
request_headers,
|
||||
acceptor,
|
||||
})
|
||||
}
|
||||
@@ -73,7 +64,7 @@ impl Plugin for TlsTermPlugin {
|
||||
|
||||
let (mut tls_r, mut tls_w) = tokio::io::split(tls);
|
||||
let mut head = read_http_request_head(&mut tls_r).await?;
|
||||
apply_request_rewrites(&mut head, &self.host_header_rewrite, &self.request_headers)?;
|
||||
apply_host_rewrite(&mut head, &self.host_header_rewrite)?;
|
||||
|
||||
orbien_core::net::apply_x_forwarded_for(&mut head, &conn.src_addr, "https")?;
|
||||
local.write_all(&head).await?;
|
||||
@@ -114,11 +105,11 @@ async fn read_http_request_head<R: AsyncReadExt + Unpin>(stream: &mut R) -> Resu
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_request_rewrites(
|
||||
buf: &mut Vec<u8>,
|
||||
host_rewrite: &str,
|
||||
extra_headers: &[(String, String)],
|
||||
) -> Result<()> {
|
||||
fn apply_host_rewrite(buf: &mut Vec<u8>, host_rewrite: &str) -> Result<()> {
|
||||
if host_rewrite.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let text = String::from_utf8_lossy(buf);
|
||||
let mut lines: Vec<String> = text.split_inclusive('\n').map(|s| s.to_string()).collect();
|
||||
if lines.is_empty() {
|
||||
@@ -131,27 +122,17 @@ fn apply_request_rewrites(
|
||||
"\n"
|
||||
};
|
||||
|
||||
if !host_rewrite.is_empty() {
|
||||
let mut replaced = false;
|
||||
for line in lines.iter_mut().skip(1) {
|
||||
let trimmed = line.trim_start_matches([' ', '\t']);
|
||||
if trimmed.len() >= 5 && trimmed.as_bytes()[..5].eq_ignore_ascii_case(b"host:") {
|
||||
*line = format!("Host: {host_rewrite}{ending}");
|
||||
replaced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !replaced {
|
||||
lines.insert(1, format!("Host: {host_rewrite}{ending}"));
|
||||
let mut replaced = false;
|
||||
for line in lines.iter_mut().skip(1) {
|
||||
let trimmed = line.trim_start_matches([' ', '\t']);
|
||||
if trimmed.len() >= 5 && trimmed.as_bytes()[..5].eq_ignore_ascii_case(b"host:") {
|
||||
*line = format!("Host: {host_rewrite}{ending}");
|
||||
replaced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (k, v) in extra_headers {
|
||||
let blank_idx = lines
|
||||
.iter()
|
||||
.position(|l| l == "\r\n" || l == "\n")
|
||||
.unwrap_or(lines.len());
|
||||
lines.insert(blank_idx, format!("{k}: {v}{ending}"));
|
||||
if !replaced {
|
||||
lines.insert(1, format!("Host: {host_rewrite}{ending}"));
|
||||
}
|
||||
|
||||
*buf = lines.join("").into_bytes();
|
||||
|
||||
@@ -90,10 +90,6 @@ certFile = "./certs/portal.crt"
|
||||
keyFile = "./certs/portal.key"
|
||||
hostHeaderRewrite = "127.0.0.1"
|
||||
|
||||
[tunnels.plugin.requestHeaders.set]
|
||||
X-Forwarded-Proto = "https"
|
||||
X-Orbien-Tunnel = "portal"
|
||||
|
||||
[[tunnels]]
|
||||
name = "socks5"
|
||||
protocol = "tcp"
|
||||
|
||||
@@ -170,21 +170,12 @@ pub struct PluginConfig {
|
||||
#[serde(default, rename = "hostHeaderRewrite", alias = "host_header_rewrite")]
|
||||
pub host_header_rewrite: String,
|
||||
|
||||
#[serde(default, rename = "requestHeaders", alias = "request_headers")]
|
||||
pub request_headers: PluginRequestHeaders,
|
||||
|
||||
#[serde(default)]
|
||||
pub username: String,
|
||||
#[serde(default)]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub struct PluginRequestHeaders {
|
||||
#[serde(default)]
|
||||
pub set: std::collections::HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct TunnelTransportConfig {
|
||||
#[serde(default)]
|
||||
|
||||
@@ -3,7 +3,7 @@ mod env;
|
||||
mod server;
|
||||
|
||||
pub use client::{
|
||||
ClientConfig, ClientTlsConfig, PluginConfig, PluginRequestHeaders, TransportConfig,
|
||||
ClientConfig, ClientTlsConfig, PluginConfig, TransportConfig,
|
||||
TunnelConfig, TunnelTransportConfig,
|
||||
};
|
||||
pub use env::{contains_env_placeholders, expand_env_placeholders};
|
||||
|
||||
@@ -57,8 +57,6 @@ tunnel-tls-term=TLS terminate
|
||||
tunnel-plugin-local-addr=Local address
|
||||
tunnel-plugin-cert=Certificate path
|
||||
tunnel-plugin-key=Key path
|
||||
tunnel-plugin-request-headers=Extra request headers
|
||||
tunnel-plugin-request-headers-hint=e.g. X-From: orbien, comma-separated
|
||||
tunnel-plugin-username=Username
|
||||
tunnel-plugin-password=Password
|
||||
tunnel-copied=Copied to clipboard
|
||||
|
||||
@@ -55,8 +55,6 @@ tunnel-tls-term=TLS 终止
|
||||
tunnel-plugin-local-addr=本地地址
|
||||
tunnel-plugin-cert=证书路径
|
||||
tunnel-plugin-key=私钥路径
|
||||
tunnel-plugin-request-headers=追加请求头
|
||||
tunnel-plugin-request-headers-hint=如 X-From: orbien,多项逗号分隔
|
||||
tunnel-plugin-username=用户名
|
||||
tunnel-plugin-password=密码
|
||||
tunnel-copied=已复制到剪贴板
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use orbien_client::ClientConfig;
|
||||
use orbien_core::config::{
|
||||
parse_host_port, ClientTlsConfig, PluginConfig, PluginRequestHeaders, TransportConfig,
|
||||
TunnelConfig, TunnelTransportConfig,
|
||||
parse_host_port, ClientTlsConfig, PluginConfig, TransportConfig, TunnelConfig,
|
||||
TunnelTransportConfig,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -298,35 +297,6 @@ fn split_csv(raw: &str) -> Vec<String> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parse_request_headers(raw: &str) -> PluginRequestHeaders {
|
||||
let mut set = HashMap::new();
|
||||
for part in raw.split(',') {
|
||||
let part = part.trim();
|
||||
if part.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let Some((name, value)) = part.split_once(':') else {
|
||||
continue;
|
||||
};
|
||||
let name = name.trim();
|
||||
if name.is_empty() {
|
||||
continue;
|
||||
}
|
||||
set.insert(name.to_string(), value.trim().to_string());
|
||||
}
|
||||
PluginRequestHeaders { set }
|
||||
}
|
||||
|
||||
fn format_request_headers(headers: &PluginRequestHeaders) -> String {
|
||||
let mut names: Vec<&String> = headers.set.keys().collect();
|
||||
names.sort();
|
||||
names
|
||||
.into_iter()
|
||||
.map(|name| format!("{name}: {}", headers.set[name]))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
}
|
||||
|
||||
fn is_tls_term_plugin(plugin_type: &str) -> bool {
|
||||
matches!(plugin_type.trim().to_ascii_lowercase().as_str(), "tls-term")
|
||||
}
|
||||
@@ -354,7 +324,6 @@ pub fn tunnel_from_parts(
|
||||
plugin_cert_file: &str,
|
||||
plugin_key_file: &str,
|
||||
plugin_host_rewrite: &str,
|
||||
plugin_request_headers: &str,
|
||||
plugin_username: &str,
|
||||
plugin_password: &str,
|
||||
) -> Result<TunnelConfig> {
|
||||
@@ -373,7 +342,6 @@ pub fn tunnel_from_parts(
|
||||
cert_file: plugin_cert_file.trim().into(),
|
||||
key_file: plugin_key_file.trim().into(),
|
||||
host_header_rewrite: plugin_host_rewrite.trim().into(),
|
||||
request_headers: parse_request_headers(plugin_request_headers),
|
||||
username: String::new(),
|
||||
password: String::new(),
|
||||
})
|
||||
@@ -466,9 +434,6 @@ pub fn tunnel_to_parts(p: &TunnelConfig) -> TunnelParts {
|
||||
plugin_host_rewrite: tls_term
|
||||
.map(|pl| pl.host_header_rewrite.clone())
|
||||
.unwrap_or_default(),
|
||||
plugin_request_headers: tls_term
|
||||
.map(|pl| format_request_headers(&pl.request_headers))
|
||||
.unwrap_or_default(),
|
||||
plugin_username: socks5.map(|pl| pl.username.clone()).unwrap_or_default(),
|
||||
plugin_password: socks5.map(|pl| pl.password.clone()).unwrap_or_default(),
|
||||
}
|
||||
@@ -494,7 +459,6 @@ pub struct TunnelParts {
|
||||
pub plugin_cert_file: String,
|
||||
pub plugin_key_file: String,
|
||||
pub plugin_host_rewrite: String,
|
||||
pub plugin_request_headers: String,
|
||||
pub plugin_username: String,
|
||||
pub plugin_password: String,
|
||||
}
|
||||
|
||||
@@ -102,7 +102,6 @@ fn row_to_tunnel(row: &TunnelRow) -> anyhow::Result<orbien_core::config::TunnelC
|
||||
row.plugin_cert_file.as_str(),
|
||||
row.plugin_key_file.as_str(),
|
||||
row.plugin_host_rewrite.as_str(),
|
||||
row.plugin_request_headers.as_str(),
|
||||
row.plugin_username.as_str(),
|
||||
row.plugin_password.as_str(),
|
||||
)
|
||||
@@ -130,7 +129,6 @@ fn tunnel_to_row(p: &orbien_core::config::TunnelConfig) -> TunnelRow {
|
||||
plugin_cert_file: parts.plugin_cert_file.into(),
|
||||
plugin_key_file: parts.plugin_key_file.into(),
|
||||
plugin_host_rewrite: parts.plugin_host_rewrite.into(),
|
||||
plugin_request_headers: parts.plugin_request_headers.into(),
|
||||
plugin_username: parts.plugin_username.into(),
|
||||
plugin_password: parts.plugin_password.into(),
|
||||
}
|
||||
@@ -359,7 +357,6 @@ fn reset_tunnel_form(ui: &AppWindow) {
|
||||
ui.set_tunnel_edit_plugin_cert_file("".into());
|
||||
ui.set_tunnel_edit_plugin_key_file("".into());
|
||||
ui.set_tunnel_edit_plugin_host_rewrite("".into());
|
||||
ui.set_tunnel_edit_plugin_request_headers("".into());
|
||||
ui.set_tunnel_edit_plugin_username("".into());
|
||||
ui.set_tunnel_edit_plugin_password("".into());
|
||||
ui.set_tunnel_edit_type_index(0);
|
||||
@@ -389,7 +386,6 @@ fn fill_tunnel_form(ui: &AppWindow, row: &TunnelRow) {
|
||||
ui.set_tunnel_edit_plugin_cert_file(row.plugin_cert_file.clone());
|
||||
ui.set_tunnel_edit_plugin_key_file(row.plugin_key_file.clone());
|
||||
ui.set_tunnel_edit_plugin_host_rewrite(row.plugin_host_rewrite.clone());
|
||||
ui.set_tunnel_edit_plugin_request_headers(row.plugin_request_headers.clone());
|
||||
ui.set_tunnel_edit_plugin_username(row.plugin_username.clone());
|
||||
ui.set_tunnel_edit_plugin_password(row.plugin_password.clone());
|
||||
ui.set_tunnel_show_advanced(false);
|
||||
@@ -473,11 +469,6 @@ fn collect_tunnel_form(ui: &AppWindow) -> TunnelRow {
|
||||
} else {
|
||||
"".into()
|
||||
},
|
||||
plugin_request_headers: if plugin {
|
||||
ui.get_tunnel_edit_plugin_request_headers()
|
||||
} else {
|
||||
"".into()
|
||||
},
|
||||
plugin_username: if is_socks5 {
|
||||
ui.get_tunnel_edit_plugin_username()
|
||||
} else {
|
||||
|
||||
@@ -122,7 +122,6 @@ export component AppWindow inherits Window {
|
||||
in-out property <string> tunnel-edit-plugin-cert-file: "";
|
||||
in-out property <string> tunnel-edit-plugin-key-file: "";
|
||||
in-out property <string> tunnel-edit-plugin-host-rewrite: "";
|
||||
in-out property <string> tunnel-edit-plugin-request-headers: "";
|
||||
in-out property <string> tunnel-edit-plugin-username: "";
|
||||
in-out property <string> tunnel-edit-plugin-password: "";
|
||||
in-out property <int> tunnel-edit-type-index: 0;
|
||||
@@ -261,7 +260,6 @@ export component AppWindow inherits Window {
|
||||
edit-plugin-cert-file <=> root.tunnel-edit-plugin-cert-file;
|
||||
edit-plugin-key-file <=> root.tunnel-edit-plugin-key-file;
|
||||
edit-plugin-host-rewrite <=> root.tunnel-edit-plugin-host-rewrite;
|
||||
edit-plugin-request-headers <=> root.tunnel-edit-plugin-request-headers;
|
||||
edit-plugin-username <=> root.tunnel-edit-plugin-username;
|
||||
edit-plugin-password <=> root.tunnel-edit-plugin-password;
|
||||
edit-type-index <=> root.tunnel-edit-type-index;
|
||||
|
||||
@@ -28,7 +28,6 @@ export component TunnelPage inherits Rectangle {
|
||||
in-out property <string> edit-plugin-cert-file: "";
|
||||
in-out property <string> edit-plugin-key-file: "";
|
||||
in-out property <string> edit-plugin-host-rewrite: "";
|
||||
in-out property <string> edit-plugin-request-headers: "";
|
||||
in-out property <string> edit-plugin-username: "";
|
||||
in-out property <string> edit-plugin-password: "";
|
||||
in-out property <int> edit-type-index: 0;
|
||||
@@ -174,7 +173,6 @@ export component TunnelPage inherits Rectangle {
|
||||
edit-plugin-cert-file <=> root.edit-plugin-cert-file;
|
||||
edit-plugin-key-file <=> root.edit-plugin-key-file;
|
||||
edit-plugin-host-rewrite <=> root.edit-plugin-host-rewrite;
|
||||
edit-plugin-request-headers <=> root.edit-plugin-request-headers;
|
||||
edit-plugin-username <=> root.edit-plugin-username;
|
||||
edit-plugin-password <=> root.edit-plugin-password;
|
||||
edit-type-index <=> root.edit-type-index;
|
||||
|
||||
@@ -22,7 +22,6 @@ export component TunnelEditor inherits Rectangle {
|
||||
in-out property <string> edit-plugin-cert-file: "";
|
||||
in-out property <string> edit-plugin-key-file: "";
|
||||
in-out property <string> edit-plugin-host-rewrite: "";
|
||||
in-out property <string> edit-plugin-request-headers: "";
|
||||
in-out property <string> edit-plugin-username: "";
|
||||
in-out property <string> edit-plugin-password: "";
|
||||
in-out property <int> edit-type-index: 0;
|
||||
@@ -335,12 +334,6 @@ export component TunnelEditor inherits Rectangle {
|
||||
model: [Tr.proxy-protocol-off, "v1", "v2"];
|
||||
current-index <=> root.edit-proxy-protocol-index;
|
||||
}
|
||||
|
||||
if root.is-https && root.use-plugin: FormField {
|
||||
label: Tr.tunnel-plugin-request-headers;
|
||||
value <=> root.edit-plugin-request-headers;
|
||||
placeholder: Tr.tunnel-plugin-request-headers-hint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ export struct TunnelRow {
|
||||
plugin-cert-file: string,
|
||||
plugin-key-file: string,
|
||||
plugin-host-rewrite: string,
|
||||
plugin-request-headers: string,
|
||||
plugin-username: string,
|
||||
plugin-password: string,
|
||||
}
|
||||
|
||||
@@ -85,26 +85,6 @@ keyFile = "/path/to/key.pem"
|
||||
hostHeaderRewrite = "127.0.0.1"
|
||||
```
|
||||
|
||||
## 示例:TLS 终止时追加请求头
|
||||
|
||||
在 `tls-term` 下,向本地 HTTP 追加自定义请求头:
|
||||
|
||||
```toml
|
||||
[[tunnels]]
|
||||
name = "https-term"
|
||||
protocol = "https"
|
||||
domains = ["web.example.com"]
|
||||
|
||||
[tunnels.plugin]
|
||||
type = "tls-term"
|
||||
service = "127.0.0.1:80"
|
||||
certFile = "/path/to/cert.pem"
|
||||
keyFile = "/path/to/key.pem"
|
||||
|
||||
[tunnels.plugin.requestHeaders.set]
|
||||
X-From = "orbien"
|
||||
```
|
||||
|
||||
## 参数
|
||||
|
||||
| 参数 | 必填 | 默认值 | 说明 |
|
||||
@@ -118,7 +98,6 @@ X-From = "orbien"
|
||||
| `plugin.certFile` | 否 | | 证书路径;空则临时自签 |
|
||||
| `plugin.keyFile` | 否 | | 私钥路径;空则临时自签 |
|
||||
| `plugin.hostHeaderRewrite` | 否 | | 改写转发到本地服务的 Host;空表示不改 |
|
||||
| `plugin.requestHeaders.set` | 否 | | 向后端追加请求头,键值对 |
|
||||
| `transport.bandwidth` | 否 | `0` | 带宽上限(Mbps);`0` 表示不限制 |
|
||||
| `transport.bandwidthLimitSide` | 否 | `client` | 限速端:`client` / `server` |
|
||||
| `transport.proxyProtocolVersion` | 否 | | PROXY Protocol:`v1` / `v2`(`tls-term` 不可用) |
|
||||
|
||||
@@ -88,26 +88,6 @@ keyFile = "/path/to/key.pem"
|
||||
hostHeaderRewrite = "127.0.0.1"
|
||||
```
|
||||
|
||||
## Example: Add request headers with TLS termination
|
||||
|
||||
Under `tls-term`, append custom request headers to local HTTP:
|
||||
|
||||
```toml
|
||||
[[tunnels]]
|
||||
name = "https-term"
|
||||
protocol = "https"
|
||||
domains = ["web.example.com"]
|
||||
|
||||
[tunnels.plugin]
|
||||
type = "tls-term"
|
||||
service = "127.0.0.1:80"
|
||||
certFile = "/path/to/cert.pem"
|
||||
keyFile = "/path/to/key.pem"
|
||||
|
||||
[tunnels.plugin.requestHeaders.set]
|
||||
X-From = "orbien"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Required | Default | Description |
|
||||
@@ -121,7 +101,6 @@ X-From = "orbien"
|
||||
| `plugin.certFile` | No | | Certificate path; empty uses a temporary self-signed cert |
|
||||
| `plugin.keyFile` | No | | Private key path; empty uses a temporary self-signed cert |
|
||||
| `plugin.hostHeaderRewrite` | No | | Rewrite Host when forwarding to the local service; empty means no rewrite |
|
||||
| `plugin.requestHeaders.set` | No | | Extra request headers to send to the backend; key-value pairs |
|
||||
| `transport.bandwidth` | No | `0` | Bandwidth cap (Mbps); `0` means unlimited |
|
||||
| `transport.bandwidthLimitSide` | No | `client` | Limit side: `client` / `server` |
|
||||
| `transport.proxyProtocolVersion` | No | | PROXY Protocol: `v1` / `v2` (not available with `tls-term`) |
|
||||
|
||||
Reference in New Issue
Block a user