mirror of
https://github.com/Rudd-O/qubes-network-server.git
synced 2025-03-01 14:22:35 +01:00
Neuter masquerading of outbound traffic from VMs in routing mode.
This commit is contained in:
parent
e9e65f7da1
commit
7b5cae5b0e
@ -3,7 +3,7 @@
|
|||||||
%define mybuildnumber %{?build_number}%{?!build_number:1}
|
%define mybuildnumber %{?build_number}%{?!build_number:1}
|
||||||
|
|
||||||
Name: qubes-network-server
|
Name: qubes-network-server
|
||||||
Version: 0.1.0
|
Version: 0.1.1
|
||||||
Release: %{mybuildnumber}%{?dist}
|
Release: %{mybuildnumber}%{?dist}
|
||||||
Summary: Turn your Qubes OS into a network server
|
Summary: Turn your Qubes OS into a network server
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
|
@ -65,9 +65,11 @@ ADDRESS_FAMILY_IPV6 = "ip6"
|
|||||||
ADDRESS_FAMILY_IPV4 = "ip"
|
ADDRESS_FAMILY_IPV4 = "ip"
|
||||||
TABLE_NAME = "qubes"
|
TABLE_NAME = "qubes"
|
||||||
FORWARD_CHAIN_NAME = "forward"
|
FORWARD_CHAIN_NAME = "forward"
|
||||||
|
POSTROUTING_CHAIN_NAME = "postrouting"
|
||||||
ROUTING_MANAGER_CHAIN_NAME = "qubes-routing-manager"
|
ROUTING_MANAGER_CHAIN_NAME = "qubes-routing-manager"
|
||||||
|
ROUTING_MANAGER_POSTROUTING_CHAIN_NAME = "qubes-routing-manager-postrouting"
|
||||||
NFTABLES_CMD = "nft"
|
NFTABLES_CMD = "nft"
|
||||||
ADD_RULE_AFTER_THIS_RULE = "custom-forward"
|
ADD_FORWARD_RULE_AFTER_THIS_RULE = "custom-forward"
|
||||||
|
|
||||||
|
|
||||||
def get_table(address_family: ADDRESS_FAMILIES, table: str) -> NFTablesOutput:
|
def get_table(address_family: ADDRESS_FAMILIES, table: str) -> NFTablesOutput:
|
||||||
@ -202,109 +204,157 @@ def setup_plain_forwarding_for_address(source: str, enable: bool, family: int) -
|
|||||||
forward_chain = [x for x in existing_chains if x["name"] == FORWARD_CHAIN_NAME][
|
forward_chain = [x for x in existing_chains if x["name"] == FORWARD_CHAIN_NAME][
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
|
postrouting_chain = [
|
||||||
|
x for x in existing_chains if x["name"] == POSTROUTING_CHAIN_NAME
|
||||||
|
][0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
logging.warn(
|
logging.warn(
|
||||||
"No forward chain in table %s, not setting up forwarding", TABLE_NAME
|
"No forward or postrouting chains in table %s, not setting up forwarding",
|
||||||
|
TABLE_NAME,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
qubes_routing_manager_chain: None | Chain = None
|
for chain_name in [
|
||||||
try:
|
ROUTING_MANAGER_CHAIN_NAME,
|
||||||
qubes_routing_manager_chain = [
|
ROUTING_MANAGER_POSTROUTING_CHAIN_NAME,
|
||||||
x for x in existing_chains if x["name"] == ROUTING_MANAGER_CHAIN_NAME
|
]:
|
||||||
].pop()
|
chain: None | Chain = None
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not qubes_routing_manager_chain:
|
|
||||||
logging.info(
|
|
||||||
"Adding %s chain to table %s", ROUTING_MANAGER_CHAIN_NAME, TABLE_NAME
|
|
||||||
)
|
|
||||||
add_chain(af, TABLE_NAME, ROUTING_MANAGER_CHAIN_NAME)
|
|
||||||
|
|
||||||
qubes_routing_manager_rule: None | Rule = None
|
|
||||||
try:
|
|
||||||
qubes_routing_manager_rule = [
|
|
||||||
x
|
|
||||||
for x in existing_rules
|
|
||||||
if x["chain"] == forward_chain["name"]
|
|
||||||
and x["family"] == af
|
|
||||||
and len(x["expr"]) == 1
|
|
||||||
and x["expr"][0].get("jump", {}).get("target") == ROUTING_MANAGER_CHAIN_NAME
|
|
||||||
].pop()
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not qubes_routing_manager_rule:
|
|
||||||
try:
|
try:
|
||||||
custom_forwarding_rule = [
|
chain = [x for x in existing_chains if x["name"] == chain_name].pop()
|
||||||
x
|
|
||||||
for x in existing_rules
|
|
||||||
if x["chain"] == forward_chain["name"]
|
|
||||||
and len(x["expr"]) == 1
|
|
||||||
and x["expr"][0].get("jump", {}).get("target")
|
|
||||||
== ADD_RULE_AFTER_THIS_RULE
|
|
||||||
][0]
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
logging.warn(
|
pass
|
||||||
"No state forwarding rule in chain %s of table %s, not setting up forwarding",
|
|
||||||
forward_chain["name"],
|
if not chain:
|
||||||
|
logging.info(
|
||||||
|
"Adding %s chain to table %s and counter to chain",
|
||||||
|
chain_name,
|
||||||
TABLE_NAME,
|
TABLE_NAME,
|
||||||
)
|
)
|
||||||
logging.info(
|
add_chain(af, TABLE_NAME, chain_name)
|
||||||
"Adding rule to jump to %s to table %s after jump to %s",
|
append_counter_at_end(
|
||||||
ROUTING_MANAGER_CHAIN_NAME,
|
af,
|
||||||
TABLE_NAME,
|
TABLE_NAME,
|
||||||
ADD_RULE_AFTER_THIS_RULE,
|
chain_name,
|
||||||
)
|
)
|
||||||
append_rule_after(
|
|
||||||
af,
|
def is_forward_jump_to_custom_forward(rule):
|
||||||
TABLE_NAME,
|
return (
|
||||||
forward_chain["name"],
|
rule["chain"] == forward_chain["name"]
|
||||||
custom_forwarding_rule["handle"],
|
and len(rule["expr"]) == 1
|
||||||
"jump",
|
and rule["expr"][0].get("jump", {}).get("target")
|
||||||
ROUTING_MANAGER_CHAIN_NAME,
|
== ADD_FORWARD_RULE_AFTER_THIS_RULE
|
||||||
)
|
|
||||||
append_counter_at_end(
|
|
||||||
af,
|
|
||||||
TABLE_NAME,
|
|
||||||
ROUTING_MANAGER_CHAIN_NAME,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
address_rules = [
|
def is_postrouting_lo_accept(rule):
|
||||||
x
|
return (
|
||||||
for x in existing_rules
|
rule["chain"] == postrouting_chain["name"]
|
||||||
if x["chain"] == ROUTING_MANAGER_CHAIN_NAME
|
and len(rule["expr"]) == 2
|
||||||
and len(x["expr"]) == 2
|
and rule["expr"][0].get("match", {}).get("op", "") == "=="
|
||||||
and x["expr"][0].get("match", {}).get("op", {}) == "=="
|
and rule["expr"][0]
|
||||||
and x["expr"][0]["match"].get("left", {}).get("payload", {}).get("protocol", "")
|
.get("match", {})
|
||||||
== af
|
.get("left", {})
|
||||||
and x["expr"][0]["match"]["left"]["payload"].get("field", "") == "daddr"
|
.get("meta", {})
|
||||||
and x["expr"][0].get("match", {}).get("right", []) == source
|
.get("key")
|
||||||
and "accept" in x["expr"][1]
|
== "oif"
|
||||||
]
|
and rule["expr"][0].get("match", {}).get("right", "") == "lo"
|
||||||
|
and "accept" in rule["expr"][1]
|
||||||
|
)
|
||||||
|
|
||||||
if enable and not address_rules:
|
for parent_chain, child_chain_name, previous_rule_detector in [
|
||||||
logging.info(
|
(
|
||||||
"Adding accept rule on chain %s to allow traffic to %s.",
|
forward_chain,
|
||||||
ROUTING_MANAGER_CHAIN_NAME,
|
ROUTING_MANAGER_CHAIN_NAME,
|
||||||
source,
|
is_forward_jump_to_custom_forward,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
postrouting_chain,
|
||||||
|
ROUTING_MANAGER_POSTROUTING_CHAIN_NAME,
|
||||||
|
is_postrouting_lo_accept,
|
||||||
|
),
|
||||||
|
]:
|
||||||
|
jump_rule: None | Rule = None
|
||||||
|
try:
|
||||||
|
jump_rule = [
|
||||||
|
x
|
||||||
|
for x in existing_rules
|
||||||
|
if x["chain"] == parent_chain["name"]
|
||||||
|
and x["family"] == af
|
||||||
|
and len(x["expr"]) == 1
|
||||||
|
and x["expr"][0].get("jump", {}).get("target") == child_chain_name
|
||||||
|
].pop()
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not jump_rule:
|
||||||
|
try:
|
||||||
|
previous_rule = [
|
||||||
|
x for x in existing_rules if previous_rule_detector(x)
|
||||||
|
][0]
|
||||||
|
except IndexError:
|
||||||
|
logging.warn(
|
||||||
|
"Cannot find appropriate previous rule in chain %s of table %s, not setting up forwarding",
|
||||||
|
parent_chain["name"],
|
||||||
|
TABLE_NAME,
|
||||||
|
)
|
||||||
|
logging.info(
|
||||||
|
"Adding rule to jump from chain %s to chain %s in table %s",
|
||||||
|
parent_chain["name"],
|
||||||
|
child_chain_name,
|
||||||
|
TABLE_NAME,
|
||||||
|
)
|
||||||
|
append_rule_after(
|
||||||
|
af,
|
||||||
|
TABLE_NAME,
|
||||||
|
parent_chain["name"],
|
||||||
|
previous_rule["handle"],
|
||||||
|
"jump",
|
||||||
|
child_chain_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
def detect_ip_rule(rule: Rule, chain_name: str, ip: str, mode: str):
|
||||||
|
return (
|
||||||
|
rule["chain"] == chain_name
|
||||||
|
and len(rule["expr"]) == 2
|
||||||
|
and rule["expr"][0].get("match", {}).get("op", {}) == "=="
|
||||||
|
and rule["expr"][0]["match"]
|
||||||
|
.get("left", {})
|
||||||
|
.get("payload", {})
|
||||||
|
.get("protocol", "")
|
||||||
|
== af
|
||||||
|
and rule["expr"][0]["match"]["left"]["payload"].get("field", "") == mode
|
||||||
|
and rule["expr"][0].get("match", {}).get("right", []) == ip
|
||||||
|
and "accept" in rule["expr"][1]
|
||||||
)
|
)
|
||||||
append_rule_at_end(
|
|
||||||
af,
|
for chain_name, mode in [
|
||||||
TABLE_NAME,
|
(ROUTING_MANAGER_CHAIN_NAME, "daddr"),
|
||||||
ROUTING_MANAGER_CHAIN_NAME,
|
(ROUTING_MANAGER_POSTROUTING_CHAIN_NAME, "saddr"),
|
||||||
af,
|
]:
|
||||||
"daddr",
|
address_rules = [
|
||||||
source,
|
x for x in existing_rules if detect_ip_rule(x, chain_name, source, mode)
|
||||||
"accept",
|
]
|
||||||
)
|
|
||||||
elif not enable and address_rules:
|
if enable and not address_rules:
|
||||||
logging.info(
|
logging.info(
|
||||||
"Removing %s accept rules from chain %s to stop traffic to %s.",
|
"Adding accept rule on chain %s for %s.",
|
||||||
len(address_rules),
|
chain_name,
|
||||||
ROUTING_MANAGER_CHAIN_NAME,
|
source,
|
||||||
source,
|
)
|
||||||
)
|
append_rule_at_end(
|
||||||
for rule in reversed(sorted(address_rules, key=lambda r: r["handle"])):
|
af,
|
||||||
delete_rule(af, TABLE_NAME, ROUTING_MANAGER_CHAIN_NAME, rule["handle"])
|
TABLE_NAME,
|
||||||
|
chain_name,
|
||||||
|
af,
|
||||||
|
mode,
|
||||||
|
source,
|
||||||
|
"accept",
|
||||||
|
)
|
||||||
|
elif not enable and address_rules:
|
||||||
|
logging.info(
|
||||||
|
"Removing %s accept rules from chain %s for %s.",
|
||||||
|
len(address_rules),
|
||||||
|
chain_name,
|
||||||
|
source,
|
||||||
|
)
|
||||||
|
for rule in reversed(sorted(address_rules, key=lambda r: r["handle"])):
|
||||||
|
delete_rule(af, TABLE_NAME, chain_name, rule["handle"])
|
||||||
|
1580
qubesroutingmanager/fixtures/fully_added.json
Normal file
1580
qubesroutingmanager/fixtures/fully_added.json
Normal file
File diff suppressed because it is too large
Load Diff
1532
qubesroutingmanager/fixtures/partially_added.json
Normal file
1532
qubesroutingmanager/fixtures/partially_added.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user