zonefile.lua 4.61 KB
Newer Older
1
2
3
4
5
-- LuaJIT ffi bindings for zscanner, a DNS zone parser.
-- Author: Marek Vavrusa <marek.vavrusa@nic.cz>
--

local ffi = require('ffi')
6
local libzscanner = ffi.load(libpath('libzscanner', '1'))
7
ffi.cdef[[
8
9
void free(void *ptr);
void *realloc(void *ptr, size_t size);
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

/*
 * Data structures
 */

enum {
	MAX_RDATA_LENGTH = 65535,
	MAX_ITEM_LENGTH = 255,
	MAX_DNAME_LENGTH = 255,
	MAX_LABEL_LENGTH = 63,
	MAX_RDATA_ITEMS = 64,
	BITMAP_WINDOWS = 256,
	INET4_ADDR_LENGTH = 4,
	INET6_ADDR_LENGTH = 16,
	RAGEL_STACK_SIZE = 16,
};
typedef struct {
	uint8_t bitmap[32];
	uint8_t length;
} window_t;
typedef struct {
	uint8_t  excl_flag;
	uint16_t addr_family;
	uint8_t  prefix_length;
} apl_t;
typedef struct {
	uint32_t d1, d2;
	uint32_t m1, m2;
	uint32_t s1, s2;
	uint32_t alt;
	uint64_t siz, hp, vp;
	int8_t   lat_sign, long_sign, alt_sign;
} loc_t;
43
44
45
46
47
48
49
50
typedef struct zs_state {
	static const int NONE    = 0;
	static const int DATA    = 1;
	static const int ERROR   = 2;
	static const int INCLUDE = 3;
	static const int EOF     = 4;
	static const int STOP    = 5;
} zs_state_t;
51

52
typedef struct scanner {
53
54
55
56
57
58
59
60
61
62
63
64
65
	int      cs;
	int      top;
	int      stack[RAGEL_STACK_SIZE];
	bool     multiline;
	uint64_t number64;
	uint64_t number64_tmp;
	uint32_t decimals;
	uint32_t decimal_counter;
	uint32_t item_length;
	uint32_t item_length_position;
	uint8_t *item_length_location;
	uint32_t buffer_length;
	uint8_t  buffer[MAX_RDATA_LENGTH];
66
67
	char     include_filename[MAX_RDATA_LENGTH];
	char     *path;
68
69
70
71
72
73
74
75
76
77
78
79
80
	window_t windows[BITMAP_WINDOWS];
	int16_t  last_window;
	apl_t    apl;
	loc_t    loc;
	bool     long_string;
	uint8_t  *dname;
	uint32_t *dname_length;
	uint32_t dname_tmp_length;
	uint32_t r_data_tail;
	uint32_t zone_origin_length;
	uint8_t  zone_origin[MAX_DNAME_LENGTH + MAX_LABEL_LENGTH];
	uint16_t default_class;
	uint32_t default_ttl;
81
82
83
84
85
86
87
88
89
90
91
92
93
	int state;
	struct {
		bool automatic;
		void (*record)(struct zs_scanner *);
		void (*error)(struct zs_scanner *);
		void *data;
	} process;
	struct {
		const char *start;
		const char *current;
		const char *end;
		bool eof;
	} input;
94
95
96
97
	struct {
		char *name;
		int  descriptor;
	} file;
98
99
100
101
102
103
	struct {
		int code;
		uint64_t counter;
		bool fatal;
	} error;
	uint64_t line_counter;
104
105
106
107
108
109
110
	uint32_t r_owner_length;
	uint8_t  r_owner[MAX_DNAME_LENGTH + MAX_LABEL_LENGTH];
	uint16_t r_class;
	uint32_t r_ttl;
	uint16_t r_type;
	uint32_t r_data_length;
	uint8_t  r_data[MAX_RDATA_LENGTH];
111
} zs_scanner_t;
112
113
114
115

/*
 * Function signatures
 */
116
117
118
119
120
int zs_init(zs_scanner_t *scanner, const char *origin, const uint16_t rclass, const uint32_t ttl);
void zs_deinit(zs_scanner_t *scanner);
int zs_set_input_string(zs_scanner_t *scanner, const char *input, size_t size);
int zs_set_input_file(zs_scanner_t *scanner, const char *file_name);
int zs_parse_record(zs_scanner_t *scanner);
121
122
123
const char* zs_strerror(const int code);
]]

124
125
126
-- Constant table
local zs_state = ffi.new('struct zs_state')

127
-- Wrap scanner context
128
129
local const_char_t = ffi.typeof('const char *')
local zs_scanner_t = ffi.typeof('struct scanner')
130
ffi.metatype( zs_scanner_t, {
131
132
133
134
135
136
137
	__gc = function(zs) return libzscanner.zs_deinit(zs) end,
	__new = function(ct, origin, class, ttl)
		if not class then class = 1 end
		if not ttl then ttl = 3600 end
		local parser = ffi.new(ct)
		libzscanner.zs_init(parser, origin, class, ttl)
		return parser
138
139
	end,
	__index = {
140
141
142
143
144
		open = function (zs, file)
			assert(ffi.istype(zs, zs_scanner_t))
			local ret = libzscanner.zs_set_input_file(zs, file)
			if ret ~= 0 then return false, zs:strerr() end
			return true
145
		end,
146
147
148
149
150
151
152
153
154
155
		parse = function(zs, input)
			assert(ffi.istype(zs, zs_scanner_t))
			if input ~= nil then libzscanner.zs_set_input_string(zs, input, #input) end
			local ret = libzscanner.zs_parse_record(zs)
			-- Return current state only when parsed correctly, otherwise return error
			if ret == 0 and zs.state ~= zs_state.ERROR then
				return zs.state == zs_state.DATA
			else
				return false, zs:strerr()
			end
156
157
		end,
		current_rr = function(zs)
158
			assert(ffi.istype(zs, zs_scanner_t))
159
160
161
162
163
164
			return {owner = ffi.string(zs.r_owner, zs.r_owner_length),
			        ttl = tonumber(zs.r_ttl),
			        class = tonumber(zs.r_class),
			        type = tonumber(zs.r_type), 
			        rdata = ffi.string(zs.r_data, zs.r_data_length)}
		end,
165
166
167
		strerr = function(zs)
			assert(ffi.istype(zs, zs_scanner_t))
			return ffi.string(libzscanner.zs_strerror(zs.error.code))
168
169
170
171
172
		end,
	},
})

-- Module API
173
174
175
176
177
local rrparser = {
	new = zs_scanner_t,
	file = function (path)
		local zs = zs_scanner_t()
		local ok, err = zs:open(path)
178
179
180
		if not ok then
			return ok, err
		end
181
182
183
184
185
186
187
188
189
		local results = {}
		while zs:parse() do
			table.insert(results, zs:current_rr())
		end
		return results
	end,
	state = zs_state,
}
return rrparser