Home | History | Annotate | Download | only in extensions
      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. */
     16 static void
     17 help(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 
     26 static struct option opts[] = {
     27 	{ "mac-source", 1, 0, '1' },
     28 	{0}
     29 };
     30 
     31 static void
     32 parse_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 */
     57 static int
     58 parse(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 
     81 static 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. */
     92 static 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. */
    100 static void
    101 print(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. */
    114 static 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 
    123 static 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 
    137 void ipt_mac_init(void)
    138 {
    139 	register_match(&mac);
    140 }
    141