Skip to content

Commit a9cb284

Browse files
Add OpenWRT firewall redirect handling
This commit: - Adds a schema for redirects - Adds a renderer and parser for redirects - Adds initial tests for redirects
1 parent 9c08c8c commit a9cb284

File tree

3 files changed

+363
-9
lines changed

3 files changed

+363
-9
lines changed

netjsonconfig/backends/openwrt/converters/firewall.py

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@
1414
class Firewall(OpenWrtConverter):
1515
netjson_key = "firewall"
1616
intermediate_key = "firewall"
17-
_uci_types = ["defaults", "forwarding", "zone", "rule"]
17+
_uci_types = ["defaults", "forwarding", "zone", "rule", "redirect"]
1818
_schema = schema["properties"]["firewall"]
1919

2020
def to_intermediate_loop(self, block, result, index=None):
2121
forwardings = self.__intermediate_forwardings(block.pop("forwardings", {}))
2222
zones = self.__intermediate_zones(block.pop("zones", {}))
2323
rules = self.__intermediate_rules(block.pop("rules", {}))
24+
redirects = self.__intermediate_redirects(block.pop("redirects", {}))
2425
block.update({".type": "defaults", ".name": block.pop("id", "defaults")})
2526
result.setdefault("firewall", [])
26-
result["firewall"] = [self.sorted_dict(block)] + forwardings + zones + rules
27+
result["firewall"] = (
28+
[self.sorted_dict(block)] + forwardings + zones + rules + redirects
29+
)
2730
return result
2831

2932
def __intermediate_forwardings(self, forwardings):
@@ -104,6 +107,37 @@ def __intermediate_rules(self, rules):
104107
def __get_auto_name_rule(self, rule):
105108
return "rule_{0}".format(self._get_uci_name(rule["name"]))
106109

110+
def __intermediate_redirects(self, redirects):
111+
"""
112+
converts NetJSON redirect to
113+
UCI intermediate data structure
114+
"""
115+
result = []
116+
for redirect in redirects:
117+
if "config_name" in redirect:
118+
del redirect["config_name"]
119+
resultdict = OrderedDict(
120+
(
121+
(".name", self.__get_auto_name_redirect(redirect)),
122+
(".type", "redirect"),
123+
)
124+
)
125+
if "proto" in redirect:
126+
# If proto is a single value, then force it not to be in a list so that
127+
# the UCI uses "option" rather than "list". If proto is only "tcp"
128+
# and"udp", we can force it to the single special value of "tcpudp".
129+
proto = redirect["proto"]
130+
if len(proto) == 1:
131+
redirect["proto"] = proto[0]
132+
elif set(proto) == {"tcp", "udp"}:
133+
redirect["proto"] = "tcpudp"
134+
resultdict.update(redirect)
135+
result.append(resultdict)
136+
return result
137+
138+
def __get_auto_name_redirect(self, redirect):
139+
return "redirect_{0}".format(self._get_uci_name(redirect["name"]))
140+
107141
def to_netjson_loop(self, block, result, index):
108142
result.setdefault("firewall", {})
109143

@@ -122,6 +156,10 @@ def to_netjson_loop(self, block, result, index):
122156
forwarding = self.__netjson_forwarding(block)
123157
result["firewall"].setdefault("forwardings", [])
124158
result["firewall"]["forwardings"].append(forwarding)
159+
if _type == "redirect":
160+
redirect = self.__netjson_redirect(block)
161+
result["firewall"].setdefault("redirects", [])
162+
result["firewall"]["redirects"].append(redirect)
125163

126164
return self.type_cast(result)
127165

@@ -156,3 +194,14 @@ def __netjson_zone(self, zone):
156194

157195
def __netjson_forwarding(self, forwarding):
158196
return self.type_cast(forwarding)
197+
198+
def __netjson_redirect(self, redirect):
199+
if "proto" in redirect:
200+
proto = redirect.pop("proto")
201+
if not isinstance(proto, list):
202+
if proto == "tcpudp":
203+
redirect["proto"] = ["tcp", "udp"]
204+
else:
205+
redirect["proto"] = [proto]
206+
207+
return self.type_cast(redirect)

0 commit comments

Comments
 (0)