]>
Commit | Line | Data |
---|---|---|
6054c1eb | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
5cd1adba SH |
2 | #ifndef _XTABLES_H |
3 | #define _XTABLES_H | |
4 | ||
5 | /* | |
6 | * Changing any structs/functions may incur a needed change | |
7 | * in libxtables_vcurrent/vage too. | |
8 | */ | |
9 | ||
10 | #include <sys/socket.h> /* PF_* */ | |
11 | #include <sys/types.h> | |
12 | #include <limits.h> | |
13 | #include <stdbool.h> | |
14 | #include <stddef.h> | |
15 | #include <stdint.h> | |
16 | #include <netinet/in.h> | |
17 | #include <net/if.h> | |
18 | #include <linux/types.h> | |
19 | #include <linux/netfilter.h> | |
20 | #include <linux/netfilter/x_tables.h> | |
21 | ||
22 | #ifndef IPPROTO_SCTP | |
23 | #define IPPROTO_SCTP 132 | |
24 | #endif | |
25 | #ifndef IPPROTO_DCCP | |
26 | #define IPPROTO_DCCP 33 | |
27 | #endif | |
28 | #ifndef IPPROTO_MH | |
29 | # define IPPROTO_MH 135 | |
30 | #endif | |
31 | #ifndef IPPROTO_UDPLITE | |
32 | #define IPPROTO_UDPLITE 136 | |
33 | #endif | |
34 | ||
35 | #include <xtables-version.h> | |
36 | ||
37 | struct in_addr; | |
38 | ||
39 | /* | |
40 | * .size is here so that there is a somewhat reasonable check | |
41 | * against the chosen .type. | |
42 | */ | |
43 | #define XTOPT_POINTER(stype, member) \ | |
44 | .ptroff = offsetof(stype, member), \ | |
45 | .size = sizeof(((stype *)NULL)->member) | |
46 | #define XTOPT_TABLEEND {.name = NULL} | |
47 | ||
48 | /** | |
49 | * Select the format the input has to conform to, as well as the target type | |
50 | * (area pointed to with XTOPT_POINTER). Note that the storing is not always | |
51 | * uniform. @cb->val will be populated with as much as there is space, i.e. | |
52 | * exactly 2 items for ranges, but the target area can receive more values | |
53 | * (e.g. in case of ranges), or less values (e.g. %XTTYPE_HOSTMASK). | |
54 | * | |
55 | * %XTTYPE_NONE: option takes no argument | |
56 | * %XTTYPE_UINT*: standard integer | |
57 | * %XTTYPE_UINT*RC: colon-separated range of standard integers | |
58 | * %XTTYPE_DOUBLE: double-precision floating point number | |
59 | * %XTTYPE_STRING: arbitrary string | |
60 | * %XTTYPE_TOSMASK: 8-bit TOS value with optional mask | |
61 | * %XTTYPE_MARKMASK32: 32-bit mark with optional mask | |
62 | * %XTTYPE_SYSLOGLEVEL: syslog level by name or number | |
63 | * %XTTYPE_HOST: one host or address (ptr: union nf_inet_addr) | |
64 | * %XTTYPE_HOSTMASK: one host or address, with an optional prefix length | |
65 | * (ptr: union nf_inet_addr; only host portion is stored) | |
66 | * %XTTYPE_PROTOCOL: protocol number/name from /etc/protocols (ptr: uint8_t) | |
67 | * %XTTYPE_PORT: 16-bit port name or number (supports %XTOPT_NBO) | |
68 | * %XTTYPE_PORTRC: colon-separated port range (names acceptable), | |
69 | * (supports %XTOPT_NBO) | |
70 | * %XTTYPE_PLEN: prefix length | |
71 | * %XTTYPE_PLENMASK: prefix length (ptr: union nf_inet_addr) | |
72 | * %XTTYPE_ETHERMAC: Ethernet MAC address in hex form | |
73 | */ | |
74 | enum xt_option_type { | |
75 | XTTYPE_NONE, | |
76 | XTTYPE_UINT8, | |
77 | XTTYPE_UINT16, | |
78 | XTTYPE_UINT32, | |
79 | XTTYPE_UINT64, | |
80 | XTTYPE_UINT8RC, | |
81 | XTTYPE_UINT16RC, | |
82 | XTTYPE_UINT32RC, | |
83 | XTTYPE_UINT64RC, | |
84 | XTTYPE_DOUBLE, | |
85 | XTTYPE_STRING, | |
86 | XTTYPE_TOSMASK, | |
87 | XTTYPE_MARKMASK32, | |
88 | XTTYPE_SYSLOGLEVEL, | |
89 | XTTYPE_HOST, | |
90 | XTTYPE_HOSTMASK, | |
91 | XTTYPE_PROTOCOL, | |
92 | XTTYPE_PORT, | |
93 | XTTYPE_PORTRC, | |
94 | XTTYPE_PLEN, | |
95 | XTTYPE_PLENMASK, | |
96 | XTTYPE_ETHERMAC, | |
97 | }; | |
98 | ||
99 | /** | |
100 | * %XTOPT_INVERT: option is invertible (usable with !) | |
101 | * %XTOPT_MAND: option is mandatory | |
102 | * %XTOPT_MULTI: option may be specified multiple times | |
103 | * %XTOPT_PUT: store value into memory at @ptroff | |
104 | * %XTOPT_NBO: store value in network-byte order | |
105 | * (only certain XTTYPEs recognize this) | |
106 | */ | |
107 | enum xt_option_flags { | |
108 | XTOPT_INVERT = 1 << 0, | |
109 | XTOPT_MAND = 1 << 1, | |
110 | XTOPT_MULTI = 1 << 2, | |
111 | XTOPT_PUT = 1 << 3, | |
112 | XTOPT_NBO = 1 << 4, | |
113 | }; | |
114 | ||
115 | /** | |
116 | * @name: name of option | |
117 | * @type: type of input and validation method, see %XTTYPE_* | |
118 | * @id: unique number (within extension) for option, 0-31 | |
119 | * @excl: bitmask of flags that cannot be used with this option | |
120 | * @also: bitmask of flags that must be used with this option | |
121 | * @flags: bitmask of option flags, see %XTOPT_* | |
122 | * @ptroff: offset into private structure for member | |
123 | * @size: size of the item pointed to by @ptroff; this is a safeguard | |
124 | * @min: lowest allowed value (for singular integral types) | |
125 | * @max: highest allowed value (for singular integral types) | |
126 | */ | |
127 | struct xt_option_entry { | |
128 | const char *name; | |
129 | enum xt_option_type type; | |
130 | unsigned int id, excl, also, flags; | |
131 | unsigned int ptroff; | |
132 | size_t size; | |
133 | unsigned int min, max; | |
134 | }; | |
135 | ||
136 | /** | |
137 | * @arg: input from command line | |
138 | * @ext_name: name of extension currently being processed | |
139 | * @entry: current option being processed | |
140 | * @data: per-extension kernel data block | |
141 | * @xflags: options of the extension that have been used | |
142 | * @invert: whether option was used with ! | |
143 | * @nvals: number of results in uXX_multi | |
144 | * @val: parsed result | |
145 | * @udata: per-extension private scratch area | |
146 | * (cf. xtables_{match,target}->udata_size) | |
147 | */ | |
148 | struct xt_option_call { | |
149 | const char *arg, *ext_name; | |
150 | const struct xt_option_entry *entry; | |
151 | void *data; | |
152 | unsigned int xflags; | |
153 | bool invert; | |
154 | uint8_t nvals; | |
155 | union { | |
156 | uint8_t u8, u8_range[2], syslog_level, protocol; | |
157 | uint16_t u16, u16_range[2], port, port_range[2]; | |
158 | uint32_t u32, u32_range[2]; | |
159 | uint64_t u64, u64_range[2]; | |
160 | double dbl; | |
161 | struct { | |
162 | union nf_inet_addr haddr, hmask; | |
163 | uint8_t hlen; | |
164 | }; | |
165 | struct { | |
166 | uint8_t tos_value, tos_mask; | |
167 | }; | |
168 | struct { | |
169 | uint32_t mark, mask; | |
170 | }; | |
171 | uint8_t ethermac[6]; | |
172 | } val; | |
173 | /* Wished for a world where the ones below were gone: */ | |
174 | union { | |
175 | struct xt_entry_match **match; | |
176 | struct xt_entry_target **target; | |
177 | }; | |
178 | void *xt_entry; | |
179 | void *udata; | |
180 | }; | |
181 | ||
182 | /** | |
183 | * @ext_name: name of extension currently being processed | |
184 | * @data: per-extension (kernel) data block | |
185 | * @udata: per-extension private scratch area | |
186 | * (cf. xtables_{match,target}->udata_size) | |
187 | * @xflags: options of the extension that have been used | |
188 | */ | |
189 | struct xt_fcheck_call { | |
190 | const char *ext_name; | |
191 | void *data, *udata; | |
192 | unsigned int xflags; | |
193 | }; | |
194 | ||
195 | /** | |
196 | * A "linear"/linked-list based name<->id map, for files similar to | |
197 | * /etc/iproute2/. | |
198 | */ | |
199 | struct xtables_lmap { | |
200 | char *name; | |
201 | int id; | |
202 | struct xtables_lmap *next; | |
203 | }; | |
204 | ||
205 | enum xtables_ext_flags { | |
206 | XTABLES_EXT_ALIAS = 1 << 0, | |
207 | }; | |
208 | ||
209 | /* Include file for additions: new matches and targets. */ | |
210 | struct xtables_match | |
211 | { | |
212 | /* | |
213 | * ABI/API version this module requires. Must be first member, | |
214 | * as the rest of this struct may be subject to ABI changes. | |
215 | */ | |
216 | const char *version; | |
217 | ||
218 | struct xtables_match *next; | |
219 | ||
220 | const char *name; | |
221 | const char *real_name; | |
222 | ||
223 | /* Revision of match (0 by default). */ | |
224 | uint8_t revision; | |
225 | ||
226 | /* Extension flags */ | |
227 | uint8_t ext_flags; | |
228 | ||
229 | uint16_t family; | |
230 | ||
231 | /* Size of match data. */ | |
232 | size_t size; | |
233 | ||
234 | /* Size of match data relevant for userspace comparison purposes */ | |
235 | size_t userspacesize; | |
236 | ||
237 | /* Function which prints out usage message. */ | |
238 | void (*help)(void); | |
239 | ||
240 | /* Initialize the match. */ | |
241 | void (*init)(struct xt_entry_match *m); | |
242 | ||
243 | /* Function which parses command options; returns true if it | |
244 | ate an option */ | |
245 | /* entry is struct ipt_entry for example */ | |
246 | int (*parse)(int c, char **argv, int invert, unsigned int *flags, | |
247 | const void *entry, | |
248 | struct xt_entry_match **match); | |
249 | ||
250 | /* Final check; exit if not ok. */ | |
251 | void (*final_check)(unsigned int flags); | |
252 | ||
253 | /* Prints out the match iff non-NULL: put space at end */ | |
254 | /* ip is struct ipt_ip * for example */ | |
255 | void (*print)(const void *ip, | |
256 | const struct xt_entry_match *match, int numeric); | |
257 | ||
258 | /* Saves the match info in parsable form to stdout. */ | |
259 | /* ip is struct ipt_ip * for example */ | |
260 | void (*save)(const void *ip, const struct xt_entry_match *match); | |
261 | ||
262 | /* Print match name or alias */ | |
263 | const char *(*alias)(const struct xt_entry_match *match); | |
264 | ||
265 | /* Pointer to list of extra command-line options */ | |
266 | const struct option *extra_opts; | |
267 | ||
268 | /* New parser */ | |
269 | void (*x6_parse)(struct xt_option_call *); | |
270 | void (*x6_fcheck)(struct xt_fcheck_call *); | |
271 | const struct xt_option_entry *x6_options; | |
272 | ||
273 | /* Size of per-extension instance extra "global" scratch space */ | |
274 | size_t udata_size; | |
275 | ||
276 | /* Ignore these men behind the curtain: */ | |
277 | void *udata; | |
278 | unsigned int option_offset; | |
279 | struct xt_entry_match *m; | |
280 | unsigned int mflags; | |
281 | unsigned int loaded; /* simulate loading so options are merged properly */ | |
282 | }; | |
283 | ||
284 | struct xtables_target | |
285 | { | |
286 | /* | |
287 | * ABI/API version this module requires. Must be first member, | |
288 | * as the rest of this struct may be subject to ABI changes. | |
289 | */ | |
290 | const char *version; | |
291 | ||
292 | struct xtables_target *next; | |
293 | ||
294 | ||
295 | const char *name; | |
296 | ||
297 | /* Real target behind this, if any. */ | |
298 | const char *real_name; | |
299 | ||
300 | /* Revision of target (0 by default). */ | |
301 | uint8_t revision; | |
302 | ||
303 | /* Extension flags */ | |
304 | uint8_t ext_flags; | |
305 | ||
306 | uint16_t family; | |
307 | ||
308 | ||
309 | /* Size of target data. */ | |
310 | size_t size; | |
311 | ||
312 | /* Size of target data relevant for userspace comparison purposes */ | |
313 | size_t userspacesize; | |
314 | ||
315 | /* Function which prints out usage message. */ | |
316 | void (*help)(void); | |
317 | ||
318 | /* Initialize the target. */ | |
319 | void (*init)(struct xt_entry_target *t); | |
320 | ||
321 | /* Function which parses command options; returns true if it | |
322 | ate an option */ | |
323 | /* entry is struct ipt_entry for example */ | |
324 | int (*parse)(int c, char **argv, int invert, unsigned int *flags, | |
325 | const void *entry, | |
326 | struct xt_entry_target **targetinfo); | |
327 | ||
328 | /* Final check; exit if not ok. */ | |
329 | void (*final_check)(unsigned int flags); | |
330 | ||
331 | /* Prints out the target iff non-NULL: put space at end */ | |
332 | void (*print)(const void *ip, | |
333 | const struct xt_entry_target *target, int numeric); | |
334 | ||
335 | /* Saves the targinfo in parsable form to stdout. */ | |
336 | void (*save)(const void *ip, | |
337 | const struct xt_entry_target *target); | |
338 | ||
339 | /* Print target name or alias */ | |
340 | const char *(*alias)(const struct xt_entry_target *target); | |
341 | ||
342 | /* Pointer to list of extra command-line options */ | |
343 | const struct option *extra_opts; | |
344 | ||
345 | /* New parser */ | |
346 | void (*x6_parse)(struct xt_option_call *); | |
347 | void (*x6_fcheck)(struct xt_fcheck_call *); | |
348 | const struct xt_option_entry *x6_options; | |
349 | ||
350 | size_t udata_size; | |
351 | ||
352 | /* Ignore these men behind the curtain: */ | |
353 | void *udata; | |
354 | unsigned int option_offset; | |
355 | struct xt_entry_target *t; | |
356 | unsigned int tflags; | |
357 | unsigned int used; | |
358 | unsigned int loaded; /* simulate loading so options are merged properly */ | |
359 | }; | |
360 | ||
361 | struct xtables_rule_match { | |
362 | struct xtables_rule_match *next; | |
363 | struct xtables_match *match; | |
364 | /* Multiple matches of the same type: the ones before | |
365 | the current one are completed from parsing point of view */ | |
366 | bool completed; | |
367 | }; | |
368 | ||
369 | /** | |
370 | * struct xtables_pprot - | |
371 | * | |
372 | * A few hardcoded protocols for 'all' and in case the user has no | |
373 | * /etc/protocols. | |
374 | */ | |
375 | struct xtables_pprot { | |
376 | const char *name; | |
377 | uint8_t num; | |
378 | }; | |
379 | ||
380 | enum xtables_tryload { | |
381 | XTF_DONT_LOAD, | |
382 | XTF_DURING_LOAD, | |
383 | XTF_TRY_LOAD, | |
384 | XTF_LOAD_MUST_SUCCEED, | |
385 | }; | |
386 | ||
387 | enum xtables_exittype { | |
388 | OTHER_PROBLEM = 1, | |
389 | PARAMETER_PROBLEM, | |
390 | VERSION_PROBLEM, | |
391 | RESOURCE_PROBLEM, | |
392 | XTF_ONLY_ONCE, | |
393 | XTF_NO_INVERT, | |
394 | XTF_BAD_VALUE, | |
395 | XTF_ONE_ACTION, | |
396 | }; | |
397 | ||
398 | struct xtables_globals | |
399 | { | |
400 | unsigned int option_offset; | |
401 | const char *program_name, *program_version; | |
402 | struct option *orig_opts; | |
403 | struct option *opts; | |
404 | void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); | |
405 | int (*compat_rev)(const char *name, uint8_t rev, int opt); | |
406 | }; | |
407 | ||
408 | #define XT_GETOPT_TABLEEND {.name = NULL, .has_arg = false} | |
409 | ||
410 | #ifdef __cplusplus | |
411 | extern "C" { | |
412 | #endif | |
413 | ||
414 | extern const char *xtables_modprobe_program; | |
415 | extern struct xtables_match *xtables_matches; | |
416 | extern struct xtables_target *xtables_targets; | |
417 | ||
418 | extern void xtables_init(void); | |
419 | extern void xtables_set_nfproto(uint8_t); | |
420 | extern void *xtables_calloc(size_t, size_t); | |
421 | extern void *xtables_malloc(size_t); | |
422 | extern void *xtables_realloc(void *, size_t); | |
423 | ||
424 | extern int xtables_insmod(const char *, const char *, bool); | |
425 | extern int xtables_load_ko(const char *, bool); | |
426 | extern int xtables_set_params(struct xtables_globals *xtp); | |
427 | extern void xtables_free_opts(int reset_offset); | |
428 | extern struct option *xtables_merge_options(struct option *origopts, | |
429 | struct option *oldopts, const struct option *newopts, | |
430 | unsigned int *option_offset); | |
431 | ||
432 | extern int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto); | |
433 | extern struct xtables_match *xtables_find_match(const char *name, | |
434 | enum xtables_tryload, struct xtables_rule_match **match); | |
435 | extern struct xtables_target *xtables_find_target(const char *name, | |
436 | enum xtables_tryload); | |
437 | extern int xtables_compatible_revision(const char *name, uint8_t revision, | |
438 | int opt); | |
439 | ||
440 | extern void xtables_rule_matches_free(struct xtables_rule_match **matches); | |
441 | ||
442 | /* Your shared library should call one of these. */ | |
443 | extern void xtables_register_match(struct xtables_match *me); | |
444 | extern void xtables_register_matches(struct xtables_match *, unsigned int); | |
445 | extern void xtables_register_target(struct xtables_target *me); | |
446 | extern void xtables_register_targets(struct xtables_target *, unsigned int); | |
447 | ||
448 | extern bool xtables_strtoul(const char *, char **, uintmax_t *, | |
449 | uintmax_t, uintmax_t); | |
450 | extern bool xtables_strtoui(const char *, char **, unsigned int *, | |
451 | unsigned int, unsigned int); | |
452 | extern int xtables_service_to_port(const char *name, const char *proto); | |
453 | extern uint16_t xtables_parse_port(const char *port, const char *proto); | |
454 | extern void | |
455 | xtables_parse_interface(const char *arg, char *vianame, unsigned char *mask); | |
456 | ||
457 | /* this is a special 64bit data type that is 8-byte aligned */ | |
458 | #define aligned_u64 uint64_t __attribute__((aligned(8))) | |
459 | ||
460 | extern struct xtables_globals *xt_params; | |
461 | #define xtables_error (xt_params->exit_err) | |
462 | ||
463 | extern void xtables_param_act(unsigned int, const char *, ...); | |
464 | ||
465 | extern const char *xtables_ipaddr_to_numeric(const struct in_addr *); | |
466 | extern const char *xtables_ipaddr_to_anyname(const struct in_addr *); | |
467 | extern const char *xtables_ipmask_to_numeric(const struct in_addr *); | |
468 | extern struct in_addr *xtables_numeric_to_ipaddr(const char *); | |
469 | extern struct in_addr *xtables_numeric_to_ipmask(const char *); | |
470 | extern int xtables_ipmask_to_cidr(const struct in_addr *); | |
471 | extern void xtables_ipparse_any(const char *, struct in_addr **, | |
472 | struct in_addr *, unsigned int *); | |
473 | extern void xtables_ipparse_multiple(const char *, struct in_addr **, | |
474 | struct in_addr **, unsigned int *); | |
475 | ||
476 | extern struct in6_addr *xtables_numeric_to_ip6addr(const char *); | |
477 | extern const char *xtables_ip6addr_to_numeric(const struct in6_addr *); | |
478 | extern const char *xtables_ip6addr_to_anyname(const struct in6_addr *); | |
479 | extern const char *xtables_ip6mask_to_numeric(const struct in6_addr *); | |
480 | extern int xtables_ip6mask_to_cidr(const struct in6_addr *); | |
481 | extern void xtables_ip6parse_any(const char *, struct in6_addr **, | |
482 | struct in6_addr *, unsigned int *); | |
483 | extern void xtables_ip6parse_multiple(const char *, struct in6_addr **, | |
484 | struct in6_addr **, unsigned int *); | |
485 | ||
486 | /** | |
487 | * Print the specified value to standard output, quoting dangerous | |
488 | * characters if required. | |
489 | */ | |
490 | extern void xtables_save_string(const char *value); | |
491 | ||
492 | #define FMT_NUMERIC 0x0001 | |
493 | #define FMT_NOCOUNTS 0x0002 | |
494 | #define FMT_KILOMEGAGIGA 0x0004 | |
495 | #define FMT_OPTIONS 0x0008 | |
496 | #define FMT_NOTABLE 0x0010 | |
497 | #define FMT_NOTARGET 0x0020 | |
498 | #define FMT_VIA 0x0040 | |
499 | #define FMT_NONEWLINE 0x0080 | |
500 | #define FMT_LINENUMBERS 0x0100 | |
501 | ||
502 | #define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ | |
503 | | FMT_NUMERIC | FMT_NOTABLE) | |
504 | #define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) | |
505 | ||
506 | extern void xtables_print_num(uint64_t number, unsigned int format); | |
507 | ||
508 | #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) | |
509 | # ifdef _INIT | |
510 | # undef _init | |
511 | # define _init _INIT | |
512 | # endif | |
513 | extern void init_extensions(void); | |
514 | extern void init_extensions4(void); | |
515 | extern void init_extensions6(void); | |
516 | #else | |
517 | # define _init __attribute__((constructor)) _INIT | |
518 | #endif | |
519 | ||
520 | extern const struct xtables_pprot xtables_chain_protos[]; | |
521 | extern uint16_t xtables_parse_protocol(const char *s); | |
522 | ||
523 | /* kernel revision handling */ | |
524 | extern int kernel_version; | |
525 | extern void get_kernel_version(void); | |
526 | #define LINUX_VERSION(x,y,z) (0x10000*(x) + 0x100*(y) + z) | |
527 | #define LINUX_VERSION_MAJOR(x) (((x)>>16) & 0xFF) | |
528 | #define LINUX_VERSION_MINOR(x) (((x)>> 8) & 0xFF) | |
529 | #define LINUX_VERSION_PATCH(x) ( (x) & 0xFF) | |
530 | ||
531 | /* xtoptions.c */ | |
532 | extern void xtables_option_metavalidate(const char *, | |
533 | const struct xt_option_entry *); | |
534 | extern struct option *xtables_options_xfrm(struct option *, struct option *, | |
535 | const struct xt_option_entry *, | |
536 | unsigned int *); | |
537 | extern void xtables_option_parse(struct xt_option_call *); | |
538 | extern void xtables_option_tpcall(unsigned int, char **, bool, | |
539 | struct xtables_target *, void *); | |
540 | extern void xtables_option_mpcall(unsigned int, char **, bool, | |
541 | struct xtables_match *, void *); | |
542 | extern void xtables_option_tfcall(struct xtables_target *); | |
543 | extern void xtables_option_mfcall(struct xtables_match *); | |
544 | extern void xtables_options_fcheck(const char *, unsigned int, | |
545 | const struct xt_option_entry *); | |
546 | ||
547 | extern struct xtables_lmap *xtables_lmap_init(const char *); | |
548 | extern void xtables_lmap_free(struct xtables_lmap *); | |
549 | extern int xtables_lmap_name2id(const struct xtables_lmap *, const char *); | |
550 | extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int); | |
551 | ||
552 | #ifdef XTABLES_INTERNAL | |
553 | ||
554 | /* Shipped modules rely on this... */ | |
555 | ||
556 | # ifndef ARRAY_SIZE | |
557 | # define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) | |
558 | # endif | |
559 | ||
560 | extern void _init(void); | |
561 | ||
562 | #endif | |
563 | ||
564 | #ifdef __cplusplus | |
565 | } /* extern "C" */ | |
566 | #endif | |
567 | ||
568 | #endif /* _XTABLES_H */ |