Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 173 additions & 3 deletions nix/tests/default.nix
Original file line number Diff line number Diff line change
@@ -1,19 +1,189 @@
{ pkgs, ... }:
let
# Import nixpkgs snakeoil certs.
mkVirtualHost = svcName: {
extraConfig = ''
location / {
default_type application/json;
return 200 '{"remote_addr":"$remote_addr","service": "${svcName}"}';
}
'';
};
mkServiceNode = {}: {
networking.interfaces.eth1.ipv4.addresses = [
{
address = "192.168.1.200";
prefixLength = 24;
}
];

services.nginx = {
enable = true;
virtualHosts."hello.corp.example.com" = mkVirtualHost "hello.corp";
virtualHosts."bad.corp.example.com" = mkVirtualHost "bad.corp";
};
networking.firewall.allowedTCPPorts = [
80
443
];
};
in
{
daemon = pkgs.testers.nixosTest {
name = "daemon";
exit-node = pkgs.testers.nixosTest {
name = "exit-node";
nodes = {
corp-server = mkServiceNode { };
node = { nodes, ... }: {
imports = [ ../module.nix ];

networking.hosts."${nodes.corp-server.networking.primaryIPAddress}" = [ "hello.corp.example.com" "bad.corp.example.com" ];

networking.interfaces.eth1.ipv4.addresses = [
{
address = "192.168.1.100";
prefixLength = 24;
}
];
services.portail = {
enable = true;
enableAtBoot = true;
acl.filter.rules = [
"hello.corp.example.com -> allow"
".* -> deny"
];
};
};
};
testScript = ''
import json

start_all()

node.wait_for_unit("multi-user.target")
node.wait_for_unit("portail.service")

self_ip = "192.168.1.100"

# Wait for the server to be ready.
corp_server.wait_for_unit("multi-user.target")

# Wait for NGINX to be ready.
corp_server.wait_for_open_port(80)
# corp_server.wait_for_open_port(443)

# Wait for the SOCK5 server to be ready.
node.wait_for_open_port(8080)

# Let's test SOCKS5 to hello.corp.example.com.

# This tests without DNS resolution.
result = json.loads(node.succeed(
"curl --fail --socks5 127.0.0.1:8080 http://hello.corp.example.com"
))
assert result['service'] == 'hello.corp' and result['remote_addr'] == self_ip, "Unexpected result from the web service: {}".format(json.dumps(result))
# This exercise the SOCKS5 DNS resolution.
result = json.loads(node.succeed(
"curl --fail --socks5-hostname 127.0.0.1:8080 http://hello.corp.example.com"
))
assert result['service'] == 'hello.corp' and result['remote_addr'] == self_ip, "Unexpected result from the web service: {}".format(json.dumps(result))
# TODO: Test HTTPS as well.

# This exercises rejections and ACLs.
# TODO: once ACLs are stabilized, uncomment.
# This tests without DNS resolution.
# node.fail(
# "curl --fail --socks5 127.0.0.1:8080 http://bad.corp.example.com"
# )
# This exercise the SOCKS5 DNS resolution.
# node.fail(
# "curl --fail --socks5-hostname 127.0.0.1:8080 http://bad.corp.example.com"
# )
'';
};

# This tests Portail connecting to microsocks as an upstream.
microsocks-upstream = pkgs.testers.nixosTest {
name = "microsocks-upstream";
nodes = {
node = {
microsocks = { nodes, ... }: {
networking.interfaces.eth1.ipv4.addresses = [
{
address = "192.168.1.50";
prefixLength = 24;
}
];

services.microsocks = {
enable = true;
ip = "0.0.0.0";
port = 8080;
};

networking.hosts."${nodes.corp-server.networking.primaryIPAddress}" = [ "hello.corp.example.com" "bad.corp.example.com" ];
networking.firewall.allowedTCPPorts = [ 8080 ];
};
corp-server = mkServiceNode { };
node = { nodes, ... }: {
imports = [ ../module.nix ];
networking.hosts."${nodes.corp-server.networking.primaryIPAddress}" = [ "hello.corp.example.com" "bad.corp.example.com" ];
networking.interfaces.eth1.ipv4.addresses = [
{
address = "192.168.1.100";
prefixLength = 24;
}
];
services.portail = {
enable = true;
enableAtBoot = true;
settings = {
default-backend = "default";
backends.default = {
target-address = "192.168.1.50:8080";
};
};
acl.filter.rules = [
"hello.corp.example.com -> allow"
];
};
};
};
testScript = ''
import json

start_all()

node.wait_for_unit("multi-user.target")
node.wait_for_unit("portail.service")

self_ip = "192.168.1.100"

# Wait for the server to be ready.
corp_server.wait_for_unit("multi-user.target")

# Wait for NGINX to be ready.
corp_server.wait_for_open_port(80)
# corp_server.wait_for_open_port(443)

# Wait for microsocks to be ready.
microsocks.wait_for_unit("microsocks.service")
microsocks.wait_for_open_port(8080)

# Wait for the SOCK5 server to be ready.
node.wait_for_open_port(8080)

# Let's test SOCKS5 to hello.corp.example.com.

# This tests without DNS resolution.
result = json.loads(node.succeed(
"curl --fail --socks5 127.0.0.1:8080 http://hello.corp.example.com"
))
assert result['service'] == 'hello.corp' and result['remote_addr'] != self_ip, "Unexpected result from the web service: {}".format(json.dumps(result))
# This exercise the SOCKS5 DNS resolution.
result = json.loads(node.succeed(
"curl --fail --socks5-hostname 127.0.0.1:8080 http://hello.corp.example.com"
))
assert result['service'] == 'hello.corp' and result['remote_addr'] != self_ip, "Unexpected result from the web service: {}".format(json.dumps(result))
'';
};

}
3 changes: 3 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ pub struct Settings {
#[serde(default)]
pub tcp_nodelay: bool,

/// Whether to set a default upstream.
pub default_backend: Option<String>,

/// List of backends to which we can route proxy queries.
#[serde(default)]
pub backends: HashMap<String, BackendSettings>,
Expand Down
2 changes: 1 addition & 1 deletion src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub struct Statistics {

pub fn init(settings: &Settings) -> State {
State {
default_backend: None,
default_backend: settings.default_backend.clone(),
acl_rules: crate::acl::load_rules_from_file(&settings.filter_acl_rules_path.clone().unwrap()).unwrap(),
root_store: None,
client_cert_resolver: None
Expand Down