Compare commits
4 Commits
f4e31ceebe
...
262e11ba7c
Author | SHA1 | Date | |
---|---|---|---|
262e11ba7c | |||
00c43503a9 | |||
4479dd486d | |||
6b5d54ecdf |
15
README.md
15
README.md
@@ -110,10 +110,18 @@ addr =
|
|||||||
ports = 80, 443
|
ports = 80, 443
|
||||||
proto = tcp
|
proto = tcp
|
||||||
state = NEW
|
state = NEW
|
||||||
|
hitcount =
|
||||||
do_ipv6 = false
|
do_ipv6 = false
|
||||||
firewalld_direct_file_abs = /etc/firewalld/direct.xml
|
firewalld_direct_file_abs = /etc/firewalld/direct.xml
|
||||||
restart_firewalld_after_change = true
|
restart_firewalld_after_change = true
|
||||||
|
|
||||||
|
[anyone-may-icmp-with-limit]
|
||||||
|
addr =
|
||||||
|
ports =
|
||||||
|
proto = icmp
|
||||||
|
state = NEW,UNTRACKED
|
||||||
|
hitcount = 120/60
|
||||||
|
|
||||||
[anyone-can-access-website]
|
[anyone-can-access-website]
|
||||||
|
|
||||||
# Unsetting 'proto' while having a 'ports' value results in an invalid section
|
# Unsetting 'proto' while having a 'ports' value results in an invalid section
|
||||||
@@ -128,8 +136,9 @@ addr = 2606:4700:20::681a:804, lowendtalk.com
|
|||||||
ports = 80, 443
|
ports = 80, 443
|
||||||
do_ipv6 = true
|
do_ipv6 = true
|
||||||
|
|
||||||
[allow-anyone-to-access-mail-services]
|
[anyone-may-access-mail-services]
|
||||||
ports = 143, 993, 110, 995, 25, 465, 587
|
ports = 143, 993, 110, 995, 25, 465, 587
|
||||||
|
hitcount = 120/60
|
||||||
|
|
||||||
[deny-all]
|
[deny-all]
|
||||||
target = DROP
|
target = DROP
|
||||||
@@ -265,6 +274,10 @@ A custom `[section]` has the following options. We're calling them locals most o
|
|||||||
state =
|
state =
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* `hitcount`, **_optional_**, defaults to an empty value: A rate-limiting feature. Set this to `hits/seconds` to limit the amount of matched packets to `hits` over the course of `seconds`, e.g. `10/60` sets the maximum packet rate to 10 packets over the course of 60 seconds. Any packet exceeding the rate will be dropped.
|
||||||
|
|
||||||
|
Adding a `hitcount` will automatically add 2 `ip(6)tables` rules right before the actual rules. Rules follow the [iptables "recent" extension](https://ipset.netfilter.org/iptables-extensions.man.html#lbBW). The first rule does `--update`, the second one does `--set` followed by the rule you specified.
|
||||||
|
|
||||||
* `do_ipv6`, __*optional*__, defaults to `false`: Decide if you want `firewalld` to generate `ip6tables` rules in addition to `iptables` rules. A default install of Docker Engine will have its IPv6 support disabled in `/etc/docker/daemon.json`. You may still want your machine to handle incoming IPv6 traffic. If your machine truly doesn't use IPv6 feel free to leave this at `false`. Otherwise `update-firewall-source.py` generates unused rules that clutter your rule set.
|
* `do_ipv6`, __*optional*__, defaults to `false`: Decide if you want `firewalld` to generate `ip6tables` rules in addition to `iptables` rules. A default install of Docker Engine will have its IPv6 support disabled in `/etc/docker/daemon.json`. You may still want your machine to handle incoming IPv6 traffic. If your machine truly doesn't use IPv6 feel free to leave this at `false`. Otherwise `update-firewall-source.py` generates unused rules that clutter your rule set.
|
||||||
|
|
||||||
If this is `true` IPv6 addresses found or resolved in `addr` in a `[section]` will be discarded.
|
If this is `true` IPv6 addresses found or resolved in `addr` in a `[section]` will be discarded.
|
||||||
|
@@ -4,10 +4,18 @@ addr =
|
|||||||
ports = 80, 443
|
ports = 80, 443
|
||||||
proto = tcp
|
proto = tcp
|
||||||
state = NEW
|
state = NEW
|
||||||
|
hitcount =
|
||||||
do_ipv6 = false
|
do_ipv6 = false
|
||||||
firewalld_direct_file_abs = /etc/firewalld/direct.xml
|
firewalld_direct_file_abs = /etc/firewalld/direct.xml
|
||||||
restart_firewalld_after_change = true
|
restart_firewalld_after_change = true
|
||||||
|
|
||||||
|
[anyone-may-icmp-with-limit]
|
||||||
|
addr =
|
||||||
|
ports =
|
||||||
|
proto = icmp
|
||||||
|
state = NEW,UNTRACKED
|
||||||
|
hitcount = 120/60
|
||||||
|
|
||||||
[anyone-can-access-website]
|
[anyone-can-access-website]
|
||||||
|
|
||||||
# Unsetting 'proto' while having a 'ports' value results in an invalid section
|
# Unsetting 'proto' while having a 'ports' value results in an invalid section
|
||||||
@@ -22,8 +30,9 @@ addr = 2606:4700:20::681a:804, lowendtalk.com
|
|||||||
ports = 80, 443
|
ports = 80, 443
|
||||||
do_ipv6 = true
|
do_ipv6 = true
|
||||||
|
|
||||||
[allow-anyone-to-access-mail-services]
|
[anyone-may-access-mail-services]
|
||||||
ports = 143, 993, 110, 995, 25, 465, 587
|
ports = 143, 993, 110, 995, 25, 465, 587
|
||||||
|
hitcount = 120/60
|
||||||
|
|
||||||
[deny-all]
|
[deny-all]
|
||||||
target = DROP
|
target = DROP
|
||||||
|
@@ -58,6 +58,7 @@ class CONST(object):
|
|||||||
{"key": "ports", "value": "80, 443", "is_global": False, "empty_ok": True},
|
{"key": "ports", "value": "80, 443", "is_global": False, "empty_ok": True},
|
||||||
{"key": "proto", "value": "tcp", "is_global": False, "empty_ok": True},
|
{"key": "proto", "value": "tcp", "is_global": False, "empty_ok": True},
|
||||||
{"key": "state", "value": "NEW", "is_global": False, "empty_ok": True},
|
{"key": "state", "value": "NEW", "is_global": False, "empty_ok": True},
|
||||||
|
{"key": "hitcount", "value": "", "is_global": False, "empty_ok": True},
|
||||||
{"key": "do_ipv6", "value": "false", "is_global": False, "empty_ok": False},
|
{"key": "do_ipv6", "value": "false", "is_global": False, "empty_ok": False},
|
||||||
{"key": "firewalld_direct_abs", "value": "/etc/firewalld/direct.xml", "is_global": True, "empty_ok": False},
|
{"key": "firewalld_direct_abs", "value": "/etc/firewalld/direct.xml", "is_global": True, "empty_ok": False},
|
||||||
{"key": "restart_firewalld_after_change", "value": "true", "is_global": True, "empty_ok": False}
|
{"key": "restart_firewalld_after_change", "value": "true", "is_global": True, "empty_ok": False}
|
||||||
@@ -290,6 +291,7 @@ def add_rule_elem(
|
|||||||
arg_proto: str = None,
|
arg_proto: str = None,
|
||||||
arg_state: str = None,
|
arg_state: str = None,
|
||||||
arg_ports: list = None,
|
arg_ports: list = None,
|
||||||
|
arg_hitcount: str = None,
|
||||||
arg_address: str = None,
|
arg_address: str = None,
|
||||||
arg_chain: str = "FILTERS",
|
arg_chain: str = "FILTERS",
|
||||||
arg_in_interface: str = None) -> bool:
|
arg_in_interface: str = None) -> bool:
|
||||||
@@ -300,6 +302,43 @@ def add_rule_elem(
|
|||||||
arg_proto = "icmp"
|
arg_proto = "icmp"
|
||||||
if arg_proto == "icmp" and address_family == "ipv6":
|
if arg_proto == "icmp" and address_family == "ipv6":
|
||||||
arg_proto = "icmpv6"
|
arg_proto = "icmpv6"
|
||||||
|
|
||||||
|
if arg_hitcount:
|
||||||
|
try:
|
||||||
|
lxml.etree.SubElement(arg_fw_rule_data, "rule",
|
||||||
|
ipv=f"{address_family}",
|
||||||
|
table=f"filter",
|
||||||
|
chain=arg_chain,
|
||||||
|
priority=f"""{prio}""").text = \
|
||||||
|
f"""{"--in-interface " + arg_in_interface + " " if arg_in_interface else ""}""" \
|
||||||
|
f"""{"--protocol " + arg_proto + " " if arg_proto else ""}""" \
|
||||||
|
f"""{"--match multiport --destination-ports " + ",".join(arg_ports) + " " if arg_ports else ""}""" \
|
||||||
|
f"""{"--source " + arg_address + " " if arg_address else ""}""" \
|
||||||
|
f"""{"--match recent --name " + chr(34) + arg_section[:256] + chr(34) +
|
||||||
|
" --update --hitcount " + arg_hitcount.split("/")[0] + " --seconds " + arg_hitcount.split("/")[1] + " "
|
||||||
|
if arg_section else ""}""" \
|
||||||
|
f"""--jump DROP"""
|
||||||
|
prio += 1
|
||||||
|
|
||||||
|
lxml.etree.SubElement(arg_fw_rule_data, "rule",
|
||||||
|
ipv=f"{address_family}",
|
||||||
|
table=f"filter",
|
||||||
|
chain=arg_chain,
|
||||||
|
priority=f"""{prio}""").text = \
|
||||||
|
f"""{"--in-interface " + arg_in_interface + " " if arg_in_interface else ""}""" \
|
||||||
|
f"""{"--protocol " + arg_proto + " " if arg_proto else ""}""" \
|
||||||
|
f"""{"--match multiport --destination-ports " + ",".join(arg_ports) + " " if arg_ports else ""}""" \
|
||||||
|
f"""{"--source " + arg_address + " " if arg_address else ""}""" \
|
||||||
|
f"""{"--match recent --name " + chr(34) + arg_section[:256] + chr(34) +
|
||||||
|
" --set" if arg_section else ""}"""
|
||||||
|
prio += 1
|
||||||
|
except lxml.etree.LxmlError as le:
|
||||||
|
log.error(f"""Failed to add XML '<rule ipv=f"{address_family}" .../>'\n"""
|
||||||
|
f"Verbatim exception was:\n"
|
||||||
|
f"f{le}\n"
|
||||||
|
f"Exiting 8 ...")
|
||||||
|
sys.exit(8)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
lxml.etree.SubElement(arg_fw_rule_data, "rule",
|
lxml.etree.SubElement(arg_fw_rule_data, "rule",
|
||||||
ipv=f"{address_family}",
|
ipv=f"{address_family}",
|
||||||
@@ -369,7 +408,8 @@ def add_fw_rule_to_xml(
|
|||||||
section_name: str,
|
section_name: str,
|
||||||
target: str,
|
target: str,
|
||||||
ports: list,
|
ports: list,
|
||||||
proto: str) -> bool:
|
proto: str,
|
||||||
|
hitcount: str) -> bool:
|
||||||
global arg_fw_rule_data
|
global arg_fw_rule_data
|
||||||
global arg_allow_sources
|
global arg_allow_sources
|
||||||
addr = arg_allow_sources
|
addr = arg_allow_sources
|
||||||
@@ -390,8 +430,12 @@ def add_fw_rule_to_xml(
|
|||||||
arg_proto=proto,
|
arg_proto=proto,
|
||||||
arg_state=config_obj.get(section_name, "state"),
|
arg_state=config_obj.get(section_name, "state"),
|
||||||
arg_ports=ports,
|
arg_ports=ports,
|
||||||
|
arg_hitcount=hitcount,
|
||||||
arg_address=address)
|
arg_address=address)
|
||||||
rules_already_added[address_family] += 1
|
if hitcount:
|
||||||
|
rules_already_added[address_family] += 3
|
||||||
|
else:
|
||||||
|
rules_already_added[address_family] += 1
|
||||||
if not len(addr["ipv4"]) and not len(addr["ipv6"]):
|
if not len(addr["ipv4"]) and not len(addr["ipv6"]):
|
||||||
if address_family == "ipv4" or (address_family == "ipv6"
|
if address_family == "ipv4" or (address_family == "ipv6"
|
||||||
and
|
and
|
||||||
@@ -405,8 +449,12 @@ def add_fw_rule_to_xml(
|
|||||||
arg_section=section_name,
|
arg_section=section_name,
|
||||||
arg_proto=proto,
|
arg_proto=proto,
|
||||||
arg_state=config_obj.get(section_name, "state"),
|
arg_state=config_obj.get(section_name, "state"),
|
||||||
arg_ports=ports)
|
arg_ports=ports,
|
||||||
rules_already_added[address_family] += 1
|
arg_hitcount=hitcount)
|
||||||
|
if hitcount:
|
||||||
|
rules_already_added[address_family] += 3
|
||||||
|
else:
|
||||||
|
rules_already_added[address_family] += 1
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -624,7 +672,8 @@ if __name__ == "__main__":
|
|||||||
section,
|
section,
|
||||||
target=config.get(section, "target"),
|
target=config.get(section, "target"),
|
||||||
ports=config.getlist(section, "ports"),
|
ports=config.getlist(section, "ports"),
|
||||||
proto=config.get(section, "proto"))
|
proto=config.get(section, "proto"),
|
||||||
|
hitcount=config.get(section, "hitcount"))
|
||||||
for arg_address_family in ["ipv4", "ipv6"]:
|
for arg_address_family in ["ipv4", "ipv6"]:
|
||||||
if rules_count(arg_address_family):
|
if rules_count(arg_address_family):
|
||||||
add_rule_elem(
|
add_rule_elem(
|
||||||
|
Reference in New Issue
Block a user