libipt_ECN.c revision 8b7c64d6ba156a99008fcd810cba874c73294333
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 16385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <iptables.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) 53385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte exit_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) 62c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte exit_error(PARAMETER_PROBLEM, 63c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Only use --ecn-tcp-cwr ONCE!"); 64c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte if (string_to_number(optarg, 0, 1, &result)) 65c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte exit_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) 73c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte exit_error(PARAMETER_PROBLEM, 74c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Only use --ecn-tcp-ece ONCE!"); 75c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte if (string_to_number(optarg, 0, 1, &result)) 76c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte exit_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) 84c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte exit_error(PARAMETER_PROBLEM, 85c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte "ECN target: Only use --ecn-ip-ect ONCE!"); 86c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte if (string_to_number(optarg, 0, 3, &result)) 87c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte exit_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) 103385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte exit_error(PARAMETER_PROBLEM, 1044ac9fddb50eb4898f145d6daf14cbf97702ee763Harald Welte "ECN target: Parameter --ecn-tcp-remove is required"); 105385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 106385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 107385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte/* Prints out the targinfo. */ 1081d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_print(const void *ip, const struct xt_entry_target *target, 1091d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt int numeric) 110385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 111385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte const struct ipt_ECN_info *einfo = 112385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte (const struct ipt_ECN_info *)target->data; 113385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 114385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte printf("ECN "); 115385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1167b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR) 1177b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte && einfo->proto.tcp.ece == 0 1187b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte && einfo->proto.tcp.cwr == 0) 1197b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("TCP remove "); 1207b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte else { 1217b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_ECE) 122c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte printf("ECE=%u ", einfo->proto.tcp.ece); 1237b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte 1247b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_CWR) 125c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte printf("CWR=%u ", einfo->proto.tcp.cwr); 1267b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte 1277b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_IP) 128c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte printf("ECT codepoint=%u ", einfo->ip_ect); 129385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte } 130385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 131385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 132385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte/* Saves the union ipt_targinfo in parsable form to stdout. */ 1331d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_save(const void *ip, const struct xt_entry_target *target) 134385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 135385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte const struct ipt_ECN_info *einfo = 136385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte (const struct ipt_ECN_info *)target->data; 137385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1387b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR) 1397b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte && einfo->proto.tcp.ece == 0 1407b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte && einfo->proto.tcp.cwr == 0) 1417b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("--ecn-tcp-remove "); 1427b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte else { 143c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte 1447b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_ECE) 1457b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece); 1467b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte 1477b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_CWR) 1487b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr); 149c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte 1507b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte if (einfo->operation & IPT_ECN_OP_SET_IP) 1517b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte printf("--ecn-ip-ect %d ", einfo->ip_ect); 152385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte } 153385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 154385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 1558b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target ecn_tg_reg = { 1568caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira .name = "ECN", 1578b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .version = XTABLES_VERSION, 1588b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .family = PF_INET, 1598b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .size = XT_ALIGN(sizeof(struct ipt_ECN_info)), 1608b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .userspacesize = XT_ALIGN(sizeof(struct ipt_ECN_info)), 1611d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .help = ECN_help, 1621d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .parse = ECN_parse, 1631d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .final_check = ECN_check, 1641d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .print = ECN_print, 1651d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .save = ECN_save, 1661d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .extra_opts = ECN_opts, 167385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}; 168385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte 169385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltevoid _init(void) 170385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{ 1718b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt xtables_register_target(&ecn_tg_reg); 172385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte} 173