Skip to content

Commit eb5c9d4

Browse files
rdsharmaCapirca Team
authored andcommitted
Add generator patterns documentation
PiperOrigin-RevId: 347106320
1 parent fad05d4 commit eb5c9d4

File tree

1 file changed

+367
-0
lines changed

1 file changed

+367
-0
lines changed

doc/generator_patterns.md

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
# Common Patterns For Generators
2+
3+
<!--* # copybara:strip_begin(internal linter)
4+
# LINT.IfChange
5+
# copybara:strip_end *-->
6+
7+
## Objective
8+
9+
The purpose of this document is to describe common patterns for new Capirca
10+
Generators.
11+
12+
## Security based requirements:
13+
14+
### Inet_version ‘Mixed’ Platform Support
15+
16+
#### When the platform does not support “mixed” in a single access-list
17+
18+
##### Problem
19+
20+
When the inet_version is set to ‘mixed’ it implies that the resultant policy
21+
should contain addresses from both families. Some platforms do not support both
22+
address families to exist in the same filter therefore leading to Capirca
23+
generators needing to handle the output differently for those platforms. Cisco
24+
is an example platform that does not support a mixed filter being generated, and
25+
therefore it requires two separate *access-list* filters.
26+
27+
Platforms that support mixed family filters will simply generate filters that
28+
contain both address families.
29+
30+
##### Desired Approach
31+
32+
**The desired approach will be to have Capirca output two filters, one for each
33+
address family, for platforms that do not support ‘mixed’.** This currently
34+
occurs already with
35+
[cisco.py](https://github.com/google/capirca/blob/master/capirca/lib/cisco.py)
36+
which outputs two access-lists one that contains IPv4 and another that contains
37+
IPv6 addresses. This solves a problem of having to potentially maintain two
38+
different .pol so that in cases where vendor syntax of filter name is derived
39+
from .pol a syncing between v4 and v6 .pol do not need to be maintained.
40+
41+
This may be misleading at first because when using Capirca the user expects that
42+
the output will be a single policy, but it is actually their lack of
43+
understanding about the vendor syntax that causes this belief.
44+
45+
If the user does not want this output, then the user can simply issue two
46+
headers to Capirca one for IPv4 and one for IPv6.
47+
48+
#### When the platform does supports “mixed” in a single access-list
49+
50+
This will require the policy to be generated correctly for the
51+
[following permutations](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L236-L322)
52+
of address family, and when “mixed” is supported, and with valid tests:
53+
54+
1. [MIXED_TO_V4](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L236)
55+
1. [V4_TO_MIXED](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L245)
56+
1. [MIXED_TO_V6](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L254)
57+
1. [V6_TO_MIXED](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L262)
58+
1. [MIXED_TO_MIXED](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L270)
59+
1. [MIXED_TO_ANY](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L278)
60+
1. [ANY_TO_MIXED](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L285)
61+
1. [V4_TO_V4](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L92)
62+
1. [V6_TO_V6](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L300)
63+
1. [V4_TO_V6](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L308)
64+
1. [V6_TO_V4](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/tests/lib/nsxv_test.py#L316)
65+
66+
### noverbose option is supported correctly
67+
68+
noverberse must be supported if it makes sense for the platform. Noverbose
69+
removes all comments from the ACE terms, policies, etc. For example see the
70+
logic implemented in
71+
[juniper.py](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/juniper.py#L219).
72+
73+
### Sample.pol file is present
74+
75+
A sample pol file should exist for that generator. Some examples are
76+
[here](https://github.com/google/capirca/tree/master/policies/pol). The
77+
sample.pol file for the new generator should have examples for all the filter
78+
option types used, with all supported IP types, along with any custom fields for
79+
that generator.
80+
81+
### Perform truncating of names for term name or comment based on max length
82+
83+
This is to ensure that truncation of terms and comments that exceed a max_width,
84+
is supported by the generator. Not all platforms have length limitations, if the
85+
generator’s platform has none, then this requirement can be skipped. This
86+
applies only when the term name and comments are being incorporated into the
87+
policy. If they are actual # comments (which are not applied to the policy),
88+
then this requirement does not apply. This could be done using the existing
89+
[WrapWords()](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/aclgenerator.py#L549)
90+
or it may be done by a truncate function within the generator using a custom
91+
function such as in
92+
[juniper.py](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/juniper.py#L715).
93+
This wrapping should also be present for the term name, and should be using
94+
Capirca’s
95+
[FixTermLength()](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/aclgenerator.py#L463).
96+
97+
### Logging is supported correctly for different types of logging
98+
99+
There are different values of logging already created in
100+
[policy.py](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/policy.py#L49).
101+
Not all are supported by every platform.
102+
103+
* LOG_BOTH is for logging session-init as well as session-close, which is
104+
currently supported by JuniperSRX.
105+
106+
* DISABLE is a negative logging action.
107+
108+
* Every other option are considered positive actions.
109+
110+
General rules:
111+
112+
* The generator should support all the types of logging it can.
113+
114+
* For all unsupported positive logging actions, the generator should enable
115+
logging.
116+
117+
* For DISABLE, if the platform can turn off logging, it must; if the platform
118+
does not support it, then it does nothing. Key part is DISABLE must not
119+
enable logging.
120+
121+
### DSMO Support
122+
123+
DSMO is Discontinuous Subnet Masks and is used to save on TCAM space. This is
124+
supported by certain platforms such as Cisco, but is not supported by most
125+
platforms. If DSMO is not supported by a platform, this requirement can be
126+
safely ignored. If DSMO is supported by a platform it must be fully implemented
127+
and carefully unit tested.
128+
129+
### The usage of good and meta Unified Direction names
130+
131+
Good unified direction names for the ACE terms, that are meta and not specific
132+
to that platform, are preferred. This is only for platforms that require
133+
direction. The meta directions
134+
[supported by Capirca](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/packetfilter.py#L77)
135+
are “in”, “out” and “”, but these should not be used as is. Different platforms
136+
use “ingress”, “egress” or “both” such as GCE. Do not rely on platform specific
137+
names for directions. “ingress” and “egress” are the preferred directions to be
138+
used, which can then be converted to the platform’s required specific names for
139+
directions.
140+
141+
### Term Expirations are handled correctly
142+
143+
Term expirations need to be handled correctly in code. An
144+
[example from Juniper](https://github.com/google/capirca/blob/master/capirca/lib/juniper.py#L968-L974)
145+
is that when the term is close to
146+
[expiration](https://github.com/google/capirca/blob/c0ca9d9a3a34d3dab0b41510571448f5d82c033d/capirca/utils/config.py#L17),
147+
an INFO message is logged; and when it is expired, a WARNING message is logged
148+
and the term is not generated. This is also done similarly across other
149+
platforms such as Cisco/GCE.
150+
151+
### ICMP and ICMPv6 handling
152+
153+
The generator needs to handle ICMP and ICMPv6 correctly. This is a broad
154+
requirement, but ICMP and ICMPv6 requires careful handling to **avoid rendering
155+
icmp terms under inet6, and icmpv6 under inet**. One commit that implements this
156+
for gcp_hf is
157+
[here](https://github.com/google/capirca/commit/b4af15a36b70593b7bbf043559405558e82c81bc).
158+
Some generators do not support icmp and icmp6 when the address family is mixed,
159+
such as
160+
[nftables.py](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/nftables.py#L103-L111).
161+
The expected correct behavior is that when “mixed” is specified in the
162+
inet_version, the rule for ICMP should only contain IPv4 addresses, and the rule
163+
for ICMPv6 should contain only IPv6 addresses. Tests must ensure that types and
164+
codes used are valid for the given address family.
165+
166+
In the future, we hope to refactor the code to allow for general ICMP support,
167+
but for now this functionality is implemented per-platform in each generator.
168+
169+
### Makes an explicit determination about statefulness
170+
171+
The generator author should check for “Am I stateful?”. It should clearly state
172+
in generator the result of this as a comment somewhere If it is, it should make
173+
sure that it is doing the right thing for terms. For example, for Juniper SRX,
174+
it is
175+
[possible to skip TCP-established](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/junipersrx.py#L450-L453)
176+
because it is stateful. You would also want to do the stateful check probably
177+
early in the code rather than later, since this may impact efficiency by being
178+
able to skip further code/ checks. A pro of checking early would be being able
179+
to skip any processing of terms not necessary for a stateful firewall such as
180+
skipping TCP-established. In contrast, in iptables.py, the check is made later,
181+
while formatting the terms to modify the term to
182+
[allow established and related terms](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/iptables.py#L474-L485).
183+
184+
### Syntax of the config from the generator and on-device should match when cryptographically verified
185+
186+
The ACL that is generated from the generator, and the ACL that is obtained from
187+
the device when a show configuration command is used, should match bit-by-bit,
188+
such that it should be possible to run a hashing function (such as SHA-1) and
189+
obtain the same hash for both the ACL configurations. Another variant of this
190+
requirement is that the `diff` between these two policies should be empty.
191+
192+
There can be certain exceptions, such as if there is a policy header comment
193+
that cannot be handled by Cisco devices and is thus not present in the Cisco
194+
ACL. This can be handled by checking the diff between them and skipping over the
195+
known mismatches that are acceptable because of the device’s incapability.
196+
Another example of an exception is the Juniper
197+
[control sequence such as ‘replace’,](https://github.com/google/capirca/blob/b3e605a54f12efa1e6b0b1cfd179ee6078313c9d/capirca/lib/juniper.py#L993)
198+
which indicates the device to replace, rather than merge the contents of the
199+
ACL, which does not show up on the device ACL.
200+
201+
If there is a mismatch in the syntax of the 2 ACLs that cannot be fixed, then
202+
these mismatches and the technical reasoning behind the lack of a workaround or
203+
a fix should be listed in the associated Github issue for this generator.
204+
205+
### Apply priority as described in .pol files
206+
207+
If a priority or order exists for the platform, and an input pol file doesn't
208+
set priority for ACEs, then autogenerate priorities in top down order based on
209+
the ACE order in the .pol file.
210+
211+
### Protocol support
212+
213+
#### Call out support
214+
215+
Make explicit which protocols the platform supports, and support them in the
216+
generator. If protocols are not supported by the platform, ensure that the
217+
generator explicitly does not support them, and gracefully handles these errors.
218+
219+
#### Names vs numbers
220+
221+
Names or numbers can be used to represent protocols within a generator.
222+
Throughout a given generators use only names or numbers, not a mix of both. The
223+
choice should be made based on the default representation for the device
224+
platform. (I.e. if the policy once applied to the device will show names in a
225+
"show config" command output, then use names within the generator. If the output
226+
contains numbers, use numbers within the generator.)
227+
228+
#### Port support
229+
230+
The following is a list of which IP protocols support ports. When supporting a
231+
protocol, make sure that the handling of port or lack thereof is correct.
232+
233+
* HOPOPT = No
234+
235+
* ICMP = No
236+
237+
* IGMP = No
238+
239+
* GGP = No
240+
241+
* IPIP = No
242+
243+
* TCP = Yes
244+
245+
* EGP = No
246+
247+
* IGP = No
248+
249+
* UDP = *Yes*
250+
251+
* RDP = *Yes (Uses different port ranges though, check RFC)*
252+
253+
* IPV6 = No
254+
255+
* IPV6_ROUTE = No
256+
257+
* FRAGMENT = No
258+
259+
* RSVP = No
260+
261+
* GRE = No
262+
263+
* ESP = No
264+
265+
* AH = No
266+
267+
* ICMPV6 = No
268+
269+
* IPV6_NONXT = No
270+
271+
* IPV6_OPTS = No
272+
273+
* OSPF = No
274+
275+
* PIM = No
276+
277+
* VRRP = No
278+
279+
* L2TP = No. (only uses UDP 1701)
280+
281+
* SCTP = *Yes*
282+
283+
* UDPLITE = *Yes*
284+
285+
Note: DCCP also uses ports, but this is not currently supported. Source:
286+
https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
287+
288+
### Zone based firewall support
289+
290+
Zone based firewalls should be implemented if supported by the platform. When
291+
implementing zone based firewalls, all combinations of zone types must be tested
292+
fully. Test for invalid and reserved zone names and illegal combinations of
293+
policies (i.e. any-> specific, or any->any).
294+
295+
### Address book support
296+
297+
Address books should be implemented if they are present in a platform. The
298+
generator should explicitly state whether it is implementing a global or zone
299+
based address book. If both are available for the platform, both must be
300+
implemented, and an option must be added to choose between the two. When
301+
implementing address books, always filter for address family before building the
302+
book. Tests should ensure that address books are filtered by address family
303+
properly along with their relevant rules.
304+
305+
## Coding Style Requirements:
306+
307+
### Use builtin libraries
308+
309+
Use only Python standard builtin libraries wherever possible. External
310+
dependencies are discouraged and must be justified.
311+
312+
### Structure generators for inheritance
313+
314+
See Cisco and Juniper generators for examples. Wherever possible, use base
315+
classes, inheritance, etc to allow for common functions between generators in a
316+
"family".
317+
318+
### Reuse common functions
319+
320+
Use functions from aclgenerator.py, policy.py, nacaddr.py, etc wherever possible
321+
instead of implementing your own.
322+
323+
### If output will be in a common exchange format, use a standard library for rendering
324+
325+
This applies to common standards such as JSON, XML, YAML, protocol buffers, etc.
326+
Instead of building up such serialized output using string ops, use a standard
327+
library to produce the rendered output instead. (For example, to render JSON,
328+
use [json.dumps](https://docs.python.org/3/library/json.html#json.dumps). For
329+
XML, use some combination of the
330+
[standard libraries](https://docs.python.org/3/library/xml.html), such as
331+
xml.etree and xml.dom.) This should allow most generator code to interact with
332+
objects only, and serialize to a buffer at the end. Unit tests should operate on
333+
the object structures. Additional small unit tests should sanity check that the
334+
rendering library is producing valid output as expected. If a (JSON, XML, etc.)
335+
schema is available this should also be used to validate output in a test.
336+
337+
### Check various limits when rendering output
338+
339+
Make sure that line, identifier, full output, etc. limits are applied when
340+
rendering final output. Some of these may be specific to a given platform. These
341+
should always include but are not limited to:
342+
343+
* Maximum value of addresses and ports allowed in single rule. Generator must
344+
support automatically splitting into new rule when exceeded.
345+
* Maximum values allowed across entire policy for rule count, address, ports
346+
* Maximum length for comments, and support splitting across lines the correct
347+
way when over. Also check for max per-rule limit if one exists and truncate
348+
using the common Capirca functions if needed.
349+
* Max term length supported must be 24 or greater, in order to allow for
350+
meaningful term names.
351+
352+
### Test coverage
353+
354+
#### General coverage
355+
356+
Aim for as close to 100% test coverage as you can. Tests should cover a wide
357+
span of the vendor syntax, not just a single keyword.
358+
359+
#### Custom exceptions
360+
361+
All custom exceptions types added must be unit tested.
362+
363+
<!--* # copybara:strip_begin(internal linter)
364+
# LINT.ThenChange(
365+
# //depot/google3/ops/security/miracl/g3doc/capirca_generator_patterns.md
366+
# )
367+
# copybara:strip_end *-->

0 commit comments

Comments
 (0)