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 <xtables.h>
      8 #include <linux/netfilter_ipv4/ipt_REJECT.h>
      9 #include <linux/version.h>
     10 
     11 /* If we are compiling against a kernel that does not support
     12  * IPT_ICMP_ADMIN_PROHIBITED, we are emulating it.
     13  * The result will be a plain DROP of the packet instead of
     14  * reject. -- Maciej Soltysiak <solt (at) dns.toxicfilms.tv>
     15  */
     16 #ifndef IPT_ICMP_ADMIN_PROHIBITED
     17 #define IPT_ICMP_ADMIN_PROHIBITED	IPT_TCP_RESET + 1
     18 #endif
     19 
     20 struct reject_names {
     21 	const char *name;
     22 	const char *alias;
     23 	enum ipt_reject_with with;
     24 	const char *desc;
     25 };
     26 
     27 struct reject_names_xlate {
     28 	const char *name;
     29 	enum ipt_reject_with with;
     30 };
     31 
     32 enum {
     33 	O_REJECT_WITH = 0,
     34 };
     35 
     36 static const struct reject_names reject_table[] = {
     37 	{"icmp-net-unreachable", "net-unreach",
     38 		IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"},
     39 	{"icmp-host-unreachable", "host-unreach",
     40 		IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"},
     41 	{"icmp-proto-unreachable", "proto-unreach",
     42 		IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"},
     43 	{"icmp-port-unreachable", "port-unreach",
     44 		IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"},
     45 #if 0
     46 	{"echo-reply", "echoreply",
     47 	 IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"},
     48 #endif
     49 	{"icmp-net-prohibited", "net-prohib",
     50 	 IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"},
     51 	{"icmp-host-prohibited", "host-prohib",
     52 	 IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"},
     53 	{"tcp-reset", "tcp-rst",
     54 	 IPT_TCP_RESET, "TCP RST packet"},
     55 	{"icmp-admin-prohibited", "admin-prohib",
     56 	 IPT_ICMP_ADMIN_PROHIBITED, "ICMP administratively prohibited (*)"}
     57 };
     58 
     59 static void
     60 print_reject_types(void)
     61 {
     62 	unsigned int i;
     63 
     64 	printf("Valid reject types:\n");
     65 
     66 	for (i = 0; i < ARRAY_SIZE(reject_table); ++i) {
     67 		printf("    %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
     68 		printf("    %-25s\talias\n", reject_table[i].alias);
     69 	}
     70 	printf("\n");
     71 }
     72 
     73 static void REJECT_help(void)
     74 {
     75 	printf(
     76 "REJECT target options:\n"
     77 "--reject-with type              drop input packet and send back\n"
     78 "                                a reply packet according to type:\n");
     79 
     80 	print_reject_types();
     81 
     82 	printf("(*) See man page or read the INCOMPATIBILITES file for compatibility issues.\n");
     83 }
     84 
     85 static const struct xt_option_entry REJECT_opts[] = {
     86 	{.name = "reject-with", .id = O_REJECT_WITH, .type = XTTYPE_STRING},
     87 	XTOPT_TABLEEND,
     88 };
     89 
     90 static void REJECT_init(struct xt_entry_target *t)
     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 static void REJECT_parse(struct xt_option_call *cb)
    100 {
    101 	struct ipt_reject_info *reject = cb->data;
    102 	unsigned int i;
    103 
    104 	xtables_option_parse(cb);
    105 	for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
    106 		if (strncasecmp(reject_table[i].name,
    107 		      cb->arg, strlen(cb->arg)) == 0 ||
    108 		    strncasecmp(reject_table[i].alias,
    109 		      cb->arg, strlen(cb->arg)) == 0) {
    110 			reject->with = reject_table[i].with;
    111 			return;
    112 		}
    113 	/* This due to be dropped late in 2.4 pre-release cycle --RR */
    114 	if (strncasecmp("echo-reply", cb->arg, strlen(cb->arg)) == 0 ||
    115 	    strncasecmp("echoreply", cb->arg, strlen(cb->arg)) == 0)
    116 		fprintf(stderr, "--reject-with echo-reply no longer"
    117 			" supported\n");
    118 	xtables_error(PARAMETER_PROBLEM,
    119 		"unknown reject type \"%s\"", cb->arg);
    120 }
    121 
    122 static void REJECT_print(const void *ip, const struct xt_entry_target *target,
    123                          int numeric)
    124 {
    125 	const struct ipt_reject_info *reject
    126 		= (const struct ipt_reject_info *)target->data;
    127 	unsigned int i;
    128 
    129 	for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
    130 		if (reject_table[i].with == reject->with)
    131 			break;
    132 	printf(" reject-with %s", reject_table[i].name);
    133 }
    134 
    135 static void REJECT_save(const void *ip, const struct xt_entry_target *target)
    136 {
    137 	const struct ipt_reject_info *reject =
    138 		(const struct ipt_reject_info *)target->data;
    139 	unsigned int i;
    140 
    141 	for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
    142 		if (reject_table[i].with == reject->with)
    143 			break;
    144 
    145 	printf(" --reject-with %s", reject_table[i].name);
    146 }
    147 
    148 static const struct reject_names_xlate reject_table_xlate[] = {
    149 	{"net-unreachable",	IPT_ICMP_NET_UNREACHABLE},
    150 	{"host-unreachable",	IPT_ICMP_HOST_UNREACHABLE},
    151 	{"prot-unreachable",	IPT_ICMP_PROT_UNREACHABLE},
    152 	{"port-unreachable",	IPT_ICMP_PORT_UNREACHABLE},
    153 #if 0
    154 	{"echo-reply",		IPT_ICMP_ECHOREPLY},
    155 #endif
    156 	{"net-prohibited",	IPT_ICMP_NET_PROHIBITED},
    157 	{"host-prohibited",	IPT_ICMP_HOST_PROHIBITED},
    158 	{"tcp reset",		IPT_TCP_RESET},
    159 	{"admin-prohibited",	IPT_ICMP_ADMIN_PROHIBITED}
    160 };
    161 
    162 static int REJECT_xlate(struct xt_xlate *xl,
    163 			const struct xt_xlate_tg_params *params)
    164 {
    165 	const struct ipt_reject_info *reject =
    166 		(const struct ipt_reject_info *)params->target->data;
    167 	unsigned int i;
    168 
    169 	for (i = 0; i < ARRAY_SIZE(reject_table_xlate); ++i) {
    170 		if (reject_table_xlate[i].with == reject->with)
    171 			break;
    172 	}
    173 
    174 	if (reject->with == IPT_ICMP_PORT_UNREACHABLE)
    175 		xt_xlate_add(xl, "reject");
    176 	else if (reject->with == IPT_TCP_RESET)
    177 		xt_xlate_add(xl, "reject with %s",
    178 			   reject_table_xlate[i].name);
    179 	else
    180 		xt_xlate_add(xl, "reject with icmp type %s",
    181 			   reject_table_xlate[i].name);
    182 
    183 	return 1;
    184 }
    185 
    186 
    187 static struct xtables_target reject_tg_reg = {
    188 	.name		= "REJECT",
    189 	.version	= XTABLES_VERSION,
    190 	.family		= NFPROTO_IPV4,
    191 	.size		= XT_ALIGN(sizeof(struct ipt_reject_info)),
    192 	.userspacesize	= XT_ALIGN(sizeof(struct ipt_reject_info)),
    193 	.help		= REJECT_help,
    194 	.init		= REJECT_init,
    195 	.print		= REJECT_print,
    196 	.save		= REJECT_save,
    197 	.x6_parse	= REJECT_parse,
    198 	.x6_options	= REJECT_opts,
    199 	.xlate		= REJECT_xlate,
    200 };
    201 
    202 void _init(void)
    203 {
    204 	xtables_register_target(&reject_tg_reg);
    205 }
    206