BIND配置中一大堆一大堆的acl,什么allow-query, allow-recursion, allow-update還有view的match-clients等等等等。
acl中的主要存儲的就是IP,可以把acl當做是一個IP池,在需要驗證的時候就從這個IP池中查找該IP是否存在。那么BIND中如何實現這個非常常用的IP池的呢?
BIND中的acl用數據結構dns_acl來表示:
struct dns_acl { unsigned int magic; isc_mem_t *mctx; isc_refcount_t refcount; dns_iptable_t *iptable; #define node_count iptable->radix->num_added_node dns_aclelement_t *elements; isc_boolean_t has_negatives; unsigned int alloc; /*%< Elements allocated */ unsigned int length; /*%< Elements initialized */ char *name; /*%< Temporary use only */ ISC_LINK(dns_acl_t) nextincache; /*%< Ditto */ };
其中的iptable本質上就是一個radix tree(中文名叫基數樹)。
radix tree簡直就是為IP路由存儲和查找而生的(實際上IP路由查找正是radix tree最常用的領域之一)。在存儲IP數據,尤其是CIDR的時候,radix退化成一種二叉樹,左右子樹分別表示IP的二進制表示的1或者0,所以對於IPv4,radix 樹的最大高度是32。對於CIDR的存儲,只需要存儲前綴位就可以了,比如存儲130.50.30.40/18,只需要存儲前18位即可,后面的14位不用存儲,因為在查找ACL的時候,只要對比到第18位就可以確定是否讓此IP通過驗證。
BIND9中radix tree的實現比較復雜,可能是處於需要兼容IPv4和IPv6,以及IP地址的先后關系的考慮。
nginx中的geo模塊也用radix tree存儲CIDR形式的IP,core/ngx_radix_tree.c的實現還是相當短小精悍的。