xref: /aosp_15_r20/external/iptables/extensions/libxt_owner.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 /*
2  *	libxt_owner - iptables addon for xt_owner
3  *
4  *	Copyright © CC Computer Consultants GmbH, 2007 - 2008
5  *	Jan Engelhardt <[email protected]>
6  */
7 #include <grp.h>
8 #include <pwd.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <limits.h>
12 #include <xtables.h>
13 #include <linux/netfilter/xt_owner.h>
14 
15 /* match and invert flags */
16 enum {
17 	IPT_OWNER_UID   = 0x01,
18 	IPT_OWNER_GID   = 0x02,
19 	IPT_OWNER_PID   = 0x04,
20 	IPT_OWNER_SID   = 0x08,
21 	IPT_OWNER_COMM  = 0x10,
22 	IP6T_OWNER_UID  = IPT_OWNER_UID,
23 	IP6T_OWNER_GID  = IPT_OWNER_GID,
24 	IP6T_OWNER_PID  = IPT_OWNER_PID,
25 	IP6T_OWNER_SID  = IPT_OWNER_SID,
26 	IP6T_OWNER_COMM = IPT_OWNER_COMM,
27 };
28 
29 struct ipt_owner_info {
30 	uid_t uid;
31 	gid_t gid;
32 	pid_t pid;
33 	pid_t sid;
34 	char comm[16];
35 	uint8_t match, invert;	/* flags */
36 };
37 
38 struct ip6t_owner_info {
39 	uid_t uid;
40 	gid_t gid;
41 	pid_t pid;
42 	pid_t sid;
43 	char comm[16];
44 	uint8_t match, invert;	/* flags */
45 };
46 
47 /*
48  *	Note: "UINT32_MAX - 1" is used in the code because -1 is a reserved
49  *	UID/GID value anyway.
50  */
51 
52 enum {
53 	O_USER = 0,
54 	O_GROUP,
55 	O_SOCK_EXISTS,
56 	O_PROCESS,
57 	O_SESSION,
58 	O_COMM,
59 	O_SUPPL_GROUPS,
60 };
61 
owner_mt_help_v0(void)62 static void owner_mt_help_v0(void)
63 {
64 	printf(
65 "owner match options:\n"
66 "[!] --uid-owner userid       Match local UID\n"
67 "[!] --gid-owner groupid      Match local GID\n"
68 "[!] --pid-owner processid    Match local PID\n"
69 "[!] --sid-owner sessionid    Match local SID\n"
70 "[!] --cmd-owner name         Match local command name\n"
71 "NOTE: PID, SID and command matching are broken on SMP\n");
72 }
73 
owner_mt6_help_v0(void)74 static void owner_mt6_help_v0(void)
75 {
76 	printf(
77 "owner match options:\n"
78 "[!] --uid-owner userid       Match local UID\n"
79 "[!] --gid-owner groupid      Match local GID\n"
80 "[!] --pid-owner processid    Match local PID\n"
81 "[!] --sid-owner sessionid    Match local SID\n"
82 "NOTE: PID and SID matching are broken on SMP\n");
83 }
84 
owner_mt_help(void)85 static void owner_mt_help(void)
86 {
87 	printf(
88 "owner match options:\n"
89 "[!] --uid-owner userid[-userid]      Match local UID\n"
90 "[!] --gid-owner groupid[-groupid]    Match local GID\n"
91 "[!] --socket-exists                  Match if socket exists\n"
92 "    --suppl-groups                   Also match supplementary groups set with --gid-owner\n");
93 }
94 
95 #define s struct ipt_owner_info
96 static const struct xt_option_entry owner_mt_opts_v0[] = {
97 	{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
98 	 .flags = XTOPT_INVERT},
99 	{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
100 	 .flags = XTOPT_INVERT},
101 	{.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32,
102 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid),
103 	 .max = INT_MAX},
104 	{.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32,
105 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid),
106 	 .max = INT_MAX},
107 	{.name = "cmd-owner", .id = O_COMM, .type = XTTYPE_STRING,
108 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, comm)},
109 	XTOPT_TABLEEND,
110 };
111 #undef s
112 
113 #define s struct ip6t_owner_info
114 static const struct xt_option_entry owner_mt6_opts_v0[] = {
115 	{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
116 	 .flags = XTOPT_INVERT},
117 	{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
118 	 .flags = XTOPT_INVERT},
119 	{.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32,
120 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid),
121 	 .max = INT_MAX},
122 	{.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32,
123 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid),
124 	 .max = INT_MAX},
125 	XTOPT_TABLEEND,
126 };
127 #undef s
128 
129 static const struct xt_option_entry owner_mt_opts[] = {
130 	{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
131 	 .flags = XTOPT_INVERT},
132 	{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
133 	 .flags = XTOPT_INVERT},
134 	{.name = "socket-exists", .id = O_SOCK_EXISTS, .type = XTTYPE_NONE,
135 	 .flags = XTOPT_INVERT},
136 	{.name = "suppl-groups", .id = O_SUPPL_GROUPS, .type = XTTYPE_NONE},
137 	XTOPT_TABLEEND,
138 };
139 
owner_mt_parse_v0(struct xt_option_call * cb)140 static void owner_mt_parse_v0(struct xt_option_call *cb)
141 {
142 	struct ipt_owner_info *info = cb->data;
143 	struct passwd *pwd;
144 	struct group *grp;
145 	unsigned int id;
146 
147 	xtables_option_parse(cb);
148 	switch (cb->entry->id) {
149 	case O_USER:
150 		if ((pwd = getpwnam(cb->arg)) != NULL)
151 			id = pwd->pw_uid;
152 		else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
153 			xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg);
154 		if (cb->invert)
155 			info->invert |= IPT_OWNER_UID;
156 		info->match |= IPT_OWNER_UID;
157 		info->uid    = id;
158 		break;
159 	case O_GROUP:
160 		if ((grp = getgrnam(cb->arg)) != NULL)
161 			id = grp->gr_gid;
162 		else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
163 			xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg);
164 		if (cb->invert)
165 			info->invert |= IPT_OWNER_GID;
166 		info->match |= IPT_OWNER_GID;
167 		info->gid    = id;
168 		break;
169 	case O_PROCESS:
170 		if (cb->invert)
171 			info->invert |= IPT_OWNER_PID;
172 		info->match |= IPT_OWNER_PID;
173 		break;
174 	case O_SESSION:
175 		if (cb->invert)
176 			info->invert |= IPT_OWNER_SID;
177 		info->match |= IPT_OWNER_SID;
178 		break;
179 	case O_COMM:
180 		if (cb->invert)
181 			info->invert |= IPT_OWNER_COMM;
182 		info->match |= IPT_OWNER_COMM;
183 		break;
184 	}
185 }
186 
owner_mt6_parse_v0(struct xt_option_call * cb)187 static void owner_mt6_parse_v0(struct xt_option_call *cb)
188 {
189 	struct ip6t_owner_info *info = cb->data;
190 	struct passwd *pwd;
191 	struct group *grp;
192 	unsigned int id;
193 
194 	xtables_option_parse(cb);
195 	switch (cb->entry->id) {
196 	case O_USER:
197 		if ((pwd = getpwnam(cb->arg)) != NULL)
198 			id = pwd->pw_uid;
199 		else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
200 			xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg);
201 		if (cb->invert)
202 			info->invert |= IP6T_OWNER_UID;
203 		info->match |= IP6T_OWNER_UID;
204 		info->uid    = id;
205 		break;
206 	case O_GROUP:
207 		if ((grp = getgrnam(cb->arg)) != NULL)
208 			id = grp->gr_gid;
209 		else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
210 			xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg);
211 		if (cb->invert)
212 			info->invert |= IP6T_OWNER_GID;
213 		info->match |= IP6T_OWNER_GID;
214 		info->gid    = id;
215 		break;
216 	case O_PROCESS:
217 		if (cb->invert)
218 			info->invert |= IP6T_OWNER_PID;
219 		info->match |= IP6T_OWNER_PID;
220 		break;
221 	case O_SESSION:
222 		if (cb->invert)
223 			info->invert |= IP6T_OWNER_SID;
224 		info->match |= IP6T_OWNER_SID;
225 		break;
226 	}
227 }
228 
owner_parse_range(const char * s,unsigned int * from,unsigned int * to,const char * opt)229 static void owner_parse_range(const char *s, unsigned int *from,
230                               unsigned int *to, const char *opt)
231 {
232 	char *end;
233 
234 	/* -1 is reversed, so the max is one less than that. */
235 	if (!xtables_strtoui(s, &end, from, 0, UINT32_MAX - 1))
236 		xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
237 	*to = *from;
238 	if (*end == '-' || *end == ':')
239 		if (!xtables_strtoui(end + 1, &end, to, 0, UINT32_MAX - 1))
240 			xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
241 	if (*end != '\0')
242 		xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
243 }
244 
owner_mt_parse(struct xt_option_call * cb)245 static void owner_mt_parse(struct xt_option_call *cb)
246 {
247 	struct xt_owner_match_info *info = cb->data;
248 	struct passwd *pwd;
249 	struct group *grp;
250 	unsigned int from, to;
251 
252 	xtables_option_parse(cb);
253 	switch (cb->entry->id) {
254 	case O_USER:
255 		if ((pwd = getpwnam(cb->arg)) != NULL)
256 			from = to = pwd->pw_uid;
257 		else
258 			owner_parse_range(cb->arg, &from, &to, "--uid-owner");
259 		if (cb->invert)
260 			info->invert |= XT_OWNER_UID;
261 		info->match  |= XT_OWNER_UID;
262 		info->uid_min = from;
263 		info->uid_max = to;
264 		break;
265 	case O_GROUP:
266 		if ((grp = getgrnam(cb->arg)) != NULL)
267 			from = to = grp->gr_gid;
268 		else
269 			owner_parse_range(cb->arg, &from, &to, "--gid-owner");
270 		if (cb->invert)
271 			info->invert |= XT_OWNER_GID;
272 		info->match  |= XT_OWNER_GID;
273 		info->gid_min = from;
274 		info->gid_max = to;
275 		break;
276 	case O_SOCK_EXISTS:
277 		if (cb->invert)
278 			info->invert |= XT_OWNER_SOCKET;
279 		info->match |= XT_OWNER_SOCKET;
280 		break;
281 	case O_SUPPL_GROUPS:
282 		if (!(info->match & XT_OWNER_GID))
283 			xtables_param_act(XTF_BAD_VALUE, "owner", "--suppl-groups", "you need to use --gid-owner first");
284 		info->match |= XT_OWNER_SUPPL_GROUPS;
285 		break;
286 	}
287 }
288 
owner_mt_check(struct xt_fcheck_call * cb)289 static void owner_mt_check(struct xt_fcheck_call *cb)
290 {
291 	if (cb->xflags == 0)
292 		xtables_error(PARAMETER_PROBLEM, "owner: At least one of "
293 		           "--uid-owner, --gid-owner or --socket-exists "
294 		           "is required");
295 }
296 
297 static void
owner_mt_print_item_v0(const struct ipt_owner_info * info,const char * label,uint8_t flag,bool numeric)298 owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label,
299                        uint8_t flag, bool numeric)
300 {
301 	if (!(info->match & flag))
302 		return;
303 	if (info->invert & flag)
304 		printf(" !");
305 	printf(" %s", label);
306 
307 	switch (info->match & flag) {
308 	case IPT_OWNER_UID:
309 		if (!numeric) {
310 			struct passwd *pwd = getpwuid(info->uid);
311 
312 			if (pwd != NULL && pwd->pw_name != NULL) {
313 				printf(" %s", pwd->pw_name);
314 				break;
315 			}
316 		}
317 		printf(" %u", (unsigned int)info->uid);
318 		break;
319 
320 	case IPT_OWNER_GID:
321 		if (!numeric) {
322 			struct group *grp = getgrgid(info->gid);
323 
324 			if (grp != NULL && grp->gr_name != NULL) {
325 				printf(" %s", grp->gr_name);
326 				break;
327 			}
328 		}
329 		printf(" %u", (unsigned int)info->gid);
330 		break;
331 
332 	case IPT_OWNER_PID:
333 		printf(" %u", (unsigned int)info->pid);
334 		break;
335 
336 	case IPT_OWNER_SID:
337 		printf(" %u", (unsigned int)info->sid);
338 		break;
339 
340 	case IPT_OWNER_COMM:
341 		printf(" %.*s", (int)sizeof(info->comm), info->comm);
342 		break;
343 	}
344 }
345 
346 static void
owner_mt6_print_item_v0(const struct ip6t_owner_info * info,const char * label,uint8_t flag,bool numeric)347 owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label,
348                         uint8_t flag, bool numeric)
349 {
350 	if (!(info->match & flag))
351 		return;
352 	if (info->invert & flag)
353 		printf(" !");
354 	printf(" %s", label);
355 
356 	switch (info->match & flag) {
357 	case IP6T_OWNER_UID:
358 		if (!numeric) {
359 			struct passwd *pwd = getpwuid(info->uid);
360 
361 			if (pwd != NULL && pwd->pw_name != NULL) {
362 				printf(" %s", pwd->pw_name);
363 				break;
364 			}
365 		}
366 		printf(" %u", (unsigned int)info->uid);
367 		break;
368 
369 	case IP6T_OWNER_GID:
370 		if (!numeric) {
371 			struct group *grp = getgrgid(info->gid);
372 
373 			if (grp != NULL && grp->gr_name != NULL) {
374 				printf(" %s", grp->gr_name);
375 				break;
376 			}
377 		}
378 		printf(" %u", (unsigned int)info->gid);
379 		break;
380 
381 	case IP6T_OWNER_PID:
382 		printf(" %u", (unsigned int)info->pid);
383 		break;
384 
385 	case IP6T_OWNER_SID:
386 		printf(" %u", (unsigned int)info->sid);
387 		break;
388 	}
389 }
390 
391 static void
owner_mt_print_item(const struct xt_owner_match_info * info,const char * label,uint8_t flag,bool numeric)392 owner_mt_print_item(const struct xt_owner_match_info *info, const char *label,
393                     uint8_t flag, bool numeric)
394 {
395 	if (!(info->match & flag))
396 		return;
397 	if (info->invert & flag)
398 		printf(" !");
399 	printf(" %s", label);
400 
401 	switch (info->match & flag) {
402 	case XT_OWNER_UID:
403 		if (info->uid_min != info->uid_max) {
404 			printf(" %u-%u", (unsigned int)info->uid_min,
405 			       (unsigned int)info->uid_max);
406 			break;
407 		} else if (!numeric) {
408 			const struct passwd *pwd = getpwuid(info->uid_min);
409 
410 			if (pwd != NULL && pwd->pw_name != NULL) {
411 				printf(" %s", pwd->pw_name);
412 				break;
413 			}
414 		}
415 		printf(" %u", (unsigned int)info->uid_min);
416 		break;
417 
418 	case XT_OWNER_GID:
419 		if (info->gid_min != info->gid_max) {
420 			printf(" %u-%u", (unsigned int)info->gid_min,
421 			       (unsigned int)info->gid_max);
422 			break;
423 		} else if (!numeric) {
424 			const struct group *grp = getgrgid(info->gid_min);
425 
426 			if (grp != NULL && grp->gr_name != NULL) {
427 				printf(" %s", grp->gr_name);
428 				break;
429 			}
430 		}
431 		printf(" %u", (unsigned int)info->gid_min);
432 		break;
433 	}
434 }
435 
436 static void
owner_mt_print_v0(const void * ip,const struct xt_entry_match * match,int numeric)437 owner_mt_print_v0(const void *ip, const struct xt_entry_match *match,
438                   int numeric)
439 {
440 	const struct ipt_owner_info *info = (void *)match->data;
441 
442 	owner_mt_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
443 	owner_mt_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
444 	owner_mt_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
445 	owner_mt_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
446 	owner_mt_print_item_v0(info, "owner CMD match", IPT_OWNER_COMM, numeric);
447 }
448 
449 static void
owner_mt6_print_v0(const void * ip,const struct xt_entry_match * match,int numeric)450 owner_mt6_print_v0(const void *ip, const struct xt_entry_match *match,
451                    int numeric)
452 {
453 	const struct ip6t_owner_info *info = (void *)match->data;
454 
455 	owner_mt6_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
456 	owner_mt6_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
457 	owner_mt6_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
458 	owner_mt6_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
459 }
460 
owner_mt_print(const void * ip,const struct xt_entry_match * match,int numeric)461 static void owner_mt_print(const void *ip, const struct xt_entry_match *match,
462                            int numeric)
463 {
464 	const struct xt_owner_match_info *info = (void *)match->data;
465 
466 	owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET,       numeric);
467 	owner_mt_print_item(info, "owner UID match",     XT_OWNER_UID,          numeric);
468 	owner_mt_print_item(info, "owner GID match",     XT_OWNER_GID,          numeric);
469 	owner_mt_print_item(info, "incl. suppl. groups", XT_OWNER_SUPPL_GROUPS, numeric);
470 }
471 
472 static void
owner_mt_save_v0(const void * ip,const struct xt_entry_match * match)473 owner_mt_save_v0(const void *ip, const struct xt_entry_match *match)
474 {
475 	const struct ipt_owner_info *info = (void *)match->data;
476 
477 	owner_mt_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
478 	owner_mt_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
479 	owner_mt_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
480 	owner_mt_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
481 	owner_mt_print_item_v0(info, "--cmd-owner", IPT_OWNER_COMM, true);
482 }
483 
484 static void
owner_mt6_save_v0(const void * ip,const struct xt_entry_match * match)485 owner_mt6_save_v0(const void *ip, const struct xt_entry_match *match)
486 {
487 	const struct ip6t_owner_info *info = (void *)match->data;
488 
489 	owner_mt6_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
490 	owner_mt6_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
491 	owner_mt6_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
492 	owner_mt6_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
493 }
494 
owner_mt_save(const void * ip,const struct xt_entry_match * match)495 static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
496 {
497 	const struct xt_owner_match_info *info = (void *)match->data;
498 
499 	owner_mt_print_item(info, "--socket-exists",  XT_OWNER_SOCKET,       true);
500 	owner_mt_print_item(info, "--uid-owner",      XT_OWNER_UID,          true);
501 	owner_mt_print_item(info, "--gid-owner",      XT_OWNER_GID,          true);
502 	owner_mt_print_item(info, "--suppl-groups",   XT_OWNER_SUPPL_GROUPS, true);
503 }
504 
505 static int
owner_mt_print_uid_xlate(const struct xt_owner_match_info * info,struct xt_xlate * xl)506 owner_mt_print_uid_xlate(const struct xt_owner_match_info *info,
507 			 struct xt_xlate *xl)
508 {
509 	xt_xlate_add(xl, "skuid%s ", info->invert ? " !=" : "");
510 
511 	if (info->uid_min != info->uid_max)
512 		xt_xlate_add(xl, "%u-%u", (unsigned int)info->uid_min,
513 			     (unsigned int)info->uid_max);
514 	else
515 		xt_xlate_add(xl, "%u", (unsigned int)info->uid_min);
516 
517 	return 1;
518 }
519 
520 static int
owner_mt_print_gid_xlate(const struct xt_owner_match_info * info,struct xt_xlate * xl)521 owner_mt_print_gid_xlate(const struct xt_owner_match_info *info,
522 			 struct xt_xlate *xl)
523 {
524 	xt_xlate_add(xl, "skgid%s ", info->invert ? " !=" : "");
525 
526 	if (info->gid_min != info->gid_max)
527 		xt_xlate_add(xl, "%u-%u", (unsigned int)info->gid_min,
528 			     (unsigned int)info->gid_max);
529 	else
530 		xt_xlate_add(xl, "%u", (unsigned int)info->gid_min);
531 
532 	return 1;
533 }
534 
owner_mt_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)535 static int owner_mt_xlate(struct xt_xlate *xl,
536 			  const struct xt_xlate_mt_params *params)
537 {
538 	const struct xt_owner_match_info *info = (void *)params->match->data;
539 	int ret;
540 
541 	switch (info->match) {
542 	case XT_OWNER_UID:
543 		ret = owner_mt_print_uid_xlate(info, xl);
544 		break;
545 	case XT_OWNER_GID:
546 		ret = owner_mt_print_gid_xlate(info, xl);
547 		break;
548 	default:
549 		ret = 0;
550 	}
551 
552 	return ret;
553 }
554 
555 static struct xtables_match owner_mt_reg[] = {
556 	{
557 		.version       = XTABLES_VERSION,
558 		.name          = "owner",
559 		.revision      = 0,
560 		.family        = NFPROTO_IPV4,
561 		.size          = XT_ALIGN(sizeof(struct ipt_owner_info)),
562 		.userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)),
563 		.help          = owner_mt_help_v0,
564 		.x6_parse      = owner_mt_parse_v0,
565 		.x6_fcheck     = owner_mt_check,
566 		.print         = owner_mt_print_v0,
567 		.save          = owner_mt_save_v0,
568 		.x6_options    = owner_mt_opts_v0,
569 	},
570 	{
571 		.version       = XTABLES_VERSION,
572 		.name          = "owner",
573 		.revision      = 0,
574 		.family        = NFPROTO_IPV6,
575 		.size          = XT_ALIGN(sizeof(struct ip6t_owner_info)),
576 		.userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)),
577 		.help          = owner_mt6_help_v0,
578 		.x6_parse      = owner_mt6_parse_v0,
579 		.x6_fcheck     = owner_mt_check,
580 		.print         = owner_mt6_print_v0,
581 		.save          = owner_mt6_save_v0,
582 		.x6_options    = owner_mt6_opts_v0,
583 	},
584 	{
585 		.version       = XTABLES_VERSION,
586 		.name          = "owner",
587 		.revision      = 1,
588 		.family        = NFPROTO_UNSPEC,
589 		.size          = XT_ALIGN(sizeof(struct xt_owner_match_info)),
590 		.userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
591 		.help          = owner_mt_help,
592 		.x6_parse      = owner_mt_parse,
593 		.x6_fcheck     = owner_mt_check,
594 		.print         = owner_mt_print,
595 		.save          = owner_mt_save,
596 		.x6_options    = owner_mt_opts,
597 		.xlate	       = owner_mt_xlate,
598 	},
599 };
600 
_init(void)601 void _init(void)
602 {
603 	xtables_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg));
604 }
605