blob: c2276e96787e834e774662c1b2cab2febffcb840 [file] [log] [blame]
Harald Welte7a447312002-05-29 15:11:49 +00001/* 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
Jan Engelhardt5d9678a2008-11-20 10:15:35 +010015#include <xtables.h>
Harald Welte7a447312002-05-29 15:11:49 +000016#include <linux/netfilter_ipv4/ip_tables.h>
17#include <linux/netfilter_ipv4/ipt_ecn.h>
18
Jan Engelhardt59d16402007-10-04 16:28:39 +000019static void ecn_help(void)
Harald Welte7a447312002-05-29 15:11:49 +000020{
21 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020022"ECN match options\n"
Harald Welte7a447312002-05-29 15:11:49 +000023"[!] --ecn-tcp-cwr Match CWR bit of TCP header\n"
24"[!] --ecn-tcp-ece Match ECE bit of TCP header\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020025"[!] --ecn-ip-ect [0..3] Match ECN codepoint in IPv4 header\n");
Harald Welte7a447312002-05-29 15:11:49 +000026}
27
Jan Engelhardt59d16402007-10-04 16:28:39 +000028static const struct option ecn_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000029 { .name = "ecn-tcp-cwr", .has_arg = 0, .val = 'F' },
30 { .name = "ecn-tcp-ece", .has_arg = 0, .val = 'G' },
31 { .name = "ecn-ip-ect", .has_arg = 1, .val = 'H' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000032 { .name = NULL }
Harald Welte7a447312002-05-29 15:11:49 +000033};
34
Jan Engelhardt59d16402007-10-04 16:28:39 +000035static int ecn_parse(int c, char **argv, int invert, unsigned int *flags,
36 const void *entry, struct xt_entry_match **match)
Harald Welte7a447312002-05-29 15:11:49 +000037{
38 unsigned int result;
39 struct ipt_ecn_info *einfo
40 = (struct ipt_ecn_info *)(*match)->data;
41
42 switch (c) {
43 case 'F':
44 if (*flags & IPT_ECN_OP_MATCH_CWR)
45 exit_error(PARAMETER_PROBLEM,
46 "ECN match: can only use parameter ONCE!");
47 check_inverse(optarg, &invert, &optind, 0);
48 einfo->operation |= IPT_ECN_OP_MATCH_CWR;
49 if (invert)
50 einfo->invert |= IPT_ECN_OP_MATCH_CWR;
51 *flags |= IPT_ECN_OP_MATCH_CWR;
52 break;
53
54 case 'G':
55 if (*flags & IPT_ECN_OP_MATCH_ECE)
56 exit_error(PARAMETER_PROBLEM,
57 "ECN match: can only use parameter ONCE!");
58 check_inverse(optarg, &invert, &optind, 0);
59 einfo->operation |= IPT_ECN_OP_MATCH_ECE;
60 if (invert)
61 einfo->invert |= IPT_ECN_OP_MATCH_ECE;
62 *flags |= IPT_ECN_OP_MATCH_ECE;
63 break;
64
65 case 'H':
66 if (*flags & IPT_ECN_OP_MATCH_IP)
67 exit_error(PARAMETER_PROBLEM,
68 "ECN match: can only use parameter ONCE!");
69 check_inverse(optarg, &invert, &optind, 0);
70 if (invert)
71 einfo->invert |= IPT_ECN_OP_MATCH_IP;
72 *flags |= IPT_ECN_OP_MATCH_IP;
73 einfo->operation |= IPT_ECN_OP_MATCH_IP;
Jan Engelhardt5f2922c2009-01-27 18:43:01 +010074 if (!xtables_strtoui(optarg, NULL, &result, 0, 3))
Harald Welte7a447312002-05-29 15:11:49 +000075 exit_error(PARAMETER_PROBLEM,
76 "ECN match: Value out of range");
Harald Welte0e9ed732002-08-05 19:35:52 +000077 einfo->ip_ect = result;
Harald Welte7a447312002-05-29 15:11:49 +000078 break;
79 default:
80 return 0;
81 }
82
83 return 1;
84}
85
Jan Engelhardt59d16402007-10-04 16:28:39 +000086static void ecn_check(unsigned int flags)
Harald Welte7a447312002-05-29 15:11:49 +000087{
88 if (!flags)
89 exit_error(PARAMETER_PROBLEM,
90 "ECN match: some option required");
91}
92
Jan Engelhardt59d16402007-10-04 16:28:39 +000093static void ecn_print(const void *ip, const struct xt_entry_match *match,
94 int numeric)
Harald Welte7a447312002-05-29 15:11:49 +000095{
96 const struct ipt_ecn_info *einfo =
97 (const struct ipt_ecn_info *)match->data;
98
99 printf("ECN match ");
100
101 if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
102 if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
103 fputc('!', stdout);
104 printf("ECE ");
105 }
106
107 if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
108 if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
109 fputc('!', stdout);
110 printf("CWR ");
111 }
112
113 if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
114 if (einfo->invert & IPT_ECN_OP_MATCH_IP)
115 fputc('!', stdout);
116 printf("ECT=%d ", einfo->ip_ect);
117 }
118}
119
Jan Engelhardt59d16402007-10-04 16:28:39 +0000120static void ecn_save(const void *ip, const struct xt_entry_match *match)
Harald Welte7a447312002-05-29 15:11:49 +0000121{
122 const struct ipt_ecn_info *einfo =
123 (const struct ipt_ecn_info *)match->data;
124
125 if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
126 if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
127 printf("! ");
128 printf("--ecn-tcp-ece ");
129 }
130
131 if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
132 if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
133 printf("! ");
134 printf("--ecn-tcp-cwr ");
135 }
136
137 if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
138 if (einfo->invert & IPT_ECN_OP_MATCH_IP)
139 printf("! ");
140 printf("--ecn-ip-ect %d", einfo->ip_ect);
141 }
142}
143
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200144static struct xtables_match ecn_mt_reg = {
Jan Engelhardt59d16402007-10-04 16:28:39 +0000145 .name = "ecn",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200146 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100147 .family = NFPROTO_IPV4,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200148 .size = XT_ALIGN(sizeof(struct ipt_ecn_info)),
149 .userspacesize = XT_ALIGN(sizeof(struct ipt_ecn_info)),
Jan Engelhardt59d16402007-10-04 16:28:39 +0000150 .help = ecn_help,
151 .parse = ecn_parse,
152 .final_check = ecn_check,
153 .print = ecn_print,
154 .save = ecn_save,
155 .extra_opts = ecn_opts,
Harald Welte7a447312002-05-29 15:11:49 +0000156};
157
158void _init(void)
159{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200160 xtables_register_match(&ecn_mt_reg);
Harald Welte7a447312002-05-29 15:11:49 +0000161}