1/*
2 * Shared library add-on to iptables to match
3 * packets by their type (BROADCAST, UNICAST, MULTICAST).
4 *
5 * Michal Ludvig <michal@logix.cz>
6 */
7#include <stdio.h>
8#include <string.h>
9#include <xtables.h>
10#include <linux/if_packet.h>
11#include <linux/netfilter/xt_pkttype.h>
12
13enum {
14	O_PKTTYPE = 0,
15};
16
17struct pkttypes {
18	const char *name;
19	unsigned char pkttype;
20	unsigned char printhelp;
21	const char *help;
22};
23
24static const struct pkttypes supported_types[] = {
25	{"unicast", PACKET_HOST, 1, "to us"},
26	{"broadcast", PACKET_BROADCAST, 1, "to all"},
27	{"multicast", PACKET_MULTICAST, 1, "to group"},
28/*
29	{"otherhost", PACKET_OTHERHOST, 1, "to someone else"},
30	{"outgoing", PACKET_OUTGOING, 1, "outgoing of any type"},
31*/
32	/* aliases */
33	{"bcast", PACKET_BROADCAST, 0, NULL},
34	{"mcast", PACKET_MULTICAST, 0, NULL},
35	{"host", PACKET_HOST, 0, NULL}
36};
37
38static void print_types(void)
39{
40	unsigned int	i;
41
42	printf("Valid packet types:\n");
43	for (i = 0; i < ARRAY_SIZE(supported_types); ++i)
44		if(supported_types[i].printhelp == 1)
45			printf("\t%-14s\t\t%s\n", supported_types[i].name, supported_types[i].help);
46	printf("\n");
47}
48
49static void pkttype_help(void)
50{
51	printf(
52"pkttype match options:\n"
53"[!] --pkt-type packettype    match packet type\n");
54	print_types();
55}
56
57static const struct xt_option_entry pkttype_opts[] = {
58	{.name = "pkt-type", .id = O_PKTTYPE, .type = XTTYPE_STRING,
59	 .flags = XTOPT_MAND | XTOPT_INVERT},
60	XTOPT_TABLEEND,
61};
62
63static void parse_pkttype(const char *pkttype, struct xt_pkttype_info *info)
64{
65	unsigned int	i;
66
67	for (i = 0; i < ARRAY_SIZE(supported_types); ++i)
68		if(strcasecmp(pkttype, supported_types[i].name)==0)
69		{
70			info->pkttype=supported_types[i].pkttype;
71			return;
72		}
73
74	xtables_error(PARAMETER_PROBLEM, "Bad packet type '%s'", pkttype);
75}
76
77static void pkttype_parse(struct xt_option_call *cb)
78{
79	struct xt_pkttype_info *info = cb->data;
80
81	xtables_option_parse(cb);
82	parse_pkttype(cb->arg, info);
83	if (cb->invert)
84		info->invert = 1;
85}
86
87static void print_pkttype(const struct xt_pkttype_info *info)
88{
89	unsigned int	i;
90
91	for (i = 0; i < ARRAY_SIZE(supported_types); ++i)
92		if(supported_types[i].pkttype==info->pkttype)
93		{
94			printf("%s", supported_types[i].name);
95			return;
96		}
97
98	printf("%d", info->pkttype);	/* in case we didn't find an entry in named-packtes */
99}
100
101static void pkttype_print(const void *ip, const struct xt_entry_match *match,
102                          int numeric)
103{
104	const struct xt_pkttype_info *info = (const void *)match->data;
105
106	printf(" PKTTYPE %s= ", info->invert ? "!" : "");
107	print_pkttype(info);
108}
109
110static void pkttype_save(const void *ip, const struct xt_entry_match *match)
111{
112	const struct xt_pkttype_info *info = (const void *)match->data;
113
114	printf("%s --pkt-type ", info->invert ? " !" : "");
115	print_pkttype(info);
116}
117
118static struct xtables_match pkttype_match = {
119	.family		= NFPROTO_UNSPEC,
120	.name		= "pkttype",
121	.version	= XTABLES_VERSION,
122	.size		= XT_ALIGN(sizeof(struct xt_pkttype_info)),
123	.userspacesize	= XT_ALIGN(sizeof(struct xt_pkttype_info)),
124	.help		= pkttype_help,
125	.print		= pkttype_print,
126	.save		= pkttype_save,
127	.x6_parse	= pkttype_parse,
128	.x6_options	= pkttype_opts,
129};
130
131void _init(void)
132{
133	xtables_register_match(&pkttype_match);
134}
135