Skip to content

Commit

Permalink
Added support for proxy protocol mode (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
hannesdejager authored Apr 24, 2020
1 parent af58b13 commit 32d39fd
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 17 deletions.
22 changes: 16 additions & 6 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ readme = "README.md"

[dependencies]
async-trait = "0.1.30"
libunftp = "0.9.0"
libunftp = { git="https://github.com/bolcom/libunftp", branch="master" }
log = "0.4"
env_logger = "0.6"
redis = "0.9.0"
Expand All @@ -31,7 +31,7 @@ slog-term = "2.4.0"
slog-async = "2.3.0"
slog-stdlog = "4.0.0"
slog-scope = "4.0.0"
hyper = "0.13"
hyper = "0.13.5"
http = "0.2.1"
prometheus = "0.8"
futures = "0.3"
Expand Down
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,12 @@ docker-run-%: docker-image-% # Run the % docker image in the foreground
.PHONY: docker-list
docker-list: # List the available docker images
@echo $(DOCKER_IMAGES)

##
.PHONY: pr-prep
pr-prep: # Runs checks to ensure you're ready for a pull request
cargo fmt --all -- --check
cargo clippy --all-features -- -D warnings
cargo build --verbose --all --features rest_auth,jsonfile_auth,cloud_storage
cargo test --verbose --all --features rest_auth,jsonfile_auth,cloud_storage
cargo doc --all-features --no-deps
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::process::Command;
fn main() {
let version = match Command::new("git").args(&["describe", "--tags"]).output() {
Ok(output) => String::from_utf8(output.stdout).unwrap(),
Err(_) => env::var("BUILD_VERSION").unwrap_or(">unknown<".to_string()),
Err(_) => env::var("BUILD_VERSION").unwrap_or_else(|_| ">unknown<".to_string()),
};
println!("cargo:rustc-env=BUILD_VERSION={}", version);

Expand Down
15 changes: 12 additions & 3 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub const GCS_KEY_FILE: &str = "sbe-gcs-key-file";
pub const HTTP_BIND_ADDR: &str = "bind-address-http";
pub const IDLE_SESSION_TIMEOUT: &str = "idle-session-timeout";
pub const PASSIVE_PORTS: &str = "passive-ports";
pub const PROXY_EXTERNAL_CONTROL_ADDRES: &str = "proxy-external-control-address";
pub const REDIS_HOST: &str = "log-redis-host";
pub const REDIS_KEY: &str = "log-redis-key";
pub const REDIS_PORT: &str = "log-redis-port";
Expand Down Expand Up @@ -60,7 +61,7 @@ pub(crate) fn clap_app(tmp_dir: &str) -> clap::App {
Arg::with_name(BIND_ADDRESS)
.long("bind-address")
.value_name("HOST_PORT")
.help("Sets the host and port to listen on for FTP control connections")
.help("Sets the host and port to listen on for FTP(S) connections.")
.env("UNFTP_BIND_ADDRESS")
.takes_value(true)
.default_value("0.0.0.0:2121"),
Expand All @@ -69,7 +70,7 @@ pub(crate) fn clap_app(tmp_dir: &str) -> clap::App {
Arg::with_name(ROOT_DIR)
.long("root-dir")
.value_name("PATH")
.help("Sets the FTP root directory")
.help("When the storage backend type is 'filesystem' this sets the path where files are stored.")
.env("UNFTP_ROOT_DIR")
.takes_value(true)
.default_value(tmp_dir),
Expand Down Expand Up @@ -127,7 +128,7 @@ pub(crate) fn clap_app(tmp_dir: &str) -> clap::App {
Arg::with_name(PASSIVE_PORTS)
.long("passive-ports")
.value_name("PORT_RANGE")
.help("Sets the port range for data ports.")
.help("Sets the port range for data connections. In proxy protocol mode this resembles ports on the proxy.")
.env("UNFTP_PASSIVE_PORTS")
.takes_value(true)
.default_value("49152-65535"),
Expand Down Expand Up @@ -235,4 +236,12 @@ pub(crate) fn clap_app(tmp_dir: &str) -> clap::App {
.takes_value(true)
.default_value("600"),
)
.arg(
Arg::with_name(PROXY_EXTERNAL_CONTROL_ADDRES)
.long("proxy-external-control-address")
.value_name("HOST_PORT")
.help("This switches on proxy protocol mode and sets the external IP and external control port number for example 10.0.0.1:2121.")
.env("UNFTP_PROXY_EXTERNAL_CONTROL_ADDRES")
.takes_value(true),
)
}
23 changes: 19 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use tokio::signal::unix::{signal, SignalKind};
#[cfg(feature = "pam_auth")]
use libunftp::auth::pam;

use std::net::SocketAddr;
use user::LookupAuthenticator;

fn redis_logger(m: &clap::ArgMatches) -> Result<Option<redislog::Logger>, String> {
Expand Down Expand Up @@ -74,14 +75,15 @@ fn make_pam_auth(m: &clap::ArgMatches) -> Result<Arc<dyn auth::Authenticator<use
#[cfg(not(feature = "pam_auth"))]
{
let _ = m;
Err(format!("the pam authentication module was disabled at build time"))
Err(String::from("the pam authentication module was disabled at build time"))
}

#[cfg(feature = "pam_auth")]
{
if let Some(service) = m.value_of(args::AUTH_PAM_SERVICE) {
log::info!("Using pam authenticator");
return Ok(Arc::new(pam::PAMAuthenticator::new(service)));
let pam_auth = pam::PAMAuthenticator::new(service);
return Ok(Arc::new(LookupAuthenticator::new(pam_auth)));
}
Err(format!("--{} is required when using pam auth", args::AUTH_PAM_SERVICE))
}
Expand Down Expand Up @@ -263,6 +265,19 @@ where
.idle_session_timeout(idle_timeout)
.metrics();

// Setup proxy protocol mode.
if let Some(addr) = arg_matches.value_of(args::PROXY_EXTERNAL_CONTROL_ADDRES) {
let addr: SocketAddr = String::from(addr).parse().map_err(|e| {
format!(
"unable to parse proxy protocol external control port address {}: {}",
addr, e
)
})?;
server = server
.proxy_protocol_mode(addr.ip().to_string().as_str(), addr.port())
.map_err(|e| format!("could not set proxy protocl mode: {:?}", e))?;
}

// Setup FTPS
server = match (
arg_matches.value_of(args::FTPS_CERTS_FILE),
Expand Down Expand Up @@ -293,7 +308,7 @@ where

// starts an HTTP server and exports Prometheus metrics.
async fn start_http(log: &Logger, bind_addr: &str) -> Result<(), String> {
let http_addr = bind_addr
let http_addr: SocketAddr = bind_addr
.parse()
.map_err(|e| format!("unable to parse HTTP address {}: {}", bind_addr, e))?;

Expand All @@ -314,7 +329,7 @@ async fn start_http(log: &Logger, bind_addr: &str) -> Result<(), String> {
Ok(())
}

async fn main_task<'a>(arg_matches: ArgMatches<'a>, log: &Logger) -> Result<(), String> {
async fn main_task(arg_matches: ArgMatches<'_>, log: &Logger) -> Result<(), String> {
if let Some(addr) = arg_matches.value_of(args::HTTP_BIND_ADDR) {
let addr = String::from(addr);
let log = log.clone();
Expand Down
2 changes: 1 addition & 1 deletion src/redislog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl Builder {
// TODO: Get something that works on windows too
fn get_host_name() -> String {
let output = Command::new("hostname").output().expect("failed to execute process");
String::from_utf8_lossy(&output.stdout).replace("\n", "").to_string()
String::from_utf8_lossy(&output.stdout).replace("\n", "")
}

let con_str = format!("redis://{}:{}", self.redis_host, self.redis_port);
Expand Down

0 comments on commit 32d39fd

Please sign in to comment.