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
|
-- SPDX-License-Identifier: GPL-3.0-or-later
local ffi = require('ffi')
local kr_cach = kres.context().cache
local charset = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-'}
local function gen_bytes(len)
local bytes = {}
for _ = 1,len do
table.insert(bytes, charset[math.random(1, #charset)])
end
local result = table.concat(bytes)
assert(#result == len)
return result
end
local function gen_ttl()
return math.random(0, 2^31-1)
end
local function gen_rrtype()
return math.random(1024, 61000)
end
local function gen_rdata(len)
assert(len >= 1 and len <= 65535)
return gen_bytes(len)
end
local function gen_label(len) -- in bytes including the length byte
assert(len >= 2 and len <= 64)
local bytes = {string.char(len - 1), gen_bytes(len - 1)}
return table.concat(bytes)
end
local function gen_dname()
local target_len -- length 2 bytes does not make sense
while target_len == nil or target_len == 2 do
target_len = math.random(1, 255)
end
local labels = {string.char(0)}
local cur_len = 1
while target_len > cur_len do
local new_len = math.random(
2,
math.min(target_len - cur_len,
64))
if (target_len - cur_len - new_len) == 1 then
-- it is a trap, single-byte label is allowed only at the end
-- we cannot leave room for single-byte label in the next round
if new_len == 64 then
goto continue -- we are at max label length, try again
end
new_len = new_len + 1
end
table.insert(labels, 1, gen_label(new_len))
cur_len = cur_len + new_len
::continue::
end
assert(target_len == cur_len)
local dname = table.concat(labels)
assert(#dname >= 1 and #dname <= 255)
assert(string.byte(dname, #dname) == 0)
return dname
end
local function gen_rrset()
local rrs = {}
local maxsize = 300 -- RR data size in bytes per RR set, does not include owner etc.
local target_len = math.random(1, maxsize)
local cur_len = 0
while target_len > cur_len do
local new_len = math.random(1, target_len - cur_len)
local new_rr = gen_rdata(new_len)
cur_len = cur_len + #new_rr
table.insert(rrs, new_rr)
end
assert(target_len == cur_len)
return rrs, cur_len
end
local function add_random_rrset()
local owner = gen_dname()
local ttl = gen_ttl()
local rr_type = gen_rrtype()
local rdata_set = gen_rrset()
local kr_rrset = kres.rrset(owner, rr_type, kres.class.IN, ttl)
for _, rr in ipairs(rdata_set) do
assert(kr_rrset:add_rdata(rr, #rr))
end
assert(kr_cach:insert(kr_rrset, nil, ffi.C.KR_RANK_SECURE))
end
ffi.cdef('int usleep(uint32_t usec);') -- at least in current glibc it's always 32-bit
local rr_count = 0
local function gen_batch()
for _ = 1,math.random(1,10) do
add_random_rrset()
rr_count = rr_count + 1
if rr_count % 100 == 0 then
print('cache usage ', cache.stats()['usage_percent'], '%')
end
end
kr_cach:commit()
ffi.C.usleep(15) -- stop *whole process* to give better chance to GC executing
local delay
if math.random(1,4) == 1 then
delay = 1 -- give a chance to DNS resolving
else
delay = 0
end
event.after(delay, gen_batch)
end
return {
add_random_rrset=add_random_rrset,
gen_batch=gen_batch,
gen_bytes=gen_bytes,
gen_dname=gen_dname,
gen_label=gen_label,
gen_rdata=gen_rdata,
gen_rrset=gen_rrset,
gen_rrtype=gen_rrtype,
gen_ttl=gen_ttl
}
|