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 <ip6tables.h>
13#include <linux/netfilter_ipv6/ip6t_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 ip6t_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 ip6t_entry *entry,
60      unsigned int *nfcache,
61      struct ip6t_entry_match **match)
62{
63	struct ip6t_mac_info *macinfo = (struct ip6t_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 ip6t_ip6 *ip,
102      const struct ip6t_entry_match *match,
103      int numeric)
104{
105	printf("MAC ");
106
107	if (((struct ip6t_mac_info *)match->data)->invert)
108		printf("! ");
109
110	print_mac(((struct ip6t_mac_info *)match->data)->srcaddr);
111}
112
113/* Saves the union ip6t_matchinfo in parsable form to stdout. */
114static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
115{
116	if (((struct ip6t_mac_info *)match->data)->invert)
117		printf("! ");
118
119	printf("--mac-source ");
120	print_mac(((struct ip6t_mac_info *)match->data)->srcaddr);
121}
122
123static struct ip6tables_match mac = {
124	.name		= "mac",
125	.version	= IPTABLES_VERSION,
126	.size		= IP6T_ALIGN(sizeof(struct ip6t_mac_info)),
127	.userspacesize	= IP6T_ALIGN(sizeof(struct ip6t_mac_info)),
128	.help		= &help,
129	.parse		= &parse,
130	.final_check	= &final_check,
131	.print		= &print,
132	.save		= &save,
133	.extra_opts	= opts,
134};
135
136void _init(void)
137{
138	register_match6(&mac);
139}
140