1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2  *                         Patrick Schaaf <bof@bof.de>
3  *                         Martin Josefsson <gandalf@wlug.westbo.se>
4  * Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 /* Shared library add-on to iptables to add IP set mangling target. */
12 #include <stdbool.h>
13 #include <stdio.h>
14 #include <netdb.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <getopt.h>
18 #include <ctype.h>
19 
20 #include <xtables.h>
21 #include <linux/netfilter/xt_set.h>
22 #include "libxt_set.h"
23 
24 /* Revision 0 */
25 
26 static void
set_target_help_v0(void)27 set_target_help_v0(void)
28 {
29 	printf("SET target options:\n"
30 	       " --add-set name flags\n"
31 	       " --del-set name flags\n"
32 	       "		add/del src/dst IP/port from/to named sets,\n"
33 	       "		where flags are the comma separated list of\n"
34 	       "		'src' and 'dst' specifications.\n");
35 }
36 
37 static const struct option set_target_opts_v0[] = {
38 	{.name = "add-set", .has_arg = true, .val = '1'},
39 	{.name = "del-set", .has_arg = true, .val = '2'},
40 	XT_GETOPT_TABLEEND,
41 };
42 
43 static void
set_target_check_v0(unsigned int flags)44 set_target_check_v0(unsigned int flags)
45 {
46 	if (!flags)
47 		xtables_error(PARAMETER_PROBLEM,
48 			   "You must specify either `--add-set' or `--del-set'");
49 }
50 
51 static void
set_target_init_v0(struct xt_entry_target * target)52 set_target_init_v0(struct xt_entry_target *target)
53 {
54 	struct xt_set_info_target_v0 *info =
55 		(struct xt_set_info_target_v0 *) target->data;
56 
57 	info->add_set.index =
58 	info->del_set.index = IPSET_INVALID_ID;
59 
60 }
61 
62 static void
parse_target_v0(char ** argv,int invert,unsigned int * flags,struct xt_set_info_v0 * info,const char * what)63 parse_target_v0(char **argv, int invert, unsigned int *flags,
64 		struct xt_set_info_v0 *info, const char *what)
65 {
66 	if (info->u.flags[0])
67 		xtables_error(PARAMETER_PROBLEM,
68 			      "--%s can be specified only once", what);
69 
70 	if (!argv[optind]
71 	    || argv[optind][0] == '-' || argv[optind][0] == '!')
72 		xtables_error(PARAMETER_PROBLEM,
73 			      "--%s requires two args.", what);
74 
75 	if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
76 		xtables_error(PARAMETER_PROBLEM,
77 			      "setname `%s' too long, max %d characters.",
78 			      optarg, IPSET_MAXNAMELEN - 1);
79 
80 	get_set_byname(optarg, (struct xt_set_info *)info);
81 	parse_dirs_v0(argv[optind], info);
82 	optind++;
83 
84 	*flags = 1;
85 }
86 
87 static int
set_target_parse_v0(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)88 set_target_parse_v0(int c, char **argv, int invert, unsigned int *flags,
89 		    const void *entry, struct xt_entry_target **target)
90 {
91 	struct xt_set_info_target_v0 *myinfo =
92 		(struct xt_set_info_target_v0 *) (*target)->data;
93 
94 	switch (c) {
95 	case '1':		/* --add-set <set> <flags> */
96 		parse_target_v0(argv, invert, flags,
97 				&myinfo->add_set, "add-set");
98 		break;
99 	case '2':		/* --del-set <set>[:<flags>] <flags> */
100 		parse_target_v0(argv, invert, flags,
101 				&myinfo->del_set, "del-set");
102 		break;
103 	}
104 	return 1;
105 }
106 
107 static void
print_target_v0(const char * prefix,const struct xt_set_info_v0 * info)108 print_target_v0(const char *prefix, const struct xt_set_info_v0 *info)
109 {
110 	int i;
111 	char setname[IPSET_MAXNAMELEN];
112 
113 	if (info->index == IPSET_INVALID_ID)
114 		return;
115 	get_set_byid(setname, info->index);
116 	printf(" %s %s", prefix, setname);
117 	for (i = 0; i < IPSET_DIM_MAX; i++) {
118 		if (!info->u.flags[i])
119 			break;
120 		printf("%s%s",
121 		       i == 0 ? " " : ",",
122 		       info->u.flags[i] & IPSET_SRC ? "src" : "dst");
123 	}
124 }
125 
126 static void
set_target_print_v0(const void * ip,const struct xt_entry_target * target,int numeric)127 set_target_print_v0(const void *ip, const struct xt_entry_target *target,
128 		    int numeric)
129 {
130 	const struct xt_set_info_target_v0 *info = (const void *)target->data;
131 
132 	print_target_v0("add-set", &info->add_set);
133 	print_target_v0("del-set", &info->del_set);
134 }
135 
136 static void
set_target_save_v0(const void * ip,const struct xt_entry_target * target)137 set_target_save_v0(const void *ip, const struct xt_entry_target *target)
138 {
139 	const struct xt_set_info_target_v0 *info = (const void *)target->data;
140 
141 	print_target_v0("--add-set", &info->add_set);
142 	print_target_v0("--del-set", &info->del_set);
143 }
144 
145 /* Revision 1 */
146 static void
set_target_init_v1(struct xt_entry_target * target)147 set_target_init_v1(struct xt_entry_target *target)
148 {
149 	struct xt_set_info_target_v1 *info =
150 		(struct xt_set_info_target_v1 *) target->data;
151 
152 	info->add_set.index =
153 	info->del_set.index = IPSET_INVALID_ID;
154 
155 }
156 
157 #define SET_TARGET_ADD		0x1
158 #define SET_TARGET_DEL		0x2
159 #define SET_TARGET_EXIST	0x4
160 #define SET_TARGET_TIMEOUT	0x8
161 #define SET_TARGET_MAP		0x10
162 #define SET_TARGET_MAP_MARK	0x20
163 #define SET_TARGET_MAP_PRIO	0x40
164 #define SET_TARGET_MAP_QUEUE	0x80
165 
166 static void
parse_target(char ** argv,int invert,struct xt_set_info * info,const char * what)167 parse_target(char **argv, int invert, struct xt_set_info *info,
168 	     const char *what)
169 {
170 	if (info->dim)
171 		xtables_error(PARAMETER_PROBLEM,
172 			      "--%s can be specified only once", what);
173 	if (!argv[optind]
174 	    || argv[optind][0] == '-' || argv[optind][0] == '!')
175 		xtables_error(PARAMETER_PROBLEM,
176 			      "--%s requires two args.", what);
177 
178 	if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
179 		xtables_error(PARAMETER_PROBLEM,
180 			      "setname `%s' too long, max %d characters.",
181 			      optarg, IPSET_MAXNAMELEN - 1);
182 
183 	get_set_byname(optarg, info);
184 	parse_dirs(argv[optind], info);
185 	optind++;
186 }
187 
188 static int
set_target_parse_v1(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)189 set_target_parse_v1(int c, char **argv, int invert, unsigned int *flags,
190 		    const void *entry, struct xt_entry_target **target)
191 {
192 	struct xt_set_info_target_v1 *myinfo =
193 		(struct xt_set_info_target_v1 *) (*target)->data;
194 
195 	switch (c) {
196 	case '1':		/* --add-set <set> <flags> */
197 		parse_target(argv, invert, &myinfo->add_set, "add-set");
198 		*flags |= SET_TARGET_ADD;
199 		break;
200 	case '2':		/* --del-set <set>[:<flags>] <flags> */
201 		parse_target(argv, invert, &myinfo->del_set, "del-set");
202 		*flags |= SET_TARGET_DEL;
203 		break;
204 	}
205 	return 1;
206 }
207 
208 static void
print_target(const char * prefix,const struct xt_set_info * info)209 print_target(const char *prefix, const struct xt_set_info *info)
210 {
211 	int i;
212 	char setname[IPSET_MAXNAMELEN];
213 
214 	if (info->index == IPSET_INVALID_ID)
215 		return;
216 	get_set_byid(setname, info->index);
217 	printf(" %s %s", prefix, setname);
218 	for (i = 1; i <= info->dim; i++) {
219 		printf("%s%s",
220 		       i == 1 ? " " : ",",
221 		       info->flags & (1 << i) ? "src" : "dst");
222 	}
223 }
224 
225 static void
set_target_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)226 set_target_print_v1(const void *ip, const struct xt_entry_target *target,
227 		    int numeric)
228 {
229 	const struct xt_set_info_target_v1 *info = (const void *)target->data;
230 
231 	print_target("add-set", &info->add_set);
232 	print_target("del-set", &info->del_set);
233 }
234 
235 static void
set_target_save_v1(const void * ip,const struct xt_entry_target * target)236 set_target_save_v1(const void *ip, const struct xt_entry_target *target)
237 {
238 	const struct xt_set_info_target_v1 *info = (const void *)target->data;
239 
240 	print_target("--add-set", &info->add_set);
241 	print_target("--del-set", &info->del_set);
242 }
243 
244 /* Revision 2 */
245 
246 static void
set_target_help_v2(void)247 set_target_help_v2(void)
248 {
249 	printf("SET target options:\n"
250 	       " --add-set name flags [--exist] [--timeout n]\n"
251 	       " --del-set name flags\n"
252 	       "		add/del src/dst IP/port from/to named sets,\n"
253 	       "		where flags are the comma separated list of\n"
254 	       "		'src' and 'dst' specifications.\n");
255 }
256 
257 static const struct option set_target_opts_v2[] = {
258 	{.name = "add-set", .has_arg = true,  .val = '1'},
259 	{.name = "del-set", .has_arg = true,  .val = '2'},
260 	{.name = "exist",   .has_arg = false, .val = '3'},
261 	{.name = "timeout", .has_arg = true,  .val = '4'},
262 	XT_GETOPT_TABLEEND,
263 };
264 
265 static void
set_target_check_v2(unsigned int flags)266 set_target_check_v2(unsigned int flags)
267 {
268 	if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL)))
269 		xtables_error(PARAMETER_PROBLEM,
270 			   "You must specify either `--add-set' or `--del-set'");
271 	if (!(flags & SET_TARGET_ADD)) {
272 		if (flags & SET_TARGET_EXIST)
273 			xtables_error(PARAMETER_PROBLEM,
274 				"Flag `--exist' can be used with `--add-set' only");
275 		if (flags & SET_TARGET_TIMEOUT)
276 			xtables_error(PARAMETER_PROBLEM,
277 				"Option `--timeout' can be used with `--add-set' only");
278 	}
279 }
280 
281 
282 static void
set_target_init_v2(struct xt_entry_target * target)283 set_target_init_v2(struct xt_entry_target *target)
284 {
285 	struct xt_set_info_target_v2 *info =
286 		(struct xt_set_info_target_v2 *) target->data;
287 
288 	info->add_set.index =
289 	info->del_set.index = IPSET_INVALID_ID;
290 	info->timeout = UINT32_MAX;
291 }
292 
293 static int
set_target_parse_v2(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)294 set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags,
295 		    const void *entry, struct xt_entry_target **target)
296 {
297 	struct xt_set_info_target_v2 *myinfo =
298 		(struct xt_set_info_target_v2 *) (*target)->data;
299 	unsigned int timeout;
300 
301 	switch (c) {
302 	case '1':		/* --add-set <set> <flags> */
303 		parse_target(argv, invert, &myinfo->add_set, "add-set");
304 		*flags |= SET_TARGET_ADD;
305 		break;
306 	case '2':		/* --del-set <set>[:<flags>] <flags> */
307 		parse_target(argv, invert, &myinfo->del_set, "del-set");
308 		*flags |= SET_TARGET_DEL;
309 		break;
310 	case '3':
311 		myinfo->flags |= IPSET_FLAG_EXIST;
312 		*flags |= SET_TARGET_EXIST;
313 		break;
314 	case '4':
315 		if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
316 			xtables_error(PARAMETER_PROBLEM,
317 				      "Invalid value for option --timeout "
318 				      "or out of range 0-%u", UINT32_MAX - 1);
319 		myinfo->timeout = timeout;
320 		*flags |= SET_TARGET_TIMEOUT;
321 		break;
322 	}
323 	return 1;
324 }
325 
326 static void
set_target_print_v2(const void * ip,const struct xt_entry_target * target,int numeric)327 set_target_print_v2(const void *ip, const struct xt_entry_target *target,
328 		    int numeric)
329 {
330 	const struct xt_set_info_target_v2 *info = (const void *)target->data;
331 
332 	print_target("add-set", &info->add_set);
333 	if (info->flags & IPSET_FLAG_EXIST)
334 		printf(" exist");
335 	if (info->timeout != UINT32_MAX)
336 		printf(" timeout %u", info->timeout);
337 	print_target("del-set", &info->del_set);
338 }
339 
340 static void
set_target_save_v2(const void * ip,const struct xt_entry_target * target)341 set_target_save_v2(const void *ip, const struct xt_entry_target *target)
342 {
343 	const struct xt_set_info_target_v2 *info = (const void *)target->data;
344 
345 	print_target("--add-set", &info->add_set);
346 	if (info->flags & IPSET_FLAG_EXIST)
347 		printf(" --exist");
348 	if (info->timeout != UINT32_MAX)
349 		printf(" --timeout %u", info->timeout);
350 	print_target("--del-set", &info->del_set);
351 }
352 
353 
354 /* Revision 3 */
355 
356 static void
set_target_help_v3(void)357 set_target_help_v3(void)
358 {
359 	printf("SET target options:\n"
360 	       " --add-set name flags [--exist] [--timeout n]\n"
361 	       " --del-set name flags\n"
362 	       " --map-set name flags"
363 	       " [--map-mark] [--map-prio] [--map-queue]\n"
364 	       "		add/del src/dst IP/port from/to named sets,\n"
365 	       "		where flags are the comma separated list of\n"
366 	       "		'src' and 'dst' specifications.\n");
367 }
368 
369 static const struct option set_target_opts_v3[] = {
370 	{.name = "add-set",	.has_arg = true,  .val = '1'},
371 	{.name = "del-set",	.has_arg = true,  .val = '2'},
372 	{.name = "exist",	.has_arg = false, .val = '3'},
373 	{.name = "timeout",	.has_arg = true,  .val = '4'},
374 	{.name = "map-set",	.has_arg = true,  .val = '5'},
375 	{.name = "map-mark",	.has_arg = false, .val = '6'},
376 	{.name = "map-prio",	.has_arg = false, .val = '7'},
377 	{.name = "map-queue",	.has_arg = false, .val = '8'},
378 	XT_GETOPT_TABLEEND,
379 };
380 
381 static void
set_target_check_v3(unsigned int flags)382 set_target_check_v3(unsigned int flags)
383 {
384 	if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL|SET_TARGET_MAP)))
385 		xtables_error(PARAMETER_PROBLEM,
386 			      "You must specify either `--add-set' or "
387 			      "`--del-set' or `--map-set'");
388 	if (!(flags & SET_TARGET_ADD)) {
389 		if (flags & SET_TARGET_EXIST)
390 			xtables_error(PARAMETER_PROBLEM,
391 				"Flag `--exist' can be used with `--add-set' only");
392 		if (flags & SET_TARGET_TIMEOUT)
393 			xtables_error(PARAMETER_PROBLEM,
394 				"Option `--timeout' can be used with `--add-set' only");
395 	}
396 	if (!(flags & SET_TARGET_MAP)) {
397 		if (flags & SET_TARGET_MAP_MARK)
398 			xtables_error(PARAMETER_PROBLEM,
399 				"Flag `--map-mark' can be used with `--map-set' only");
400 		if (flags & SET_TARGET_MAP_PRIO)
401 			xtables_error(PARAMETER_PROBLEM,
402 				"Flag `--map-prio' can be used with `--map-set' only");
403 		if (flags & SET_TARGET_MAP_QUEUE)
404 			xtables_error(PARAMETER_PROBLEM,
405 				"Flag `--map-queue' can be used with `--map-set' only");
406 	}
407 	if ((flags & SET_TARGET_MAP) && !(flags & (SET_TARGET_MAP_MARK |
408 						   SET_TARGET_MAP_PRIO |
409 						   SET_TARGET_MAP_QUEUE)))
410 		xtables_error(PARAMETER_PROBLEM,
411 			"You must specify flags `--map-mark' or "
412 			"'--map-prio` or `--map-queue'");
413 }
414 
415 static void
set_target_init_v3(struct xt_entry_target * target)416 set_target_init_v3(struct xt_entry_target *target)
417 {
418 	struct xt_set_info_target_v3 *info =
419 		(struct xt_set_info_target_v3 *) target->data;
420 
421 	info->add_set.index =
422 	info->del_set.index =
423 	info->map_set.index = IPSET_INVALID_ID;
424 	info->timeout = UINT32_MAX;
425 }
426 
427 static int
set_target_parse_v3(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)428 set_target_parse_v3(int c, char **argv, int invert, unsigned int *flags,
429 		    const void *entry, struct xt_entry_target **target)
430 {
431 	struct xt_set_info_target_v3 *myinfo =
432 		(struct xt_set_info_target_v3 *) (*target)->data;
433 	unsigned int timeout;
434 
435 	switch (c) {
436 	case '1':		/* --add-set <set> <flags> */
437 		parse_target(argv, invert, &myinfo->add_set, "add-set");
438 		*flags |= SET_TARGET_ADD;
439 		break;
440 	case '2':		/* --del-set <set>[:<flags>] <flags> */
441 		parse_target(argv, invert, &myinfo->del_set, "del-set");
442 		*flags |= SET_TARGET_DEL;
443 		break;
444 	case '3':
445 		myinfo->flags |= IPSET_FLAG_EXIST;
446 		*flags |= SET_TARGET_EXIST;
447 		break;
448 	case '4':
449 		if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
450 			xtables_error(PARAMETER_PROBLEM,
451 				      "Invalid value for option --timeout "
452 				      "or out of range 0-%u", UINT32_MAX - 1);
453 		myinfo->timeout = timeout;
454 		*flags |= SET_TARGET_TIMEOUT;
455 		break;
456 	case '5':		/* --map-set <set> <flags> */
457 		parse_target(argv, invert, &myinfo->map_set, "map-set");
458 		*flags |= SET_TARGET_MAP;
459 		break;
460 	case '6':
461 		myinfo->flags |= IPSET_FLAG_MAP_SKBMARK;
462 		*flags |= SET_TARGET_MAP_MARK;
463 		break;
464 	case '7':
465 		myinfo->flags |= IPSET_FLAG_MAP_SKBPRIO;
466 		*flags |= SET_TARGET_MAP_PRIO;
467 		break;
468 	case '8':
469 		myinfo->flags |= IPSET_FLAG_MAP_SKBQUEUE;
470 		*flags |= SET_TARGET_MAP_QUEUE;
471 		break;
472 	}
473 	return 1;
474 }
475 
476 static void
set_target_print_v3(const void * ip,const struct xt_entry_target * target,int numeric)477 set_target_print_v3(const void *ip, const struct xt_entry_target *target,
478 		    int numeric)
479 {
480 	const struct xt_set_info_target_v3 *info = (const void *)target->data;
481 
482 	print_target("add-set", &info->add_set);
483 	if (info->flags & IPSET_FLAG_EXIST)
484 		printf(" exist");
485 	if (info->timeout != UINT32_MAX)
486 		printf(" timeout %u", info->timeout);
487 	print_target("del-set", &info->del_set);
488 	print_target("map-set", &info->map_set);
489 	if (info->flags & IPSET_FLAG_MAP_SKBMARK)
490 		printf(" map-mark");
491 	if (info->flags & IPSET_FLAG_MAP_SKBPRIO)
492 		printf(" map-prio");
493 	if (info->flags & IPSET_FLAG_MAP_SKBQUEUE)
494 		printf(" map-queue");
495 }
496 
497 static void
set_target_save_v3(const void * ip,const struct xt_entry_target * target)498 set_target_save_v3(const void *ip, const struct xt_entry_target *target)
499 {
500 	const struct xt_set_info_target_v3 *info = (const void *)target->data;
501 
502 	print_target("--add-set", &info->add_set);
503 	if (info->flags & IPSET_FLAG_EXIST)
504 		printf(" --exist");
505 	if (info->timeout != UINT32_MAX)
506 		printf(" --timeout %u", info->timeout);
507 	print_target("--del-set", &info->del_set);
508 	print_target("--map-set", &info->map_set);
509 	if (info->flags & IPSET_FLAG_MAP_SKBMARK)
510 		printf(" --map-mark");
511 	if (info->flags & IPSET_FLAG_MAP_SKBPRIO)
512 		printf(" --map-prio");
513 	if (info->flags & IPSET_FLAG_MAP_SKBQUEUE)
514 		printf(" --map-queue");
515 }
516 
517 static struct xtables_target set_tg_reg[] = {
518 	{
519 		.name		= "SET",
520 		.revision	= 0,
521 		.version	= XTABLES_VERSION,
522 		.family		= NFPROTO_IPV4,
523 		.size		= XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
524 		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
525 		.help		= set_target_help_v0,
526 		.init		= set_target_init_v0,
527 		.parse		= set_target_parse_v0,
528 		.final_check	= set_target_check_v0,
529 		.print		= set_target_print_v0,
530 		.save		= set_target_save_v0,
531 		.extra_opts	= set_target_opts_v0,
532 	},
533 	{
534 		.name		= "SET",
535 		.revision	= 1,
536 		.version	= XTABLES_VERSION,
537 		.family		= NFPROTO_UNSPEC,
538 		.size		= XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
539 		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
540 		.help		= set_target_help_v0,
541 		.init		= set_target_init_v1,
542 		.parse		= set_target_parse_v1,
543 		.final_check	= set_target_check_v0,
544 		.print		= set_target_print_v1,
545 		.save		= set_target_save_v1,
546 		.extra_opts	= set_target_opts_v0,
547 	},
548 	{
549 		.name		= "SET",
550 		.revision	= 2,
551 		.version	= XTABLES_VERSION,
552 		.family		= NFPROTO_UNSPEC,
553 		.size		= XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
554 		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
555 		.help		= set_target_help_v2,
556 		.init		= set_target_init_v2,
557 		.parse		= set_target_parse_v2,
558 		.final_check	= set_target_check_v2,
559 		.print		= set_target_print_v2,
560 		.save		= set_target_save_v2,
561 		.extra_opts	= set_target_opts_v2,
562 	},
563 	{
564 		.name		= "SET",
565 		.revision	= 3,
566 		.version	= XTABLES_VERSION,
567 		.family		= NFPROTO_UNSPEC,
568 		.size		= XT_ALIGN(sizeof(struct xt_set_info_target_v3)),
569 		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_target_v3)),
570 		.help		= set_target_help_v3,
571 		.init		= set_target_init_v3,
572 		.parse		= set_target_parse_v3,
573 		.final_check	= set_target_check_v3,
574 		.print		= set_target_print_v3,
575 		.save		= set_target_save_v3,
576 		.extra_opts	= set_target_opts_v3,
577 	},
578 };
579 
_init(void)580 void _init(void)
581 {
582 	xtables_register_targets(set_tg_reg, ARRAY_SIZE(set_tg_reg));
583 }
584