libxt_ecn.c revision 59d164019340d110d302634e429320577f0db7be
17a44731615d950a2966737d1d1c960859023f3a3Harald Welte/* Shared library add-on to iptables for ECN matching
27a44731615d950a2966737d1d1c960859023f3a3Harald Welte *
37a44731615d950a2966737d1d1c960859023f3a3Harald Welte * (C) 2002 by Harald Welte <laforge@gnumonks.org>
47a44731615d950a2966737d1d1c960859023f3a3Harald Welte *
57a44731615d950a2966737d1d1c960859023f3a3Harald Welte * This program is distributed under the terms of GNU GPL v2, 1991
67a44731615d950a2966737d1d1c960859023f3a3Harald Welte *
77a44731615d950a2966737d1d1c960859023f3a3Harald Welte * libipt_ecn.c borrowed heavily from libipt_dscp.c
87a44731615d950a2966737d1d1c960859023f3a3Harald Welte *
97a44731615d950a2966737d1d1c960859023f3a3Harald Welte */
107a44731615d950a2966737d1d1c960859023f3a3Harald Welte#include <stdio.h>
117a44731615d950a2966737d1d1c960859023f3a3Harald Welte#include <string.h>
127a44731615d950a2966737d1d1c960859023f3a3Harald Welte#include <stdlib.h>
137a44731615d950a2966737d1d1c960859023f3a3Harald Welte#include <getopt.h>
147a44731615d950a2966737d1d1c960859023f3a3Harald Welte
157a44731615d950a2966737d1d1c960859023f3a3Harald Welte#include <iptables.h>
167a44731615d950a2966737d1d1c960859023f3a3Harald Welte#include <linux/netfilter_ipv4/ip_tables.h>
177a44731615d950a2966737d1d1c960859023f3a3Harald Welte#include <linux/netfilter_ipv4/ipt_ecn.h>
187a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1959d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void ecn_help(void)
207a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
217a44731615d950a2966737d1d1c960859023f3a3Harald Welte	printf(
227a44731615d950a2966737d1d1c960859023f3a3Harald Welte"ECN match v%s options\n"
237a44731615d950a2966737d1d1c960859023f3a3Harald Welte"[!] --ecn-tcp-cwr 		Match CWR bit of TCP header\n"
247a44731615d950a2966737d1d1c960859023f3a3Harald Welte"[!] --ecn-tcp-ece		Match ECE bit of TCP header\n"
257a44731615d950a2966737d1d1c960859023f3a3Harald Welte"[!] --ecn-ip-ect [0..3]	Match ECN codepoint in IPv4 header\n",
267a44731615d950a2966737d1d1c960859023f3a3Harald Welte	IPTABLES_VERSION);
277a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
287a44731615d950a2966737d1d1c960859023f3a3Harald Welte
2959d164019340d110d302634e429320577f0db7beJan Engelhardtstatic const struct option ecn_opts[] = {
30500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ .name = "ecn-tcp-cwr", .has_arg = 0, .val = 'F' },
31500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ .name = "ecn-tcp-ece", .has_arg = 0, .val = 'G' },
32500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ .name = "ecn-ip-ect",  .has_arg = 1, .val = 'H' },
33500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ }
347a44731615d950a2966737d1d1c960859023f3a3Harald Welte};
357a44731615d950a2966737d1d1c960859023f3a3Harald Welte
3659d164019340d110d302634e429320577f0db7beJan Engelhardtstatic int ecn_parse(int c, char **argv, int invert, unsigned int *flags,
3759d164019340d110d302634e429320577f0db7beJan Engelhardt                     const void *entry, struct xt_entry_match **match)
387a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
397a44731615d950a2966737d1d1c960859023f3a3Harald Welte	unsigned int result;
407a44731615d950a2966737d1d1c960859023f3a3Harald Welte	struct ipt_ecn_info *einfo
417a44731615d950a2966737d1d1c960859023f3a3Harald Welte		= (struct ipt_ecn_info *)(*match)->data;
427a44731615d950a2966737d1d1c960859023f3a3Harald Welte
437a44731615d950a2966737d1d1c960859023f3a3Harald Welte	switch (c) {
447a44731615d950a2966737d1d1c960859023f3a3Harald Welte	case 'F':
457a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (*flags & IPT_ECN_OP_MATCH_CWR)
467a44731615d950a2966737d1d1c960859023f3a3Harald Welte			exit_error(PARAMETER_PROBLEM,
477a44731615d950a2966737d1d1c960859023f3a3Harald Welte			           "ECN match: can only use parameter ONCE!");
487a44731615d950a2966737d1d1c960859023f3a3Harald Welte		check_inverse(optarg, &invert, &optind, 0);
497a44731615d950a2966737d1d1c960859023f3a3Harald Welte		einfo->operation |= IPT_ECN_OP_MATCH_CWR;
507a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (invert)
517a44731615d950a2966737d1d1c960859023f3a3Harald Welte			einfo->invert |= IPT_ECN_OP_MATCH_CWR;
527a44731615d950a2966737d1d1c960859023f3a3Harald Welte		*flags |= IPT_ECN_OP_MATCH_CWR;
537a44731615d950a2966737d1d1c960859023f3a3Harald Welte		break;
547a44731615d950a2966737d1d1c960859023f3a3Harald Welte
557a44731615d950a2966737d1d1c960859023f3a3Harald Welte	case 'G':
567a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (*flags & IPT_ECN_OP_MATCH_ECE)
577a44731615d950a2966737d1d1c960859023f3a3Harald Welte			exit_error(PARAMETER_PROBLEM,
587a44731615d950a2966737d1d1c960859023f3a3Harald Welte				   "ECN match: can only use parameter ONCE!");
597a44731615d950a2966737d1d1c960859023f3a3Harald Welte		check_inverse(optarg, &invert, &optind, 0);
607a44731615d950a2966737d1d1c960859023f3a3Harald Welte		einfo->operation |= IPT_ECN_OP_MATCH_ECE;
617a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (invert)
627a44731615d950a2966737d1d1c960859023f3a3Harald Welte			einfo->invert |= IPT_ECN_OP_MATCH_ECE;
637a44731615d950a2966737d1d1c960859023f3a3Harald Welte		*flags |= IPT_ECN_OP_MATCH_ECE;
647a44731615d950a2966737d1d1c960859023f3a3Harald Welte		break;
657a44731615d950a2966737d1d1c960859023f3a3Harald Welte
667a44731615d950a2966737d1d1c960859023f3a3Harald Welte	case 'H':
677a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (*flags & IPT_ECN_OP_MATCH_IP)
687a44731615d950a2966737d1d1c960859023f3a3Harald Welte			exit_error(PARAMETER_PROBLEM,
697a44731615d950a2966737d1d1c960859023f3a3Harald Welte				   "ECN match: can only use parameter ONCE!");
707a44731615d950a2966737d1d1c960859023f3a3Harald Welte		check_inverse(optarg, &invert, &optind, 0);
717a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (invert)
727a44731615d950a2966737d1d1c960859023f3a3Harald Welte			einfo->invert |= IPT_ECN_OP_MATCH_IP;
737a44731615d950a2966737d1d1c960859023f3a3Harald Welte		*flags |= IPT_ECN_OP_MATCH_IP;
747a44731615d950a2966737d1d1c960859023f3a3Harald Welte		einfo->operation |= IPT_ECN_OP_MATCH_IP;
757a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (string_to_number(optarg, 0, 3, &result))
767a44731615d950a2966737d1d1c960859023f3a3Harald Welte			exit_error(PARAMETER_PROBLEM,
777a44731615d950a2966737d1d1c960859023f3a3Harald Welte				   "ECN match: Value out of range");
780e9ed738e0344ccb75b457dac5291f0849944c61Harald Welte		einfo->ip_ect = result;
797a44731615d950a2966737d1d1c960859023f3a3Harald Welte		break;
807a44731615d950a2966737d1d1c960859023f3a3Harald Welte	default:
817a44731615d950a2966737d1d1c960859023f3a3Harald Welte		return 0;
827a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
837a44731615d950a2966737d1d1c960859023f3a3Harald Welte
847a44731615d950a2966737d1d1c960859023f3a3Harald Welte	return 1;
857a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
867a44731615d950a2966737d1d1c960859023f3a3Harald Welte
8759d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void ecn_check(unsigned int flags)
887a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
897a44731615d950a2966737d1d1c960859023f3a3Harald Welte	if (!flags)
907a44731615d950a2966737d1d1c960859023f3a3Harald Welte		exit_error(PARAMETER_PROBLEM,
917a44731615d950a2966737d1d1c960859023f3a3Harald Welte		           "ECN match: some option required");
927a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
937a44731615d950a2966737d1d1c960859023f3a3Harald Welte
947a44731615d950a2966737d1d1c960859023f3a3Harald Welte/* Prints out the matchinfo. */
9559d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void ecn_print(const void *ip, const struct xt_entry_match *match,
9659d164019340d110d302634e429320577f0db7beJan Engelhardt                      int numeric)
977a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
987a44731615d950a2966737d1d1c960859023f3a3Harald Welte	const struct ipt_ecn_info *einfo =
997a44731615d950a2966737d1d1c960859023f3a3Harald Welte		(const struct ipt_ecn_info *)match->data;
1007a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1017a44731615d950a2966737d1d1c960859023f3a3Harald Welte	printf("ECN match ");
1027a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1037a44731615d950a2966737d1d1c960859023f3a3Harald Welte	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
1047a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
1057a44731615d950a2966737d1d1c960859023f3a3Harald Welte			fputc('!', stdout);
1067a44731615d950a2966737d1d1c960859023f3a3Harald Welte		printf("ECE ");
1077a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1087a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1097a44731615d950a2966737d1d1c960859023f3a3Harald Welte	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
1107a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
1117a44731615d950a2966737d1d1c960859023f3a3Harald Welte			fputc('!', stdout);
1127a44731615d950a2966737d1d1c960859023f3a3Harald Welte		printf("CWR ");
1137a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1147a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1157a44731615d950a2966737d1d1c960859023f3a3Harald Welte	if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
1167a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (einfo->invert & IPT_ECN_OP_MATCH_IP)
1177a44731615d950a2966737d1d1c960859023f3a3Harald Welte			fputc('!', stdout);
1187a44731615d950a2966737d1d1c960859023f3a3Harald Welte		printf("ECT=%d ", einfo->ip_ect);
1197a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1207a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
1217a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1227a44731615d950a2966737d1d1c960859023f3a3Harald Welte/* Saves the union ipt_matchinfo in parsable form to stdout. */
12359d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void ecn_save(const void *ip, const struct xt_entry_match *match)
1247a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
1257a44731615d950a2966737d1d1c960859023f3a3Harald Welte	const struct ipt_ecn_info *einfo =
1267a44731615d950a2966737d1d1c960859023f3a3Harald Welte		(const struct ipt_ecn_info *)match->data;
1277a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1287a44731615d950a2966737d1d1c960859023f3a3Harald Welte	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
1297a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
1307a44731615d950a2966737d1d1c960859023f3a3Harald Welte			printf("! ");
1317a44731615d950a2966737d1d1c960859023f3a3Harald Welte		printf("--ecn-tcp-ece ");
1327a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1337a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1347a44731615d950a2966737d1d1c960859023f3a3Harald Welte	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
1357a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
1367a44731615d950a2966737d1d1c960859023f3a3Harald Welte			printf("! ");
1377a44731615d950a2966737d1d1c960859023f3a3Harald Welte		printf("--ecn-tcp-cwr ");
1387a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1397a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1407a44731615d950a2966737d1d1c960859023f3a3Harald Welte	if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
1417a44731615d950a2966737d1d1c960859023f3a3Harald Welte		if (einfo->invert & IPT_ECN_OP_MATCH_IP)
1427a44731615d950a2966737d1d1c960859023f3a3Harald Welte			printf("! ");
1437a44731615d950a2966737d1d1c960859023f3a3Harald Welte		printf("--ecn-ip-ect %d", einfo->ip_ect);
1447a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1457a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
1467a44731615d950a2966737d1d1c960859023f3a3Harald Welte
14759d164019340d110d302634e429320577f0db7beJan Engelhardtstatic struct iptables_match ecn_match = {
14859d164019340d110d302634e429320577f0db7beJan Engelhardt    .name          = "ecn",
149fb7ed72f53b4d1cf645cc7529a6dc68e2a7ecd26Stephane Ouellette    .version       = IPTABLES_VERSION,
150fb7ed72f53b4d1cf645cc7529a6dc68e2a7ecd26Stephane Ouellette    .size          = IPT_ALIGN(sizeof(struct ipt_ecn_info)),
151fb7ed72f53b4d1cf645cc7529a6dc68e2a7ecd26Stephane Ouellette    .userspacesize = IPT_ALIGN(sizeof(struct ipt_ecn_info)),
15259d164019340d110d302634e429320577f0db7beJan Engelhardt    .help          = ecn_help,
15359d164019340d110d302634e429320577f0db7beJan Engelhardt    .parse         = ecn_parse,
15459d164019340d110d302634e429320577f0db7beJan Engelhardt    .final_check   = ecn_check,
15559d164019340d110d302634e429320577f0db7beJan Engelhardt    .print         = ecn_print,
15659d164019340d110d302634e429320577f0db7beJan Engelhardt    .save          = ecn_save,
15759d164019340d110d302634e429320577f0db7beJan Engelhardt    .extra_opts    = ecn_opts,
1587a44731615d950a2966737d1d1c960859023f3a3Harald Welte};
1597a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1607a44731615d950a2966737d1d1c960859023f3a3Harald Weltevoid _init(void)
1617a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
16259d164019340d110d302634e429320577f0db7beJan Engelhardt	register_match(&ecn_match);
1637a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
164