• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_2ecn.h>
18 
help(void)19 static 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 
29 static 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 
36 static int
parse(int c,char ** argv,int invert,unsigned int * flags,const struct ipt_entry * entry,unsigned int * nfcache,struct ipt_entry_match ** match)37 parse(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 
90 static void
final_check(unsigned int flags)91 final_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. */
99 static void
print(const struct ipt_ip * ip,const struct ipt_entry_match * match,int numeric)100 print(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. */
129 static void
save(const struct ipt_ip * ip,const struct ipt_entry_match * match)130 save(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 
154 static
155 struct 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 
ipt_2ecn_init(void)168 void ipt_2ecn_init(void)
169 {
170 	register_match(&ecn);
171 }
172