Home | History | Annotate | Download | only in extensions
      1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem (at) linux.nu>
      2  *                         Patrick Schaaf <bof (at) bof.de>
      3  *                         Martin Josefsson <gandalf (at) wlug.westbo.se>
      4  * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec (at) blackhole.kfki.hu>
      5  *
      6  * This program is free software; you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License version 2 as
      8  * published by the Free Software Foundation.
      9  */
     10 
     11 /* Shared library add-on to iptables to add IP set mangling target. */
     12 #include <stdio.h>
     13 #include <netdb.h>
     14 #include <string.h>
     15 #include <stdlib.h>
     16 #include <getopt.h>
     17 #include <ctype.h>
     18 
     19 #include <iptables.h>
     20 #include <linux/netfilter_ipv4/ip_tables.h>
     21 #include <linux/netfilter_ipv4/ip_nat_rule.h>
     22 #include <linux/netfilter_ipv4/ip_set.h>
     23 #include <linux/netfilter_ipv4/ipt_set.h>
     24 #include "libipt_set.h"
     25 
     26 /* Function which prints out usage message. */
     27 static void help(void)
     28 {
     29 	printf("SET v%s options:\n"
     30 	       " --add-set name flags\n"
     31 	       " --del-set name flags\n"
     32 	       "		add/del src/dst IP/port from/to named sets,\n"
     33 	       "		where flags are the comma separated list of\n"
     34 	       "		'src' and 'dst'.\n"
     35 	       "\n", IPTABLES_VERSION);
     36 }
     37 
     38 static struct option opts[] = {
     39 	{"add-set",   1, 0, '1'},
     40 	{"del-set",   1, 0, '2'},
     41 	{0}
     42 };
     43 
     44 /* Initialize the target. */
     45 static void init(struct ipt_entry_target *target, unsigned int *nfcache)
     46 {
     47 	struct ipt_set_info_target *info =
     48 	    (struct ipt_set_info_target *) target->data;
     49 
     50 	memset(info, 0, sizeof(struct ipt_set_info_target));
     51 	info->add_set.index =
     52 	info->del_set.index = IP_SET_INVALID_ID;
     53 
     54 }
     55 
     56 static void
     57 parse_target(char **argv, int invert, unsigned int *flags,
     58              struct ipt_set_info *info, const char *what)
     59 {
     60 	if (info->flags[0])
     61 		exit_error(PARAMETER_PROBLEM,
     62 			   "--%s can be specified only once", what);
     63 
     64 	if (check_inverse(optarg, &invert, NULL, 0))
     65 		exit_error(PARAMETER_PROBLEM,
     66 			   "Unexpected `!' after --%s", what);
     67 
     68 	if (!argv[optind]
     69 	    || argv[optind][0] == '-' || argv[optind][0] == '!')
     70 		exit_error(PARAMETER_PROBLEM,
     71 			   "--%s requires two args.", what);
     72 
     73 	if (strlen(argv[optind-1]) > IP_SET_MAXNAMELEN - 1)
     74 		exit_error(PARAMETER_PROBLEM,
     75 			   "setname `%s' too long, max %d characters.",
     76 			   argv[optind-1], IP_SET_MAXNAMELEN - 1);
     77 
     78 	get_set_byname(argv[optind - 1], info);
     79 	parse_bindings(argv[optind], info);
     80 	optind++;
     81 
     82 	*flags = 1;
     83 }
     84 
     85 /* Function which parses command options; returns true if it
     86    ate an option */
     87 static int
     88 parse(int c, char **argv, int invert, unsigned int *flags,
     89       const struct ipt_entry *entry, struct ipt_entry_target **target)
     90 {
     91 	struct ipt_set_info_target *myinfo =
     92 	    (struct ipt_set_info_target *) (*target)->data;
     93 
     94 	switch (c) {
     95 	case '1':		/* --add-set <set> <flags> */
     96 		parse_target(argv, invert, flags,
     97 			     &myinfo->add_set, "add-set");
     98 		break;
     99 	case '2':		/* --del-set <set>[:<flags>] <flags> */
    100 		parse_target(argv, invert, flags,
    101 			     &myinfo->del_set, "del-set");
    102 		break;
    103 
    104 	default:
    105 		return 0;
    106 	}
    107 	return 1;
    108 }
    109 
    110 /* Final check; must specify at least one. */
    111 static void final_check(unsigned int flags)
    112 {
    113 	if (!flags)
    114 		exit_error(PARAMETER_PROBLEM,
    115 			   "You must specify either `--add-set' or `--del-set'");
    116 }
    117 
    118 static void
    119 print_target(const char *prefix, const struct ipt_set_info *info)
    120 {
    121 	int i;
    122 	char setname[IP_SET_MAXNAMELEN];
    123 
    124 	if (info->index == IP_SET_INVALID_ID)
    125 		return;
    126 	get_set_byid(setname, info->index);
    127 	printf("%s %s", prefix, setname);
    128 	for (i = 0; i < IP_SET_MAX_BINDINGS; i++) {
    129 		if (!info->flags[i])
    130 			break;
    131 		printf("%s%s",
    132 		       i == 0 ? " " : ",",
    133 		       info->flags[i] & IPSET_SRC ? "src" : "dst");
    134 	}
    135 	printf(" ");
    136 }
    137 
    138 /* Prints out the targinfo. */
    139 static void
    140 print(const struct ipt_ip *ip,
    141       const struct ipt_entry_target *target, int numeric)
    142 {
    143 	struct ipt_set_info_target *info =
    144 	    (struct ipt_set_info_target *) target->data;
    145 
    146 	print_target("add-set", &info->add_set);
    147 	print_target("del-set", &info->del_set);
    148 }
    149 
    150 /* Saves the union ipt_targinfo in parsable form to stdout. */
    151 static void
    152 save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
    153 {
    154 	struct ipt_set_info_target *info =
    155 	    (struct ipt_set_info_target *) target->data;
    156 
    157 	print_target("--add-set", &info->add_set);
    158 	print_target("--del-set", &info->del_set);
    159 }
    160 
    161 static
    162 struct iptables_target ipt_set_target
    163 = {
    164 	.name		= "SET",
    165 	.version	= IPTABLES_VERSION,
    166 	.size		= IPT_ALIGN(sizeof(struct ipt_set_info_target)),
    167 	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_set_info_target)),
    168 	.help		= &help,
    169 	.init		= &init,
    170 	.parse		= &parse,
    171 	.final_check	= &final_check,
    172 	.print		= &print,
    173 	.save		= &save,
    174 	.extra_opts	= opts
    175 };
    176 
    177 void ipt_SET_init(void)
    178 {
    179 	register_target(&ipt_set_target);
    180 }
    181