1/* Shared library add-on to iptables to add MAC address support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#if defined(__GLIBC__) && __GLIBC__ == 2
8#include <net/ethernet.h>
9#else
10#include <linux/if_ether.h>
11#endif
12#include <iptables.h>
13#include <linux/netfilter_ipv4/ipt_mac.h>
14
15/* Function which prints out usage message. */
16static void
17help(void)
18{
19	printf(
20"MAC v%s options:\n"
21" --mac-source [!] XX:XX:XX:XX:XX:XX\n"
22"				Match source MAC address\n"
23"\n", IPTABLES_VERSION);
24}
25
26static struct option opts[] = {
27	{ "mac-source", 1, 0, '1' },
28	{0}
29};
30
31static void
32parse_mac(const char *mac, struct ipt_mac_info *info)
33{
34	unsigned int i = 0;
35
36	if (strlen(mac) != ETH_ALEN*3-1)
37		exit_error(PARAMETER_PROBLEM, "Bad mac address `%s'", mac);
38
39	for (i = 0; i < ETH_ALEN; i++) {
40		long number;
41		char *end;
42
43		number = strtol(mac + i*3, &end, 16);
44
45		if (end == mac + i*3 + 2
46		    && number >= 0
47		    && number <= 255)
48			info->srcaddr[i] = number;
49		else
50			exit_error(PARAMETER_PROBLEM,
51				   "Bad mac address `%s'", mac);
52	}
53}
54
55/* Function which parses command options; returns true if it
56   ate an option */
57static int
58parse(int c, char **argv, int invert, unsigned int *flags,
59      const struct ipt_entry *entry,
60      unsigned int *nfcache,
61      struct ipt_entry_match **match)
62{
63	struct ipt_mac_info *macinfo = (struct ipt_mac_info *)(*match)->data;
64
65	switch (c) {
66	case '1':
67		check_inverse(optarg, &invert, &optind, 0);
68		parse_mac(argv[optind-1], macinfo);
69		if (invert)
70			macinfo->invert = 1;
71		*flags = 1;
72		break;
73
74	default:
75		return 0;
76	}
77
78	return 1;
79}
80
81static void print_mac(unsigned char macaddress[ETH_ALEN])
82{
83	unsigned int i;
84
85	printf("%02X", macaddress[0]);
86	for (i = 1; i < ETH_ALEN; i++)
87		printf(":%02X", macaddress[i]);
88	printf(" ");
89}
90
91/* Final check; must have specified --mac. */
92static void final_check(unsigned int flags)
93{
94	if (!flags)
95		exit_error(PARAMETER_PROBLEM,
96			   "You must specify `--mac-source'");
97}
98
99/* Prints out the matchinfo. */
100static void
101print(const struct ipt_ip *ip,
102      const struct ipt_entry_match *match,
103      int numeric)
104{
105	printf("MAC ");
106
107	if (((struct ipt_mac_info *)match->data)->invert)
108		printf("! ");
109
110	print_mac(((struct ipt_mac_info *)match->data)->srcaddr);
111}
112
113/* Saves the union ipt_matchinfo in parsable form to stdout. */
114static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
115{
116	if (((struct ipt_mac_info *)match->data)->invert)
117		printf("! ");
118
119	printf("--mac-source ");
120	print_mac(((struct ipt_mac_info *)match->data)->srcaddr);
121}
122
123static struct iptables_match mac = {
124	.next		= NULL,
125 	.name		= "mac",
126	.version	= IPTABLES_VERSION,
127	.size		= IPT_ALIGN(sizeof(struct ipt_mac_info)),
128	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_mac_info)),
129	.help		= &help,
130	.parse		= &parse,
131	.final_check	= &final_check,
132	.print		= &print,
133	.save		= &save,
134	.extra_opts	= opts
135};
136
137void _init(void)
138{
139	register_match(&mac);
140}
141