libipt_ECN.c revision 1829ed482efbc8b390cc760d012b3a4450494e1a
1385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte/* Shared library add-on to iptables for ECN, $Version$ 2385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * 3385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * (C) 2002 by Harald Welte <laforge@gnumonks.org> 4385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * 5385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * This program is distributed under the terms of GNU GPL v2, 1991 6385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * 7385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * libipt_ECN.c borrowed heavily from libipt_DSCP.c 8385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * 98caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira * $Id$ 10385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte */ 11385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <stdio.h> 12385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <string.h> 13385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <stdlib.h> 14385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <getopt.h> 15385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 165d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h> 17385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <linux/netfilter_ipv4/ip_tables.h> 18385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <linux/netfilter_ipv4/ipt_ECN.h> 19385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 201d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_help(void) 21385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 22385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte printf( 238b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"ECN target options\n" 248b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt" --ecn-tcp-remove Remove all ECN bits from TCP header\n"); 2531d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte} 2631d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte 2731d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte#if 0 281c8fa733e6092029d97bc5b2b6a4cb13b513f2f0Harald Welte"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n" 29c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte" --ecn-ip-ect Set the IPv4 ECT codepoint (0 to 3)\n" 30c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte" --ecn-tcp-cwr Set the IPv4 CWR bit (0 or 1)\n" 3192cad5f4a349daac294332b8f8f696b43c55d3fcHarald Welte" --ecn-tcp-ece Set the IPv4 ECE bit (0 or 1)\n", 3231d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte#endif 3331d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte 34385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 351d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic const struct option ECN_opts[] = { 36500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy { "ecn-tcp-remove", 0, NULL, 'F' }, 37500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy { "ecn-tcp-cwr", 1, NULL, 'G' }, 38500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy { "ecn-tcp-ece", 1, NULL, 'H' }, 39500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy { "ecn-ip-ect", 1, NULL, '9' }, 409ee386a1b6d7704b259460152c959ab0e79e02aaMax Kellermann { .name = NULL } 41385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}; 42385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 431d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic int ECN_parse(int c, char **argv, int invert, unsigned int *flags, 441d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt const void *entry, struct xt_entry_target **target) 45385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 46c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte unsigned int result; 475a15c9a8b29871fc3246ed91423f271041a87c21Harald Welte struct ipt_ECN_info *einfo 48385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte = (struct ipt_ECN_info *)(*target)->data; 49385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 50385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte switch (c) { 51385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte case 'F': 52385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte if (*flags) 531829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 54c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Only use --ecn-tcp-remove ONCE!"); 55c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR; 56c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->proto.tcp.ece = 0; 57c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->proto.tcp.cwr = 0; 58385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte *flags = 1; 59385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte break; 60c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte case 'G': 61c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte if (*flags & IPT_ECN_OP_SET_CWR) 621829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 63c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Only use --ecn-tcp-cwr ONCE!"); 645f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt if (!xtables_strtoui(optarg, NULL, &result, 0, 1)) 651829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 66c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Value out of range"); 67c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->operation |= IPT_ECN_OP_SET_CWR; 68c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->proto.tcp.cwr = result; 69c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte *flags |= IPT_ECN_OP_SET_CWR; 70c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte break; 71c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte case 'H': 72c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte if (*flags & IPT_ECN_OP_SET_ECE) 731829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 74c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Only use --ecn-tcp-ece ONCE!"); 755f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt if (!xtables_strtoui(optarg, NULL, &result, 0, 1)) 761829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 77c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Value out of range"); 78c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->operation |= IPT_ECN_OP_SET_ECE; 79c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->proto.tcp.ece = result; 80c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte *flags |= IPT_ECN_OP_SET_ECE; 81c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte break; 82c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte case '9': 83c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte if (*flags & IPT_ECN_OP_SET_IP) 841829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 85c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Only use --ecn-ip-ect ONCE!"); 865f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt if (!xtables_strtoui(optarg, NULL, &result, 0, 3)) 871829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 88c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Value out of range"); 89c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->operation |= IPT_ECN_OP_SET_IP; 90c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte einfo->ip_ect = result; 91c05c44fc6018fcd94df499c981d846ff20882c4cHarald Welte *flags |= IPT_ECN_OP_SET_IP; 92c05c44fc6018fcd94df499c981d846ff20882c4cHarald Welte break; 93385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte default: 94385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte return 0; 95385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte } 96385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 97385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte return 1; 98385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 99385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1001d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_check(unsigned int flags) 101385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 102385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte if (!flags) 1031829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 1044ac9fddb50eb4898f145d6daf14cbf97702ee763Harald Welte "ECN target: Parameter --ecn-tcp-remove is required"); 105385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 106385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1071d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_print(const void *ip, const struct xt_entry_target *target, 1081d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt int numeric) 109385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 110385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte const struct ipt_ECN_info *einfo = 111385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte (const struct ipt_ECN_info *)target->data; 112385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 113385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte printf("ECN "); 114385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1157b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR) 1167b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte && einfo->proto.tcp.ece == 0 1177b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte && einfo->proto.tcp.cwr == 0) 1187b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("TCP remove "); 1197b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte else { 1207b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_ECE) 121c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte printf("ECE=%u ", einfo->proto.tcp.ece); 1227b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte 1237b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_CWR) 124c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte printf("CWR=%u ", einfo->proto.tcp.cwr); 1257b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte 1267b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_IP) 127c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte printf("ECT codepoint=%u ", einfo->ip_ect); 128385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte } 129385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 130385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1311d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_save(const void *ip, const struct xt_entry_target *target) 132385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 133385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte const struct ipt_ECN_info *einfo = 134385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte (const struct ipt_ECN_info *)target->data; 135385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1367b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR) 1377b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte && einfo->proto.tcp.ece == 0 1387b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte && einfo->proto.tcp.cwr == 0) 1397b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("--ecn-tcp-remove "); 1407b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte else { 141c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte 1427b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_ECE) 1437b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece); 1447b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte 1457b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_CWR) 1467b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr); 147c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte 1487b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_IP) 1497b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("--ecn-ip-ect %d ", einfo->ip_ect); 150385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte } 151385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 152385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1538b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target ecn_tg_reg = { 1548caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira .name = "ECN", 1558b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .version = XTABLES_VERSION, 15603d99486d8283552705b58dc55b6085dffc38792Jan Engelhardt .family = NFPROTO_IPV4, 1578b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .size = XT_ALIGN(sizeof(struct ipt_ECN_info)), 1588b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .userspacesize = XT_ALIGN(sizeof(struct ipt_ECN_info)), 1591d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .help = ECN_help, 1601d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .parse = ECN_parse, 1611d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .final_check = ECN_check, 1621d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .print = ECN_print, 1631d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .save = ECN_save, 1641d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .extra_opts = ECN_opts, 165385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}; 166385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 167385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltevoid _init(void) 168385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 1698b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt xtables_register_target(&ecn_tg_reg); 170385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 171