BIND 10 #998: IP based ACL check
BIND 10 Development
do-not-reply at isc.org
Fri Jun 17 11:11:23 UTC 2011
#998: IP based ACL check
-------------------------------------+-------------------------------------
Reporter: | Owner: jinmei
vorner | Status: reviewing
Type: task | Milestone:
Priority: major | Sprint-20110628
Component: | Resolution:
Unclassified | Sensitive: 0
Keywords: | Sub-Project: DNS
Defect Severity: N/A | Estimated Difficulty: 5.0
Feature Depending on Ticket: | Total Hours: 0
Add Hours to Ticket: 0 |
Internal?: 0 |
-------------------------------------+-------------------------------------
Changes (by stephen):
* owner: stephen => jinmei
Comment:
> First, I don't see much benefit in having both Ipv4Check and Ipv6Check
as derived classes of !IpCheck?...
Which version of the code did you review? !IpCheck, Ipv4Check and
Ipv6Check were all derived from Check.
> Second, regardless of whether they are derived from !IpCheck?, I'm not
so sure if it makes sense to separate classes for IPv4 and IPv6.
Essentially they do the same thing: dealing with some binary data with a
fixed maximum size and a variable-length effective size (in bits), and
matching given data of the maximum size against its internal data (up to
the effective size). So, most of the code logic should be sharable, and it
seems we can implement everything in a single class with an identifier of
the address family ...
That's a very valid point and, on reflection, I agree with you. I have
rewritten the code to put everything in one class.
> Third: maybe this is premature at this point, but I guess Ip(vX)Check
will need to contain the information of "which address it is", such as the
source address or destination address. For example, consider the following
ACL entry:
>
> allow from 2001:db8:1::/64 to 2001:db8:2::/64
>
> In this case, the "Context" would be something like a "Packet" class,
that stores the source and destination address information. Both the "from
2001:db8:1::/64" and "to 2001:db8:2::/64" would be represented as separate
Ip(v6)Check objects, and the former/latter would have to know it's a
source/destination address; otherwise the Context cannot determine which
address it should extract to perform the match.
The class as implemented here is only a single ACL match (or non-match -
the capability to check for a non-match was trivial, which is why I added
it to this class). The ACL you are suggesting in the example is really a
combined ACL:
{{{
allow (source matches 2001:db8:1::/64) AND (dest matches 2001:db8:2::/64)
}}}
I would see then implementation as being a class containing two IPCheck
classes, one for source and one for destination. It would be the container
class that knows the structure of the packet and distinguishes between
source and destination address.
However, consider the possible ACL:
{{{
allow (source matches 2001:db8:1::/64) AND (protocol is TCP)
}}}
(I don't know whether we would want to allow access based on protocol, but
as it is a possibility so I think we should consider it.) In this case a
more general class allowing the AND between two ACLs is called for.
Applying this to the IP check problem, an alternative approach to a single
class checking both source and destination addresses could be to derive
SourceIPCheck and DestinationIPCheck classes from IPCheck and combine them
using the AND operator. (All the derived classes would do is provide a
matches() method to pass the source/destination IP address from the packet
to the parent IPCheck::matches())
> Finally: I suspect methods like "compare()" would need to take something
more generic, at least some opaque data and the address family identifier.
For example...
The entry into compare() is through matches(), which is currently
unspecified until it is known what structure is going to be used as
"Context". (The idea is that once we know, a template specialisation can
be written.)
> Now, the address family of getSourceAddr() may be different from the IP
version for this !IpCheck instance, and in that case we'd be expected to
return "false". So, we'd like compare() to take various types of
addresses, and return false if the family doesn't match.
Whoops! I missed that. Added.
> Either make !IpCheck a single "for all IP versions" check class, or to
make IpvXCheck direct subclass of Check. In the latter case !IpCheck will
be removed, some factory function will be introduced, and employ some code
sharing technique (such as templates).
The new IPCheck is now a single class.
> extend the compare() method (or something equivalent to that if
addressing the first point affects this part of interface) so that it can
take different types of addresses
Let's discuss this further. As noted above, I think that this can be
implemented by the planned logical operator ACLs.
> (maybe optionally) add an interface to Ip(vX)Check to maintain and
return the type of addresses.
Done.
> I'd say "IP" instead of "Ip" because "IP" is an acronym
I used Ip to avoid a run of capitals, but I'm not dogmatic about it and
have renamed the class IPCheck.
> I'd use unnamed namespace wherever possible in the test, and avoid using
file-scope "static'
Done.
> can't compare() be private?
An oversight - it is now.
> "getNetmask(): const uint32_t" should be uint32_t. The const is
redundant, and at least clang++ actually treats it a fatal warning.
Treating all addresses as arrays, this now returns a vector.
Thanks for the comprehensive review.
--
Ticket URL: <http://bind10.isc.org/ticket/998#comment:9>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list