summaryrefslogtreecommitdiffstats
path: root/tests/config/test_dns_generators.lua
blob: 4a7cc0a584bad07b833837cc17d8d260335034c8 (plain)
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
}