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