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