1/* Shared library add-on to iptables for ECN matching
2 *
3 * (C) 2002 by Harald Welte <laforge@gnumonks.org>
4 *
5 * This program is distributed under the terms of GNU GPL v2, 1991
6 *
7 * libipt_ecn.c borrowed heavily from libipt_dscp.c
8 *
9 */
10#include <stdio.h>
11#include <string.h>
12#include <stdlib.h>
13#include <getopt.h>
14
15#include <iptables.h>
16#include <linux/netfilter_ipv4/ip_tables.h>
17#include <linux/netfilter_ipv4/ipt_ecn.h>
18
19static void help(void)
20{
21	printf(
22"ECN match v%s options\n"
23"[!] --ecn-tcp-cwr 		Match CWR bit of TCP header\n"
24"[!] --ecn-tcp-ece		Match ECE bit of TCP header\n"
25"[!] --ecn-ip-ect [0..3]	Match ECN codepoint in IPv4 header\n",
26	IPTABLES_VERSION);
27}
28
29static struct option opts[] = {
30	{ .name = "ecn-tcp-cwr", .has_arg = 0, .flag = 0, .val = 'F' },
31	{ .name = "ecn-tcp-ece", .has_arg = 0, .flag = 0, .val = 'G' },
32	{ .name = "ecn-ip-ect",  .has_arg = 1, .flag = 0, .val = 'H' },
33	{ .name = 0 }
34};
35
36static int
37parse(int c, char **argv, int invert, unsigned int *flags,
38      const struct ipt_entry *entry,
39      unsigned int *nfcache,
40      struct ipt_entry_match **match)
41{
42	unsigned int result;
43	struct ipt_ecn_info *einfo
44		= (struct ipt_ecn_info *)(*match)->data;
45
46	switch (c) {
47	case 'F':
48		if (*flags & IPT_ECN_OP_MATCH_CWR)
49			exit_error(PARAMETER_PROBLEM,
50			           "ECN match: can only use parameter ONCE!");
51		check_inverse(optarg, &invert, &optind, 0);
52		einfo->operation |= IPT_ECN_OP_MATCH_CWR;
53		if (invert)
54			einfo->invert |= IPT_ECN_OP_MATCH_CWR;
55		*flags |= IPT_ECN_OP_MATCH_CWR;
56		break;
57
58	case 'G':
59		if (*flags & IPT_ECN_OP_MATCH_ECE)
60			exit_error(PARAMETER_PROBLEM,
61				   "ECN match: can only use parameter ONCE!");
62		check_inverse(optarg, &invert, &optind, 0);
63		einfo->operation |= IPT_ECN_OP_MATCH_ECE;
64		if (invert)
65			einfo->invert |= IPT_ECN_OP_MATCH_ECE;
66		*flags |= IPT_ECN_OP_MATCH_ECE;
67		break;
68
69	case 'H':
70		if (*flags & IPT_ECN_OP_MATCH_IP)
71			exit_error(PARAMETER_PROBLEM,
72				   "ECN match: can only use parameter ONCE!");
73		check_inverse(optarg, &invert, &optind, 0);
74		if (invert)
75			einfo->invert |= IPT_ECN_OP_MATCH_IP;
76		*flags |= IPT_ECN_OP_MATCH_IP;
77		einfo->operation |= IPT_ECN_OP_MATCH_IP;
78		if (string_to_number(optarg, 0, 3, &result))
79			exit_error(PARAMETER_PROBLEM,
80				   "ECN match: Value out of range");
81		einfo->ip_ect = result;
82		break;
83	default:
84		return 0;
85	}
86
87	return 1;
88}
89
90static void
91final_check(unsigned int flags)
92{
93	if (!flags)
94		exit_error(PARAMETER_PROBLEM,
95		           "ECN match: some option required");
96}
97
98/* Prints out the matchinfo. */
99static void
100print(const struct ipt_ip *ip,
101      const struct ipt_entry_match *match,
102      int numeric)
103{
104	const struct ipt_ecn_info *einfo =
105		(const struct ipt_ecn_info *)match->data;
106
107	printf("ECN match ");
108
109	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
110		if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
111			fputc('!', stdout);
112		printf("ECE ");
113	}
114
115	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
116		if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
117			fputc('!', stdout);
118		printf("CWR ");
119	}
120
121	if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
122		if (einfo->invert & IPT_ECN_OP_MATCH_IP)
123			fputc('!', stdout);
124		printf("ECT=%d ", einfo->ip_ect);
125	}
126}
127
128/* Saves the union ipt_matchinfo in parsable form to stdout. */
129static void
130save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
131{
132	const struct ipt_ecn_info *einfo =
133		(const struct ipt_ecn_info *)match->data;
134
135	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
136		if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
137			printf("! ");
138		printf("--ecn-tcp-ece ");
139	}
140
141	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
142		if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
143			printf("! ");
144		printf("--ecn-tcp-cwr ");
145	}
146
147	if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
148		if (einfo->invert & IPT_ECN_OP_MATCH_IP)
149			printf("! ");
150		printf("--ecn-ip-ect %d", einfo->ip_ect);
151	}
152}
153
154static
155struct iptables_match ecn
156= { .name          = "ecn",
157    .version       = IPTABLES_VERSION,
158    .size          = IPT_ALIGN(sizeof(struct ipt_ecn_info)),
159    .userspacesize = IPT_ALIGN(sizeof(struct ipt_ecn_info)),
160    .help          = &help,
161    .parse         = &parse,
162    .final_check   = &final_check,
163    .print         = &print,
164    .save          = &save,
165    .extra_opts    = opts
166};
167
168void _init(void)
169{
170	register_match(&ecn);
171}
172