libipt_REJECT.c revision d09b6d591ca7d7d7575cb6aa20384c9830f777ab
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* Shared library add-on to iptables to add customized REJECT support.
2926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (C) 2000 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <stdbool.h>
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <stdio.h>
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <string.h>
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <stdlib.h>
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <getopt.h>
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <xtables.h>
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <linux/netfilter_ipv4/ipt_REJECT.h>
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <linux/version.h>
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* If we are compiling against a kernel that does not support
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * IPT_ICMP_ADMIN_PROHIBITED, we are emulating it.
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * The result will be a plain DROP of the packet instead of
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * reject. -- Maciej Soltysiak <solt@dns.toxicfilms.tv>
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifndef IPT_ICMP_ADMIN_PROHIBITED
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define IPT_ICMP_ADMIN_PROHIBITED	IPT_TCP_RESET + 1
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
23926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)struct reject_names {
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	const char *name;
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	const char *alias;
2619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)	enum ipt_reject_with with;
2719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)	const char *desc;
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
29c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
3051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)static const struct reject_names reject_table[] = {
31e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch	{"icmp-net-unreachable", "net-unreach",
32e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch		IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"},
33e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch	{"icmp-host-unreachable", "host-unreach",
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"},
35c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	{"icmp-proto-unreachable", "proto-unreach",
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"},
37c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	{"icmp-port-unreachable", "port-unreach",
387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci		IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"},
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if 0
40f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu	{"echo-reply", "echoreply",
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"},
42f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#endif
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	{"icmp-net-prohibited", "net-prohib",
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"},
45926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	{"icmp-host-prohibited", "host-prohib",
46926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	 IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"},
4719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)	{"tcp-reset", "tcp-rst",
4819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)	 IPT_TCP_RESET, "TCP RST packet"},
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	{"icmp-admin-prohibited", "admin-prohib",
50f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu	 IPT_ICMP_ADMIN_PROHIBITED, "ICMP administratively prohibited (*)"}
5119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)};
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
53f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liustatic void
54f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liuprint_reject_types(void)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)	unsigned int i;
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
58f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu	printf("Valid reject types:\n");
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	for (i = 0; i < ARRAY_SIZE(reject_table); ++i) {
61c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)		printf("    %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		printf("    %-25s\talias\n", reject_table[i].alias);
637242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci	}
64	printf("\n");
65}
66
67static void REJECT_help(void)
68{
69	printf(
70"REJECT target options:\n"
71"--reject-with type              drop input packet and send back\n"
72"                                a reply packet according to type:\n");
73
74	print_reject_types();
75
76	printf("(*) See man page or read the INCOMPATIBILITES file for compatibility issues.\n");
77}
78
79static const struct option REJECT_opts[] = {
80	{.name = "reject-with", .has_arg = true, .val = '1'},
81	XT_GETOPT_TABLEEND,
82};
83
84static void REJECT_init(struct xt_entry_target *t)
85{
86	struct ipt_reject_info *reject = (struct ipt_reject_info *)t->data;
87
88	/* default */
89	reject->with = IPT_ICMP_PORT_UNREACHABLE;
90
91}
92
93static int REJECT_parse(int c, char **argv, int invert, unsigned int *flags,
94                        const void *entry, struct xt_entry_target **target)
95{
96	struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data;
97	static const unsigned int limit = ARRAY_SIZE(reject_table);
98	unsigned int i;
99
100	switch(c) {
101	case '1':
102		if (xtables_check_inverse(optarg, &invert, NULL, 0, argv))
103			xtables_error(PARAMETER_PROBLEM,
104				   "Unexpected `!' after --reject-with");
105		for (i = 0; i < limit; i++) {
106			if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0)
107			    || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) {
108				reject->with = reject_table[i].with;
109				return 1;
110			}
111		}
112		/* This due to be dropped late in 2.4 pre-release cycle --RR */
113		if (strncasecmp("echo-reply", optarg, strlen(optarg)) == 0
114		    || strncasecmp("echoreply", optarg, strlen(optarg)) == 0)
115			fprintf(stderr, "--reject-with echo-reply no longer"
116				" supported\n");
117		xtables_error(PARAMETER_PROBLEM, "unknown reject type \"%s\"", optarg);
118		break;
119	}
120	return 0;
121}
122
123static void REJECT_print(const void *ip, const struct xt_entry_target *target,
124                         int numeric)
125{
126	const struct ipt_reject_info *reject
127		= (const struct ipt_reject_info *)target->data;
128	unsigned int i;
129
130	for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
131		if (reject_table[i].with == reject->with)
132			break;
133	printf("reject-with %s ", reject_table[i].name);
134}
135
136static void REJECT_save(const void *ip, const struct xt_entry_target *target)
137{
138	const struct ipt_reject_info *reject
139		= (const struct ipt_reject_info *)target->data;
140	unsigned int i;
141
142	for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
143		if (reject_table[i].with == reject->with)
144			break;
145
146	printf("--reject-with %s ", reject_table[i].name);
147}
148
149static struct xtables_target reject_tg_reg = {
150	.name		= "REJECT",
151	.version	= XTABLES_VERSION,
152	.family		= NFPROTO_IPV4,
153	.size		= XT_ALIGN(sizeof(struct ipt_reject_info)),
154	.userspacesize	= XT_ALIGN(sizeof(struct ipt_reject_info)),
155	.help		= REJECT_help,
156	.init		= REJECT_init,
157	.parse		= REJECT_parse,
158	.print		= REJECT_print,
159	.save		= REJECT_save,
160	.extra_opts	= REJECT_opts,
161};
162
163void _init(void)
164{
165	xtables_register_target(&reject_tg_reg);
166}
167