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 <iptables.h>
10#include <linux/netfilter_ipv4/ip_tables.h>
11#include <linux/netfilter_ipv4/ipt_REJECT.h>
12
13struct reject_names {
14	const char *name;
15	const char *alias;
16	enum ipt_reject_with with;
17	const char *desc;
18};
19
20static const struct reject_names reject_table[] = {
21	{"icmp-net-unreachable", "net-unreach",
22		IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"},
23	{"icmp-host-unreachable", "host-unreach",
24		IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"},
25	{"icmp-proto-unreachable", "proto-unreach",
26		IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"},
27	{"icmp-port-unreachable", "port-unreach",
28		IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"},
29	{"icmp-net-prohibited", "net-prohib",
30	 IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"},
31	{"icmp-host-prohibited", "host-prohib",
32	 IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"},
33	{"tcp-reset", "tcp-reset",
34	 IPT_TCP_RESET, "TCP RST packet"}
35};
36
37static void
38print_reject_types()
39{
40	unsigned int i;
41
42	printf("Valid reject types:\n");
43
44	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
45		printf("    %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
46		printf("    %-25s\talias\n", reject_table[i].alias);
47	}
48	printf("\n");
49}
50
51/* Saves the union ipt_targinfo in parsable form to stdout. */
52
53/* Function which prints out usage message. */
54static void
55help(void)
56{
57	printf(
58"REJECT options:\n"
59"--reject-with type              drop input packet and send back\n"
60"                                a reply packet according to type:\n");
61
62	print_reject_types();
63}
64
65static struct option opts[] = {
66	{ "reject-with", 1, 0, '1' },
67	{ 0 }
68};
69
70/* Allocate and initialize the target. */
71static void
72init(struct ipt_entry_target *t, unsigned int *nfcache)
73{
74	struct ipt_reject_info *reject = (struct ipt_reject_info *)t->data;
75
76	/* default */
77	reject->with = IPT_ICMP_PORT_UNREACHABLE;
78
79	/* Can't cache this */
80	*nfcache |= NFC_UNKNOWN;
81}
82
83/* Function which parses command options; returns true if it
84   ate an option */
85static int
86parse(int c, char **argv, int invert, unsigned int *flags,
87      const struct ipt_entry *entry,
88      struct ipt_entry_target **target)
89{
90	struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data;
91	unsigned int limit = sizeof(reject_table)/sizeof(struct reject_names);
92	unsigned int i;
93
94	switch(c) {
95	case '1':
96		if (check_inverse(optarg, &invert, NULL, 0))
97			exit_error(PARAMETER_PROBLEM,
98				   "Unexpected `!' after --reject-with");
99		for (i = 0; i < limit; i++) {
100			if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0)
101			    || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) {
102				reject->with = reject_table[i].with;
103				return 1;
104			}
105		}
106		/* This due to be dropped late in 2.4 pre-release cycle --RR */
107		if (strncasecmp("echo-reply", optarg, strlen(optarg)) == 0
108		    || strncasecmp("echoreply", optarg, strlen(optarg)) == 0)
109			fprintf(stderr, "--reject-with echo-reply no longer"
110				" supported\n");
111		exit_error(PARAMETER_PROBLEM, "unknown reject type `%s'",optarg);
112	default:
113		/* Fall through */
114		break;
115	}
116	return 0;
117}
118
119/* Final check; nothing. */
120static void final_check(unsigned int flags)
121{
122}
123
124/* Prints out ipt_reject_info. */
125static void
126print(const struct ipt_ip *ip,
127      const struct ipt_entry_target *target,
128      int numeric)
129{
130	const struct ipt_reject_info *reject
131		= (const struct ipt_reject_info *)target->data;
132	unsigned int i;
133
134	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
135		if (reject_table[i].with == reject->with)
136			break;
137	}
138	printf("reject-with %s ", reject_table[i].name);
139}
140
141/* Saves ipt_reject in parsable form to stdout. */
142static void save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
143{
144	const struct ipt_reject_info *reject
145		= (const struct ipt_reject_info *)target->data;
146	unsigned int i;
147
148	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++)
149		if (reject_table[i].with == reject->with)
150			break;
151
152	printf("--reject-with %s ", reject_table[i].name);
153}
154
155static
156struct iptables_target reject
157= { NULL,
158    "REJECT",
159    IPTABLES_VERSION,
160    IPT_ALIGN(sizeof(struct ipt_reject_info)),
161    IPT_ALIGN(sizeof(struct ipt_reject_info)),
162    &help,
163    &init,
164    &parse,
165    &final_check,
166    &print,
167    &save,
168    opts
169};
170
171void _init(void)
172{
173	register_target(&reject);
174}
175