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