xref: /aosp_15_r20/external/iproute2/tc/m_xt.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * m_xt.c	xtables based targets
3*de1e4e89SAndroid Build Coastguard Worker  *		utilities mostly ripped from iptables <duh, its the linux way>
4*de1e4e89SAndroid Build Coastguard Worker  *
5*de1e4e89SAndroid Build Coastguard Worker  *		This program is free software; you can distribute it and/or
6*de1e4e89SAndroid Build Coastguard Worker  *		modify it under the terms of the GNU General Public License
7*de1e4e89SAndroid Build Coastguard Worker  *		as published by the Free Software Foundation; either version
8*de1e4e89SAndroid Build Coastguard Worker  *		2 of the License, or (at your option) any later version.
9*de1e4e89SAndroid Build Coastguard Worker  *
10*de1e4e89SAndroid Build Coastguard Worker  * Authors:  J Hadi Salim ([email protected])
11*de1e4e89SAndroid Build Coastguard Worker  */
12*de1e4e89SAndroid Build Coastguard Worker 
13*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <net/if.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <limits.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <linux/netfilter.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <linux/netfilter_ipv4/ip_tables.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <xtables.h>
22*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
23*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
24*de1e4e89SAndroid Build Coastguard Worker #include <linux/tc_act/tc_ipt.h>
25*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
26*de1e4e89SAndroid Build Coastguard Worker #include <dlfcn.h>
27*de1e4e89SAndroid Build Coastguard Worker #include <getopt.h>
28*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
29*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
30*de1e4e89SAndroid Build Coastguard Worker #include <netdb.h>
31*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
32*de1e4e89SAndroid Build Coastguard Worker #include <ctype.h>
33*de1e4e89SAndroid Build Coastguard Worker #include <stdarg.h>
34*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
35*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
36*de1e4e89SAndroid Build Coastguard Worker #include <sys/wait.h>
37*de1e4e89SAndroid Build Coastguard Worker #ifndef XT_LIB_DIR
38*de1e4e89SAndroid Build Coastguard Worker #       define XT_LIB_DIR "/lib/xtables"
39*de1e4e89SAndroid Build Coastguard Worker #endif
40*de1e4e89SAndroid Build Coastguard Worker 
41*de1e4e89SAndroid Build Coastguard Worker #ifndef __ALIGN_KERNEL
42*de1e4e89SAndroid Build Coastguard Worker #define __ALIGN_KERNEL(x, a)	\
43*de1e4e89SAndroid Build Coastguard Worker 	__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
44*de1e4e89SAndroid Build Coastguard Worker #define __ALIGN_KERNEL_MASK(x, mask) \
45*de1e4e89SAndroid Build Coastguard Worker 	(((x) + (mask)) & ~(mask))
46*de1e4e89SAndroid Build Coastguard Worker #endif
47*de1e4e89SAndroid Build Coastguard Worker 
48*de1e4e89SAndroid Build Coastguard Worker #ifndef ALIGN
49*de1e4e89SAndroid Build Coastguard Worker #define ALIGN(x, a)	__ALIGN_KERNEL((x), (a))
50*de1e4e89SAndroid Build Coastguard Worker #endif
51*de1e4e89SAndroid Build Coastguard Worker 
52*de1e4e89SAndroid Build Coastguard Worker static const char *tname = "mangle";
53*de1e4e89SAndroid Build Coastguard Worker 
54*de1e4e89SAndroid Build Coastguard Worker char *lib_dir;
55*de1e4e89SAndroid Build Coastguard Worker 
56*de1e4e89SAndroid Build Coastguard Worker static const char * const ipthooks[] = {
57*de1e4e89SAndroid Build Coastguard Worker 	"NF_IP_PRE_ROUTING",
58*de1e4e89SAndroid Build Coastguard Worker 	"NF_IP_LOCAL_IN",
59*de1e4e89SAndroid Build Coastguard Worker 	"NF_IP_FORWARD",
60*de1e4e89SAndroid Build Coastguard Worker 	"NF_IP_LOCAL_OUT",
61*de1e4e89SAndroid Build Coastguard Worker 	"NF_IP_POST_ROUTING",
62*de1e4e89SAndroid Build Coastguard Worker };
63*de1e4e89SAndroid Build Coastguard Worker 
64*de1e4e89SAndroid Build Coastguard Worker static struct option original_opts[] = {
65*de1e4e89SAndroid Build Coastguard Worker 	{
66*de1e4e89SAndroid Build Coastguard Worker 		.name = "jump",
67*de1e4e89SAndroid Build Coastguard Worker 		.has_arg = 1,
68*de1e4e89SAndroid Build Coastguard Worker 		.val = 'j'
69*de1e4e89SAndroid Build Coastguard Worker 	},
70*de1e4e89SAndroid Build Coastguard Worker 	{0, 0, 0, 0}
71*de1e4e89SAndroid Build Coastguard Worker };
72*de1e4e89SAndroid Build Coastguard Worker 
73*de1e4e89SAndroid Build Coastguard Worker static struct xtables_globals tcipt_globals = {
74*de1e4e89SAndroid Build Coastguard Worker 	.option_offset = 0,
75*de1e4e89SAndroid Build Coastguard Worker 	.program_name = "tc-ipt",
76*de1e4e89SAndroid Build Coastguard Worker 	.program_version = "0.2",
77*de1e4e89SAndroid Build Coastguard Worker 	.orig_opts = original_opts,
78*de1e4e89SAndroid Build Coastguard Worker 	.opts = original_opts,
79*de1e4e89SAndroid Build Coastguard Worker 	.exit_err = NULL,
80*de1e4e89SAndroid Build Coastguard Worker #if XTABLES_VERSION_CODE >= 11
81*de1e4e89SAndroid Build Coastguard Worker 	.compat_rev = xtables_compatible_revision,
82*de1e4e89SAndroid Build Coastguard Worker #endif
83*de1e4e89SAndroid Build Coastguard Worker };
84*de1e4e89SAndroid Build Coastguard Worker 
85*de1e4e89SAndroid Build Coastguard Worker /*
86*de1e4e89SAndroid Build Coastguard Worker  * we may need to check for version mismatch
87*de1e4e89SAndroid Build Coastguard Worker */
88*de1e4e89SAndroid Build Coastguard Worker static int
build_st(struct xtables_target * target,struct xt_entry_target * t)89*de1e4e89SAndroid Build Coastguard Worker build_st(struct xtables_target *target, struct xt_entry_target *t)
90*de1e4e89SAndroid Build Coastguard Worker {
91*de1e4e89SAndroid Build Coastguard Worker 
92*de1e4e89SAndroid Build Coastguard Worker 	size_t size =
93*de1e4e89SAndroid Build Coastguard Worker 		    XT_ALIGN(sizeof(struct xt_entry_target)) + target->size;
94*de1e4e89SAndroid Build Coastguard Worker 
95*de1e4e89SAndroid Build Coastguard Worker 	if (t == NULL) {
96*de1e4e89SAndroid Build Coastguard Worker 		target->t = xtables_calloc(1, size);
97*de1e4e89SAndroid Build Coastguard Worker 		target->t->u.target_size = size;
98*de1e4e89SAndroid Build Coastguard Worker 		strncpy(target->t->u.user.name, target->name,
99*de1e4e89SAndroid Build Coastguard Worker 			sizeof(target->t->u.user.name) - 1);
100*de1e4e89SAndroid Build Coastguard Worker 		target->t->u.user.revision = target->revision;
101*de1e4e89SAndroid Build Coastguard Worker 
102*de1e4e89SAndroid Build Coastguard Worker 		if (target->init != NULL)
103*de1e4e89SAndroid Build Coastguard Worker 			target->init(target->t);
104*de1e4e89SAndroid Build Coastguard Worker 	} else {
105*de1e4e89SAndroid Build Coastguard Worker 		target->t = t;
106*de1e4e89SAndroid Build Coastguard Worker 	}
107*de1e4e89SAndroid Build Coastguard Worker 	return 0;
108*de1e4e89SAndroid Build Coastguard Worker 
109*de1e4e89SAndroid Build Coastguard Worker }
110*de1e4e89SAndroid Build Coastguard Worker 
set_lib_dir(void)111*de1e4e89SAndroid Build Coastguard Worker static void set_lib_dir(void)
112*de1e4e89SAndroid Build Coastguard Worker {
113*de1e4e89SAndroid Build Coastguard Worker 
114*de1e4e89SAndroid Build Coastguard Worker 	lib_dir = getenv("XTABLES_LIBDIR");
115*de1e4e89SAndroid Build Coastguard Worker 	if (!lib_dir) {
116*de1e4e89SAndroid Build Coastguard Worker 		lib_dir = getenv("IPTABLES_LIB_DIR");
117*de1e4e89SAndroid Build Coastguard Worker 		if (lib_dir)
118*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "using deprecated IPTABLES_LIB_DIR\n");
119*de1e4e89SAndroid Build Coastguard Worker 	}
120*de1e4e89SAndroid Build Coastguard Worker 	if (lib_dir == NULL)
121*de1e4e89SAndroid Build Coastguard Worker 		lib_dir = XT_LIB_DIR;
122*de1e4e89SAndroid Build Coastguard Worker 
123*de1e4e89SAndroid Build Coastguard Worker }
124*de1e4e89SAndroid Build Coastguard Worker 
get_xtables_target_opts(struct xtables_globals * globals,struct xtables_target * m)125*de1e4e89SAndroid Build Coastguard Worker static int get_xtables_target_opts(struct xtables_globals *globals,
126*de1e4e89SAndroid Build Coastguard Worker 				   struct xtables_target *m)
127*de1e4e89SAndroid Build Coastguard Worker {
128*de1e4e89SAndroid Build Coastguard Worker 	struct option *opts;
129*de1e4e89SAndroid Build Coastguard Worker 
130*de1e4e89SAndroid Build Coastguard Worker #if XTABLES_VERSION_CODE >= 6
131*de1e4e89SAndroid Build Coastguard Worker 	opts = xtables_options_xfrm(globals->orig_opts,
132*de1e4e89SAndroid Build Coastguard Worker 				    globals->opts,
133*de1e4e89SAndroid Build Coastguard Worker 				    m->x6_options,
134*de1e4e89SAndroid Build Coastguard Worker 				    &m->option_offset);
135*de1e4e89SAndroid Build Coastguard Worker #else
136*de1e4e89SAndroid Build Coastguard Worker 	opts = xtables_merge_options(globals->opts,
137*de1e4e89SAndroid Build Coastguard Worker 				     m->extra_opts,
138*de1e4e89SAndroid Build Coastguard Worker 				     &m->option_offset);
139*de1e4e89SAndroid Build Coastguard Worker #endif
140*de1e4e89SAndroid Build Coastguard Worker 	if (!opts)
141*de1e4e89SAndroid Build Coastguard Worker 		return -1;
142*de1e4e89SAndroid Build Coastguard Worker 	globals->opts = opts;
143*de1e4e89SAndroid Build Coastguard Worker 	return 0;
144*de1e4e89SAndroid Build Coastguard Worker }
145*de1e4e89SAndroid Build Coastguard Worker 
parse_ipt(struct action_util * a,int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)146*de1e4e89SAndroid Build Coastguard Worker static int parse_ipt(struct action_util *a, int *argc_p,
147*de1e4e89SAndroid Build Coastguard Worker 		     char ***argv_p, int tca_id, struct nlmsghdr *n)
148*de1e4e89SAndroid Build Coastguard Worker {
149*de1e4e89SAndroid Build Coastguard Worker 	struct xtables_target *m = NULL;
150*de1e4e89SAndroid Build Coastguard Worker #if XTABLES_VERSION_CODE >= 6
151*de1e4e89SAndroid Build Coastguard Worker 	struct ipt_entry fw = {};
152*de1e4e89SAndroid Build Coastguard Worker #endif
153*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tail;
154*de1e4e89SAndroid Build Coastguard Worker 
155*de1e4e89SAndroid Build Coastguard Worker 	int c;
156*de1e4e89SAndroid Build Coastguard Worker 	char **argv = *argv_p;
157*de1e4e89SAndroid Build Coastguard Worker 	int argc;
158*de1e4e89SAndroid Build Coastguard Worker 	char k[16];
159*de1e4e89SAndroid Build Coastguard Worker 	int size = 0;
160*de1e4e89SAndroid Build Coastguard Worker 	int iok = 0, ok = 0;
161*de1e4e89SAndroid Build Coastguard Worker 	__u32 hook = 0, index = 0;
162*de1e4e89SAndroid Build Coastguard Worker 
163*de1e4e89SAndroid Build Coastguard Worker 	/* copy tcipt_globals because .opts will be modified by iptables */
164*de1e4e89SAndroid Build Coastguard Worker 	struct xtables_globals tmp_tcipt_globals = tcipt_globals;
165*de1e4e89SAndroid Build Coastguard Worker 
166*de1e4e89SAndroid Build Coastguard Worker 	xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4);
167*de1e4e89SAndroid Build Coastguard Worker 	set_lib_dir();
168*de1e4e89SAndroid Build Coastguard Worker 
169*de1e4e89SAndroid Build Coastguard Worker 	/* parse only up until the next action */
170*de1e4e89SAndroid Build Coastguard Worker 	for (argc = 0; argc < *argc_p; argc++) {
171*de1e4e89SAndroid Build Coastguard Worker 		if (!argv[argc] || !strcmp(argv[argc], "action"))
172*de1e4e89SAndroid Build Coastguard Worker 			break;
173*de1e4e89SAndroid Build Coastguard Worker 	}
174*de1e4e89SAndroid Build Coastguard Worker 
175*de1e4e89SAndroid Build Coastguard Worker 	if (argc <= 2) {
176*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr,
177*de1e4e89SAndroid Build Coastguard Worker 			"too few arguments for xt, need at least '-j <target>'\n");
178*de1e4e89SAndroid Build Coastguard Worker 		return -1;
179*de1e4e89SAndroid Build Coastguard Worker 	}
180*de1e4e89SAndroid Build Coastguard Worker 
181*de1e4e89SAndroid Build Coastguard Worker 	while (1) {
182*de1e4e89SAndroid Build Coastguard Worker 		c = getopt_long(argc, argv, "j:", tmp_tcipt_globals.opts, NULL);
183*de1e4e89SAndroid Build Coastguard Worker 		if (c == -1)
184*de1e4e89SAndroid Build Coastguard Worker 			break;
185*de1e4e89SAndroid Build Coastguard Worker 		switch (c) {
186*de1e4e89SAndroid Build Coastguard Worker 		case 'j':
187*de1e4e89SAndroid Build Coastguard Worker 			m = xtables_find_target(optarg, XTF_TRY_LOAD);
188*de1e4e89SAndroid Build Coastguard Worker 			if (!m) {
189*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr,
190*de1e4e89SAndroid Build Coastguard Worker 					" failed to find target %s\n\n",
191*de1e4e89SAndroid Build Coastguard Worker 					optarg);
192*de1e4e89SAndroid Build Coastguard Worker 				return -1;
193*de1e4e89SAndroid Build Coastguard Worker 			}
194*de1e4e89SAndroid Build Coastguard Worker 
195*de1e4e89SAndroid Build Coastguard Worker 			if (build_st(m, NULL) < 0) {
196*de1e4e89SAndroid Build Coastguard Worker 				printf(" %s error\n", m->name);
197*de1e4e89SAndroid Build Coastguard Worker 				return -1;
198*de1e4e89SAndroid Build Coastguard Worker 			}
199*de1e4e89SAndroid Build Coastguard Worker 
200*de1e4e89SAndroid Build Coastguard Worker 			if (get_xtables_target_opts(&tmp_tcipt_globals,
201*de1e4e89SAndroid Build Coastguard Worker 						    m) < 0) {
202*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr,
203*de1e4e89SAndroid Build Coastguard Worker 					" failed to find additional options for target %s\n\n",
204*de1e4e89SAndroid Build Coastguard Worker 					optarg);
205*de1e4e89SAndroid Build Coastguard Worker 				return -1;
206*de1e4e89SAndroid Build Coastguard Worker 			}
207*de1e4e89SAndroid Build Coastguard Worker 			ok++;
208*de1e4e89SAndroid Build Coastguard Worker 			break;
209*de1e4e89SAndroid Build Coastguard Worker 
210*de1e4e89SAndroid Build Coastguard Worker 		default:
211*de1e4e89SAndroid Build Coastguard Worker #if XTABLES_VERSION_CODE >= 6
212*de1e4e89SAndroid Build Coastguard Worker 			if (m != NULL && m->x6_parse != NULL) {
213*de1e4e89SAndroid Build Coastguard Worker 				xtables_option_tpcall(c, argv, 0, m, &fw);
214*de1e4e89SAndroid Build Coastguard Worker #else
215*de1e4e89SAndroid Build Coastguard Worker 			if (m != NULL && m->parse != NULL) {
216*de1e4e89SAndroid Build Coastguard Worker 				m->parse(c - m->option_offset, argv, 0,
217*de1e4e89SAndroid Build Coastguard Worker 					 &m->tflags, NULL, &m->t);
218*de1e4e89SAndroid Build Coastguard Worker #endif
219*de1e4e89SAndroid Build Coastguard Worker 			} else {
220*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr,
221*de1e4e89SAndroid Build Coastguard Worker 					"failed to find target %s\n\n", optarg);
222*de1e4e89SAndroid Build Coastguard Worker 				return -1;
223*de1e4e89SAndroid Build Coastguard Worker 
224*de1e4e89SAndroid Build Coastguard Worker 			}
225*de1e4e89SAndroid Build Coastguard Worker 			ok++;
226*de1e4e89SAndroid Build Coastguard Worker 			break;
227*de1e4e89SAndroid Build Coastguard Worker 		}
228*de1e4e89SAndroid Build Coastguard Worker 	}
229*de1e4e89SAndroid Build Coastguard Worker 
230*de1e4e89SAndroid Build Coastguard Worker 	if (argc > optind) {
231*de1e4e89SAndroid Build Coastguard Worker 		if (matches(argv[optind], "index") == 0) {
232*de1e4e89SAndroid Build Coastguard Worker 			if (get_u32(&index, argv[optind + 1], 10)) {
233*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Illegal \"index\"\n");
234*de1e4e89SAndroid Build Coastguard Worker 				xtables_free_opts(1);
235*de1e4e89SAndroid Build Coastguard Worker 				return -1;
236*de1e4e89SAndroid Build Coastguard Worker 			}
237*de1e4e89SAndroid Build Coastguard Worker 			iok++;
238*de1e4e89SAndroid Build Coastguard Worker 
239*de1e4e89SAndroid Build Coastguard Worker 			optind += 2;
240*de1e4e89SAndroid Build Coastguard Worker 		}
241*de1e4e89SAndroid Build Coastguard Worker 	}
242*de1e4e89SAndroid Build Coastguard Worker 
243*de1e4e89SAndroid Build Coastguard Worker 	if (!ok && !iok) {
244*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv);
245*de1e4e89SAndroid Build Coastguard Worker 		return -1;
246*de1e4e89SAndroid Build Coastguard Worker 	}
247*de1e4e89SAndroid Build Coastguard Worker 
248*de1e4e89SAndroid Build Coastguard Worker 	/* check that we passed the correct parameters to the target */
249*de1e4e89SAndroid Build Coastguard Worker #if XTABLES_VERSION_CODE >= 6
250*de1e4e89SAndroid Build Coastguard Worker 	if (m)
251*de1e4e89SAndroid Build Coastguard Worker 		xtables_option_tfcall(m);
252*de1e4e89SAndroid Build Coastguard Worker #else
253*de1e4e89SAndroid Build Coastguard Worker 	if (m && m->final_check)
254*de1e4e89SAndroid Build Coastguard Worker 		m->final_check(m->tflags);
255*de1e4e89SAndroid Build Coastguard Worker #endif
256*de1e4e89SAndroid Build Coastguard Worker 
257*de1e4e89SAndroid Build Coastguard Worker 	{
258*de1e4e89SAndroid Build Coastguard Worker 		struct tcmsg *t = NLMSG_DATA(n);
259*de1e4e89SAndroid Build Coastguard Worker 
260*de1e4e89SAndroid Build Coastguard Worker 		if (t->tcm_parent != TC_H_ROOT
261*de1e4e89SAndroid Build Coastguard Worker 		    && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) {
262*de1e4e89SAndroid Build Coastguard Worker 			hook = NF_IP_PRE_ROUTING;
263*de1e4e89SAndroid Build Coastguard Worker 		} else {
264*de1e4e89SAndroid Build Coastguard Worker 			hook = NF_IP_POST_ROUTING;
265*de1e4e89SAndroid Build Coastguard Worker 		}
266*de1e4e89SAndroid Build Coastguard Worker 	}
267*de1e4e89SAndroid Build Coastguard Worker 
268*de1e4e89SAndroid Build Coastguard Worker 	tail = NLMSG_TAIL(n);
269*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
270*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
271*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stdout, "\ttarget: ");
272*de1e4e89SAndroid Build Coastguard Worker 
273*de1e4e89SAndroid Build Coastguard Worker 	if (m) {
274*de1e4e89SAndroid Build Coastguard Worker 		if (m->print)
275*de1e4e89SAndroid Build Coastguard Worker 			m->print(NULL, m->t, 0);
276*de1e4e89SAndroid Build Coastguard Worker 		else
277*de1e4e89SAndroid Build Coastguard Worker 			printf("%s ", m->name);
278*de1e4e89SAndroid Build Coastguard Worker 	}
279*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stdout, " index %d\n", index);
280*de1e4e89SAndroid Build Coastguard Worker 
281*de1e4e89SAndroid Build Coastguard Worker 	if (strlen(tname) >= 16) {
282*de1e4e89SAndroid Build Coastguard Worker 		size = 15;
283*de1e4e89SAndroid Build Coastguard Worker 		k[15] = 0;
284*de1e4e89SAndroid Build Coastguard Worker 	} else {
285*de1e4e89SAndroid Build Coastguard Worker 		size = 1 + strlen(tname);
286*de1e4e89SAndroid Build Coastguard Worker 	}
287*de1e4e89SAndroid Build Coastguard Worker 	strncpy(k, tname, size);
288*de1e4e89SAndroid Build Coastguard Worker 
289*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size);
290*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4);
291*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
292*de1e4e89SAndroid Build Coastguard Worker 	if (m)
293*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
294*de1e4e89SAndroid Build Coastguard Worker 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
295*de1e4e89SAndroid Build Coastguard Worker 
296*de1e4e89SAndroid Build Coastguard Worker 	argv += optind;
297*de1e4e89SAndroid Build Coastguard Worker 	*argc_p -= argc;
298*de1e4e89SAndroid Build Coastguard Worker 	*argv_p = argv;
299*de1e4e89SAndroid Build Coastguard Worker 
300*de1e4e89SAndroid Build Coastguard Worker 	optind = 0;
301*de1e4e89SAndroid Build Coastguard Worker 	xtables_free_opts(1);
302*de1e4e89SAndroid Build Coastguard Worker 
303*de1e4e89SAndroid Build Coastguard Worker 	if (m) {
304*de1e4e89SAndroid Build Coastguard Worker 		/* Clear flags if target will be used again */
305*de1e4e89SAndroid Build Coastguard Worker 		m->tflags = 0;
306*de1e4e89SAndroid Build Coastguard Worker 		m->used = 0;
307*de1e4e89SAndroid Build Coastguard Worker 		/* Free allocated memory */
308*de1e4e89SAndroid Build Coastguard Worker 		if (m->t)
309*de1e4e89SAndroid Build Coastguard Worker 			free(m->t);
310*de1e4e89SAndroid Build Coastguard Worker 	}
311*de1e4e89SAndroid Build Coastguard Worker 
312*de1e4e89SAndroid Build Coastguard Worker 	return 0;
313*de1e4e89SAndroid Build Coastguard Worker 
314*de1e4e89SAndroid Build Coastguard Worker }
315*de1e4e89SAndroid Build Coastguard Worker 
316*de1e4e89SAndroid Build Coastguard Worker static int
317*de1e4e89SAndroid Build Coastguard Worker print_ipt(struct action_util *au, FILE *f, struct rtattr *arg)
318*de1e4e89SAndroid Build Coastguard Worker {
319*de1e4e89SAndroid Build Coastguard Worker 	struct xtables_target *m;
320*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_IPT_MAX + 1];
321*de1e4e89SAndroid Build Coastguard Worker 	struct xt_entry_target *t = NULL;
322*de1e4e89SAndroid Build Coastguard Worker 
323*de1e4e89SAndroid Build Coastguard Worker 	if (arg == NULL)
324*de1e4e89SAndroid Build Coastguard Worker 		return -1;
325*de1e4e89SAndroid Build Coastguard Worker 
326*de1e4e89SAndroid Build Coastguard Worker 	/* copy tcipt_globals because .opts will be modified by iptables */
327*de1e4e89SAndroid Build Coastguard Worker 	struct xtables_globals tmp_tcipt_globals = tcipt_globals;
328*de1e4e89SAndroid Build Coastguard Worker 
329*de1e4e89SAndroid Build Coastguard Worker 	xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4);
330*de1e4e89SAndroid Build Coastguard Worker 	set_lib_dir();
331*de1e4e89SAndroid Build Coastguard Worker 
332*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
333*de1e4e89SAndroid Build Coastguard Worker 
334*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_IPT_TABLE] == NULL) {
335*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "[NULL ipt table name ] assuming mangle ");
336*de1e4e89SAndroid Build Coastguard Worker 	} else {
337*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "tablename: %s ",
338*de1e4e89SAndroid Build Coastguard Worker 			rta_getattr_str(tb[TCA_IPT_TABLE]));
339*de1e4e89SAndroid Build Coastguard Worker 	}
340*de1e4e89SAndroid Build Coastguard Worker 
341*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_IPT_HOOK] == NULL) {
342*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "[NULL ipt hook name ]\n ");
343*de1e4e89SAndroid Build Coastguard Worker 		return -1;
344*de1e4e89SAndroid Build Coastguard Worker 	} else {
345*de1e4e89SAndroid Build Coastguard Worker 		__u32 hook;
346*de1e4e89SAndroid Build Coastguard Worker 
347*de1e4e89SAndroid Build Coastguard Worker 		hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
348*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, " hook: %s\n", ipthooks[hook]);
349*de1e4e89SAndroid Build Coastguard Worker 	}
350*de1e4e89SAndroid Build Coastguard Worker 
351*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_IPT_TARG] == NULL) {
352*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "\t[NULL ipt target parameters ]\n");
353*de1e4e89SAndroid Build Coastguard Worker 		return -1;
354*de1e4e89SAndroid Build Coastguard Worker 	}
355*de1e4e89SAndroid Build Coastguard Worker 
356*de1e4e89SAndroid Build Coastguard Worker 	t = RTA_DATA(tb[TCA_IPT_TARG]);
357*de1e4e89SAndroid Build Coastguard Worker 	m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD);
358*de1e4e89SAndroid Build Coastguard Worker 	if (!m) {
359*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, " failed to find target %s\n\n",
360*de1e4e89SAndroid Build Coastguard Worker 			t->u.user.name);
361*de1e4e89SAndroid Build Coastguard Worker 		return -1;
362*de1e4e89SAndroid Build Coastguard Worker 	}
363*de1e4e89SAndroid Build Coastguard Worker 	if (build_st(m, t) < 0) {
364*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, " %s error\n", m->name);
365*de1e4e89SAndroid Build Coastguard Worker 		return -1;
366*de1e4e89SAndroid Build Coastguard Worker 	}
367*de1e4e89SAndroid Build Coastguard Worker 
368*de1e4e89SAndroid Build Coastguard Worker 	if (get_xtables_target_opts(&tmp_tcipt_globals, m) < 0) {
369*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr,
370*de1e4e89SAndroid Build Coastguard Worker 			" failed to find additional options for target %s\n\n",
371*de1e4e89SAndroid Build Coastguard Worker 			t->u.user.name);
372*de1e4e89SAndroid Build Coastguard Worker 		return -1;
373*de1e4e89SAndroid Build Coastguard Worker 	}
374*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "\ttarget ");
375*de1e4e89SAndroid Build Coastguard Worker 	m->print(NULL, m->t, 0);
376*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_IPT_INDEX] == NULL) {
377*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, " [NULL ipt target index ]\n");
378*de1e4e89SAndroid Build Coastguard Worker 	} else {
379*de1e4e89SAndroid Build Coastguard Worker 		__u32 index;
380*de1e4e89SAndroid Build Coastguard Worker 
381*de1e4e89SAndroid Build Coastguard Worker 		index = rta_getattr_u32(tb[TCA_IPT_INDEX]);
382*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, "\n\tindex %u", index);
383*de1e4e89SAndroid Build Coastguard Worker 	}
384*de1e4e89SAndroid Build Coastguard Worker 
385*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_IPT_CNT]) {
386*de1e4e89SAndroid Build Coastguard Worker 		struct tc_cnt *c  = RTA_DATA(tb[TCA_IPT_CNT]);
387*de1e4e89SAndroid Build Coastguard Worker 
388*de1e4e89SAndroid Build Coastguard Worker 		fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt);
389*de1e4e89SAndroid Build Coastguard Worker 	}
390*de1e4e89SAndroid Build Coastguard Worker 	if (show_stats) {
391*de1e4e89SAndroid Build Coastguard Worker 		if (tb[TCA_IPT_TM]) {
392*de1e4e89SAndroid Build Coastguard Worker 			struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
393*de1e4e89SAndroid Build Coastguard Worker 
394*de1e4e89SAndroid Build Coastguard Worker 			print_tm(f, tm);
395*de1e4e89SAndroid Build Coastguard Worker 		}
396*de1e4e89SAndroid Build Coastguard Worker 	}
397*de1e4e89SAndroid Build Coastguard Worker 	fprintf(f, "\n");
398*de1e4e89SAndroid Build Coastguard Worker 
399*de1e4e89SAndroid Build Coastguard Worker 	xtables_free_opts(1);
400*de1e4e89SAndroid Build Coastguard Worker 
401*de1e4e89SAndroid Build Coastguard Worker 	return 0;
402*de1e4e89SAndroid Build Coastguard Worker }
403*de1e4e89SAndroid Build Coastguard Worker 
404*de1e4e89SAndroid Build Coastguard Worker struct action_util xt_action_util = {
405*de1e4e89SAndroid Build Coastguard Worker 	.id = "xt",
406*de1e4e89SAndroid Build Coastguard Worker 	.parse_aopt = parse_ipt,
407*de1e4e89SAndroid Build Coastguard Worker 	.print_aopt = print_ipt,
408*de1e4e89SAndroid Build Coastguard Worker };
409