Home | History | Annotate | Download | only in extensions
      1 /* Shared library add-on to iptables to add customized REJECT support.
      2  *
      3  * (C) 2000 Jozsef Kadlecsik <kadlec (at) blackhole.kfki.hu>
      4  */
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <stdlib.h>
      8 #include <getopt.h>
      9 #include <iptables.h>
     10 #include <linux/netfilter_ipv4/ip_tables.h>
     11 #include <linux/netfilter_ipv4/ipt_REJECT.h>
     12 #include <linux/version.h>
     13 
     14 /* If we are compiling against a kernel that does not support
     15  * IPT_ICMP_ADMIN_PROHIBITED, we are emulating it.
     16  * The result will be a plain DROP of the packet instead of
     17  * reject. -- Maciej Soltysiak <solt (at) dns.toxicfilms.tv>
     18  */
     19 #ifndef IPT_ICMP_ADMIN_PROHIBITED
     20 #define IPT_ICMP_ADMIN_PROHIBITED	IPT_TCP_RESET + 1
     21 #endif
     22 
     23 struct reject_names {
     24 	const char *name;
     25 	const char *alias;
     26 	enum ipt_reject_with with;
     27 	const char *desc;
     28 };
     29 
     30 static const struct reject_names reject_table[] = {
     31 	{"icmp-net-unreachable", "net-unreach",
     32 		IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"},
     33 	{"icmp-host-unreachable", "host-unreach",
     34 		IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"},
     35 	{"icmp-proto-unreachable", "proto-unreach",
     36 		IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"},
     37 	{"icmp-port-unreachable", "port-unreach",
     38 		IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"},
     39 #if 0
     40 	{"echo-reply", "echoreply",
     41 	 IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"},
     42 #endif
     43 	{"icmp-net-prohibited", "net-prohib",
     44 	 IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"},
     45 	{"icmp-host-prohibited", "host-prohib",
     46 	 IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"},
     47 	{"tcp-reset", "tcp-rst",
     48 	 IPT_TCP_RESET, "TCP RST packet"},
     49 	{"icmp-admin-prohibited", "admin-prohib",
     50 	 IPT_ICMP_ADMIN_PROHIBITED, "ICMP administratively prohibited (*)"}
     51 };
     52 
     53 static void
     54 print_reject_types()
     55 {
     56 	unsigned int i;
     57 
     58 	printf("Valid reject types:\n");
     59 
     60 	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
     61 		printf("    %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
     62 		printf("    %-25s\talias\n", reject_table[i].alias);
     63 	}
     64 	printf("\n");
     65 }
     66 
     67 /* Saves the union ipt_targinfo in parsable form to stdout. */
     68 
     69 /* Function which prints out usage message. */
     70 static void
     71 help(void)
     72 {
     73 	printf(
     74 "REJECT options:\n"
     75 "--reject-with type              drop input packet and send back\n"
     76 "                                a reply packet according to type:\n");
     77 
     78 	print_reject_types();
     79 
     80 	printf("(*) See man page or read the INCOMPATIBILITES file for compatibility issues.\n");
     81 }
     82 
     83 static struct option opts[] = {
     84 	{ "reject-with", 1, 0, '1' },
     85 	{ 0 }
     86 };
     87 
     88 /* Allocate and initialize the target. */
     89 static void
     90 init(struct ipt_entry_target *t, unsigned int *nfcache)
     91 {
     92 	struct ipt_reject_info *reject = (struct ipt_reject_info *)t->data;
     93 
     94 	/* default */
     95 	reject->with = IPT_ICMP_PORT_UNREACHABLE;
     96 
     97 }
     98 
     99 /* Function which parses command options; returns true if it
    100    ate an option */
    101 static int
    102 parse(int c, char **argv, int invert, unsigned int *flags,
    103       const struct ipt_entry *entry,
    104       struct ipt_entry_target **target)
    105 {
    106 	struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data;
    107 	unsigned int limit = sizeof(reject_table)/sizeof(struct reject_names);
    108 	unsigned int i;
    109 
    110 	switch(c) {
    111 	case '1':
    112 		if (check_inverse(optarg, &invert, NULL, 0))
    113 			exit_error(PARAMETER_PROBLEM,
    114 				   "Unexpected `!' after --reject-with");
    115 		for (i = 0; i < limit; i++) {
    116 			if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0)
    117 			    || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) {
    118 				reject->with = reject_table[i].with;
    119 				return 1;
    120 			}
    121 		}
    122 		/* This due to be dropped late in 2.4 pre-release cycle --RR */
    123 		if (strncasecmp("echo-reply", optarg, strlen(optarg)) == 0
    124 		    || strncasecmp("echoreply", optarg, strlen(optarg)) == 0)
    125 			fprintf(stderr, "--reject-with echo-reply no longer"
    126 				" supported\n");
    127 		exit_error(PARAMETER_PROBLEM, "unknown reject type `%s'",optarg);
    128 	default:
    129 		/* Fall through */
    130 		break;
    131 	}
    132 	return 0;
    133 }
    134 
    135 /* Final check; nothing. */
    136 static void final_check(unsigned int flags)
    137 {
    138 }
    139 
    140 /* Prints out ipt_reject_info. */
    141 static void
    142 print(const struct ipt_ip *ip,
    143       const struct ipt_entry_target *target,
    144       int numeric)
    145 {
    146 	const struct ipt_reject_info *reject
    147 		= (const struct ipt_reject_info *)target->data;
    148 	unsigned int i;
    149 
    150 	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
    151 		if (reject_table[i].with == reject->with)
    152 			break;
    153 	}
    154 	printf("reject-with %s ", reject_table[i].name);
    155 }
    156 
    157 /* Saves ipt_reject in parsable form to stdout. */
    158 static void save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
    159 {
    160 	const struct ipt_reject_info *reject
    161 		= (const struct ipt_reject_info *)target->data;
    162 	unsigned int i;
    163 
    164 	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++)
    165 		if (reject_table[i].with == reject->with)
    166 			break;
    167 
    168 	printf("--reject-with %s ", reject_table[i].name);
    169 }
    170 
    171 static struct iptables_target reject = {
    172 	.next		= NULL,
    173 	.name		= "REJECT",
    174 	.version	= IPTABLES_VERSION,
    175 	.size		= IPT_ALIGN(sizeof(struct ipt_reject_info)),
    176 	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_reject_info)),
    177 	.help		= &help,
    178 	.init		= &init,
    179 	.parse		= &parse,
    180 	.final_check	= &final_check,
    181 	.print		= &print,
    182 	.save		= &save,
    183 	.extra_opts	= opts
    184 };
    185 
    186 void ipt_REJECT_init(void)
    187 {
    188 	register_target(&reject);
    189 }
    190