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 <netdb.h>
9#include <string.h>
10#include <stdlib.h>
11#include <getopt.h>
12#if defined(__GLIBC__) && __GLIBC__ == 2
13#include <net/ethernet.h>
14#else
15#include <linux/if_ether.h>
16#endif
17#include <iptables.h>
18#include <linux/if_packet.h>
19#include <linux/netfilter_ipv4/ipt_pkttype.h>
20
21#define	PKTTYPE_VERSION	"0.1"
22
23struct pkttypes {
24	const char *name;
25	unsigned char pkttype;
26	unsigned char printhelp;
27	const char *help;
28};
29
30static const struct pkttypes supported_types[] = {
31	{"unicast", PACKET_HOST, 1, "to us"},
32	{"broadcast", PACKET_BROADCAST, 1, "to all"},
33	{"multicast", PACKET_MULTICAST, 1, "to group"},
34/*
35	{"otherhost", PACKET_OTHERHOST, 1, "to someone else"},
36	{"outgoing", PACKET_OUTGOING, 1, "outgoing of any type"},
37*/
38	/* aliases */
39	{"bcast", PACKET_BROADCAST, 0, NULL},
40	{"mcast", PACKET_MULTICAST, 0, NULL},
41	{"host", PACKET_HOST, 0, NULL}
42};
43
44static void print_types()
45{
46	unsigned int	i;
47
48	printf("Valid packet types:\n");
49	for (i = 0; i < sizeof(supported_types)/sizeof(struct pkttypes); i++)
50	{
51		if(supported_types[i].printhelp == 1)
52			printf("\t%-14s\t\t%s\n", supported_types[i].name, supported_types[i].help);
53	}
54	printf("\n");
55}
56
57/* Function which prints out usage message. */
58static void help(void)
59{
60	printf(
61"pkt_type v%s options:\n"
62"  --pkt-type [!] packettype\tmatch packet type\n"
63"\n", PKTTYPE_VERSION);
64	print_types();
65}
66
67static struct option opts[] = {
68	{"pkt-type", 1, 0, '1'},
69	{0}
70};
71
72static void parse_pkttype(const char *pkttype, struct ipt_pkttype_info *info)
73{
74	unsigned int	i;
75
76	for (i = 0; i < sizeof(supported_types)/sizeof(struct pkttypes); i++)
77	{
78		if(strcasecmp(pkttype, supported_types[i].name)==0)
79		{
80			info->pkttype=supported_types[i].pkttype;
81			return;
82		}
83	}
84
85	exit_error(PARAMETER_PROBLEM, "Bad packet type '%s'", pkttype);
86}
87
88static int parse(int c, char **argv, int invert, unsigned int *flags,
89      const struct ipt_entry *entry,
90      unsigned int *nfcache,
91      struct ipt_entry_match **match)
92{
93	struct ipt_pkttype_info *info = (struct ipt_pkttype_info *)(*match)->data;
94
95	switch(c)
96	{
97		case '1':
98			check_inverse(optarg, &invert, &optind, 0);
99			parse_pkttype(argv[optind-1], info);
100			if(invert)
101				info->invert=1;
102			*flags=1;
103			break;
104
105		default:
106			return 0;
107	}
108
109	return 1;
110}
111
112static void final_check(unsigned int flags)
113{
114	if (!flags)
115		exit_error(PARAMETER_PROBLEM, "You must specify `--pkt-type'");
116}
117
118static void print_pkttype(struct ipt_pkttype_info *info)
119{
120	unsigned int	i;
121
122	for (i = 0; i < sizeof(supported_types)/sizeof(struct pkttypes); i++)
123	{
124		if(supported_types[i].pkttype==info->pkttype)
125		{
126			printf("%s ", supported_types[i].name);
127			return;
128		}
129	}
130
131	printf("%d ", info->pkttype);	/* in case we didn't find an entry in named-packtes */
132}
133
134static void print(const struct ipt_ip *ip, const struct ipt_entry_match *match, int numeric)
135{
136	struct ipt_pkttype_info *info = (struct ipt_pkttype_info *)match->data;
137
138	printf("PKTTYPE %s= ", info->invert?"!":"");
139	print_pkttype(info);
140}
141
142static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
143{
144	struct ipt_pkttype_info *info = (struct ipt_pkttype_info *)match->data;
145
146	printf("--pkt-type %s", info->invert?"! ":"");
147	print_pkttype(info);
148}
149
150static struct iptables_match pkttype = {
151	.next		= NULL,
152	.name		= "pkttype",
153	.version	= IPTABLES_VERSION,
154	.size		= IPT_ALIGN(sizeof(struct ipt_pkttype_info)),
155	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_pkttype_info)),
156	.help		= &help,
157	.parse		= &parse,
158	.final_check	= &final_check,
159	.print		= &print,
160	.save		= &save,
161	.extra_opts	= opts
162};
163
164void _init(void)
165{
166	register_match(&pkttype);
167}
168