-
Notifications
You must be signed in to change notification settings - Fork 1
/
dns_tree.lua
188 lines (156 loc) · 4.83 KB
/
dns_tree.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env lua
-- -*-lua-*-
--
-- $Id: dns_tree.lua $
--
-- Author: Markus Stenberg <markus [email protected]>
--
-- Copyright (c) 2013 cisco Systems, Inc.
--
-- Created: Tue May 7 12:55:42 2013 mstenber
-- Last modified: Mon May 27 14:27:50 2013 mstenber
-- Edit time: 58 min
--
-- This module implements (nested) dns zone hierarchy using rather
-- simple API which wraps set of objects.
-- There are tree nodes, and leaf nodes; both can have values (=a list
-- of RRs related to that particular FQDN), and the tree nodes can
-- have also child nodes.
require 'mst'
module(..., package.seeall)
node = mst.create_class{class='node',
mandatory={'label'}}
function node:init()
self.children = {}
end
function node:repr_data()
return mst.repr{children=self.children and mst.table_count(self.children) or 0,
label=self.label}
end
function node:add_child(n)
self:a(not self:get_child(n.label), 'child already exists - logic error')
self:a(n and type(n) == 'table', 'non-existent child?', n)
self.children[string.lower(n.label)] = n
n.parent = self
return n
end
function node:get_child(label)
return self.children[string.lower(label)]
end
function node:iterate_subtree(f)
for k, v in pairs(self.children or {})
do
f(v)
self:a(v and v.iterate_subtree, 'no subtree method', v)
v:iterate_subtree(f)
end
end
function node:match_rec(ll, i, ...)
if i == 0
then
self:d('calling get_value')
return self:get_value(...)
end
self:a(i <= #ll)
local label = ll[i]
local child = self:get_child(label)
if not child
then
self:d('returning default', label, i, ...)
return self:get_default(...)
end
self:d('matching recursively in child', i-1, ...)
return child:match_rec(ll, i-1, ...)
end
function node:match_ll(ll, ...)
return self:match_rec(ll, #ll, ...)
end
function node:find_or_create_subtree_rec(ll, i,
end_node_callback,
intermediate_node_callback)
local label = ll[i]
local n = self:get_child(label)
if i == 1
then
-- this is the last node
if n
then
return n
end
-- add child with that label
local d = {}
d.label = label
local n = end_node_callback(d)
self:a(n and type(n) == 'table', 'non-existent end node', n)
return self:add_child(n)
end
-- intermediate node
if not n
then
n = intermediate_node_callback{label=label}
self:a(n and type(n) == 'table', 'non-existent intermediate node', n)
self:add_child(n)
end
return n:find_or_create_subtree_rec(ll, i-1,
end_node_callback,
intermediate_node_callback)
end
function node:find_or_create_subtree(ll,
end_node_callback,
intermediate_node_callback)
self:a(ll, 'no ll supplied')
self:a(end_node_callback, 'no end node callback supplied')
self:a(intermediate_node_callback, 'no intermediate node callback')
return self:find_or_create_subtree_rec(ll, #ll,
end_node_callback,
intermediate_node_callback)
end
function node:add_value(ll, value, end_node_callback, intermediate_node_callback)
end_node_callback = end_node_callback or create_leaf_node_callback
intermediate_node_callback = intermediate_node_callback or create_node_callback
local n = self:find_or_create_subtree(ll,
end_node_callback,
intermediate_node_callback)
self:a(n, 'find_or_create_subtree failed?!?')
n.value = value
return n
end
function create_node_callback(d)
mst.a(type(d) == 'table', 'wrong d', d)
return node:new(d)
end
function create_leaf_node_callback(d)
mst.a(type(d) == 'table', 'wrong d', d)
return leaf_node:new(d)
end
function node:get_fqdn()
return table.concat(self:get_ll(), '.')
end
function node:get_ll()
local t = {}
local n = self
self:a(self.label, 'no label?!?')
mst.a(type(self.label) == 'string', 'non-string label')
while #n.label > 0
do
table.insert(t, n.label)
n = n.parent
self:a(n, 'null parent encountered w/o nil label? error')
self:a(n.label, 'no label?!?', n)
mst.a(type(n.label) == 'string', 'non-string label', n)
end
return t
end
function node:get_default()
return nil, 'default value not provided'
end
function node:get_value()
return nil, 'value not provided'
end
leaf_node = node:new_subclass{class='leaf_node'}
function leaf_node:get_default()
return nil, 'leaf nodes cannot have children'
end
function leaf_node:get_value()
return self.value
end