Skip to content

Commit 48dd5e9

Browse files
author
Capirca Team
committed
Merge pull request #275 from kevinsteves:br12
PiperOrigin-RevId: 375543842
2 parents f25094a + 74fa62d commit 48dd5e9

2 files changed

Lines changed: 99 additions & 18 deletions

File tree

capirca/lib/paloaltofw.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,10 @@ class ServiceMap(object):
141141
def __init__(self):
142142
self.entries = {}
143143

144-
def get_service_name(self, term_name, ports, protocol):
144+
def get_service_name(self, term_name, src_ports, ports, protocol):
145145
"""Returns service name based on the provided ports and protocol."""
146-
if (ports, protocol) in self.entries:
147-
return self.entries[(ports, protocol)]["name"]
146+
if (src_ports, ports, protocol) in self.entries:
147+
return self.entries[(src_ports, ports, protocol)]["name"]
148148

149149
service_name = "service-%s-%s" % (term_name, protocol)
150150

@@ -158,7 +158,7 @@ def get_service_name(self, term_name, ports, protocol):
158158
"You have a duplicate service. A service named %s already exists." %
159159
service_name)
160160

161-
self.entries[(ports, protocol)] = {"name": service_name}
161+
self.entries[(src_ports, ports, protocol)] = {"name": service_name}
162162
return service_name
163163

164164

@@ -195,6 +195,16 @@ def ModifyOptions(self, terms, service_map):
195195
self.options["service"] = []
196196
self.options["logging"] = []
197197

198+
def pan_ports(ports):
199+
x = []
200+
for tup in ports:
201+
if len(tup) > 1 and tup[0] != tup[1]:
202+
x.append(str(tup[0]) + "-" + str(tup[1]))
203+
else:
204+
x.append(str(tup[0]))
205+
206+
return tuple(x)
207+
198208
# COMMENT
199209
if term.comment:
200210
self.options["description"] = term.comment
@@ -244,18 +254,17 @@ def ModifyOptions(self, terms, service_map):
244254
for pan_app in term.pan_application:
245255
self.options["application"].append(pan_app)
246256

247-
if term.destination_port:
248-
ports = []
249-
for tup in term.destination_port:
250-
if len(tup) > 1 and tup[0] != tup[1]:
251-
ports.append(str(tup[0]) + "-" + str(tup[1]))
252-
else:
253-
ports.append(str(tup[0]))
254-
ports = tuple(ports)
257+
if term.source_port or term.destination_port:
258+
src_ports = pan_ports(term.source_port)
259+
if term.destination_port:
260+
ports = pan_ports(term.destination_port)
261+
else:
262+
ports = pan_ports([("0", "65535")])
255263

256264
# check to see if this service already exists
257265
for p in term.protocol:
258-
service_name = service_map.get_service_name(term.name, ports, p)
266+
service_name = service_map.get_service_name(term.name,
267+
src_ports, ports, p)
259268
if service_name not in self.options["service"]:
260269
self.options["service"].append(service_name)
261270

@@ -757,12 +766,20 @@ def __str__(self):
757766
for k, v in self.service_map.entries.items():
758767
entry = etree.SubElement(service, "entry", {"name": v["name"]})
759768
proto0 = etree.SubElement(entry, "protocol")
760-
proto = etree.SubElement(proto0, k[1])
769+
proto = etree.SubElement(proto0, k[2])
770+
# destination port
761771
port = etree.SubElement(proto, "port")
762-
tup = str(k[0])[1:-1]
772+
tup = str(k[1])[1:-1]
763773
if tup[-1] == ",":
764774
tup = tup[:-1]
765775
port.text = tup.replace("'", "").replace(", ", ",")
776+
# source port
777+
if len(k[0]):
778+
sport = etree.SubElement(proto, "source-port")
779+
tup = str(k[0])[1:-1]
780+
if tup[-1] == ",":
781+
tup = tup[:-1]
782+
sport.text = tup.replace("'", "").replace(", ", ",")
766783

767784
# RULES
768785
vsys_entry.append(etree.Comment(" Rules "))

tests/lib/paloaltofw_test.py

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@
440440
PATH_VSYS = "./devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']"
441441
PATH_RULES = PATH_VSYS + '/rulebase/security/rules'
442442
PATH_TAG = PATH_VSYS + '/tag'
443+
PATH_SERVICE = PATH_VSYS + '/service'
443444

444445

445446
class PaloAltoFWTest(unittest.TestCase):
@@ -472,10 +473,10 @@ def testServiceMap(self):
472473
policy.ParsePolicy(GOOD_HEADER_1 + SVC_TERM_1, definitions), EXP_INFO)
473474
self.assertEqual(
474475
pol1.service_map.entries, {
475-
(('22',), 'tcp'): {
476+
((), ('22',), 'tcp'): {
476477
'name': 'service-ssh-term-1-tcp'
477478
},
478-
(('25',), 'tcp'): {
479+
((), ('25',), 'tcp'): {
479480
'name': 'service-smtp-term-1-tcp'
480481
}
481482
}, pol1.service_map.entries)
@@ -485,7 +486,7 @@ def testServiceMap(self):
485486
# The expectation is that there will be a single port mapped.
486487
self.assertEqual(
487488
pol2.service_map.entries, {
488-
(('25',), 'tcp'): {
489+
((), ('25',), 'tcp'): {
489490
'name': 'service-smtp-term-1-tcp'
490491
}
491492
}, pol2.service_map.entries)
@@ -869,6 +870,69 @@ def testPanApplication(self):
869870
apps = {elem.text for elem in x}
870871
self.assertEqual(APPS[i], apps, output)
871872

873+
def testPanPorts(self):
874+
POL = """
875+
header {
876+
target:: paloalto from-zone trust to-zone untrust
877+
}
878+
term rule-1 {
879+
%s
880+
action:: accept
881+
}"""
882+
883+
T = """
884+
protocol:: udp
885+
destination-port:: NTP
886+
"""
887+
888+
definitions = naming.Naming()
889+
definitions._ParseLine('NTP = 123/tcp 123/udp', 'services')
890+
definitions._ParseLine('DNS = 53/tcp 53/udp', 'services')
891+
892+
pol = policy.ParsePolicy(POL % T, definitions)
893+
paloalto = paloaltofw.PaloAltoFW(pol, EXP_INFO)
894+
output = str(paloalto)
895+
name = "service-rule-1-udp"
896+
path = "/entry[@name='%s']/protocol/udp/port" % name
897+
x = paloalto.config.findtext(PATH_SERVICE + path)
898+
self.assertEqual(x, "123", output)
899+
path = "/entry[@name='%s']/protocol/udp/source-port" % name
900+
x = paloalto.config.findtext(PATH_SERVICE + path)
901+
self.assertIsNone(x, output)
902+
903+
T = """
904+
protocol:: udp
905+
source-port:: NTP
906+
"""
907+
908+
pol = policy.ParsePolicy(POL % T, definitions)
909+
paloalto = paloaltofw.PaloAltoFW(pol, EXP_INFO)
910+
output = str(paloalto)
911+
name = "service-rule-1-udp"
912+
path = "/entry[@name='%s']/protocol/udp/port" % name
913+
x = paloalto.config.findtext(PATH_SERVICE + path)
914+
self.assertEqual(x, "0-65535", output)
915+
path = "/entry[@name='%s']/protocol/udp/source-port" % name
916+
x = paloalto.config.findtext(PATH_SERVICE + path)
917+
self.assertEqual(x, "123", output)
918+
919+
T = """
920+
protocol:: tcp
921+
source-port:: NTP
922+
destination-port:: NTP DNS
923+
"""
924+
925+
pol = policy.ParsePolicy(POL % T, definitions)
926+
paloalto = paloaltofw.PaloAltoFW(pol, EXP_INFO)
927+
output = str(paloalto)
928+
name = "service-rule-1-tcp"
929+
path = "/entry[@name='%s']/protocol/tcp/port" % name
930+
x = paloalto.config.findtext(PATH_SERVICE + path)
931+
self.assertEqual(x, "53,123", output)
932+
path = "/entry[@name='%s']/protocol/tcp/source-port" % name
933+
x = paloalto.config.findtext(PATH_SERVICE + path)
934+
self.assertEqual(x, "123", output)
935+
872936

873937
if __name__ == '__main__':
874938
unittest.main()

0 commit comments

Comments
 (0)