libxt_connlimit.c revision f2a77520693f0a6dd1df1f87be4b81913961c1f5
1/* Shared library add-on to iptables to add connection limit support. */ 2#include <stdio.h> 3#include <netdb.h> 4#include <string.h> 5#include <stdlib.h> 6#include <stddef.h> 7#include <getopt.h> 8#include <xtables.h> 9#include <linux/netfilter/xt_connlimit.h> 10 11static void connlimit_help(void) 12{ 13 printf( 14"connlimit match options:\n" 15"[!] --connlimit-above n match if the number of existing " 16" connections is (not) above n\n" 17" --connlimit-mask n group hosts using mask\n"); 18} 19 20static const struct option connlimit_opts[] = { 21 {"connlimit-above", 1, NULL, 'A'}, 22 {"connlimit-mask", 1, NULL, 'M'}, 23 { .name = NULL } 24}; 25 26static void connlimit_init(struct xt_entry_match *match) 27{ 28 struct xt_connlimit_info *info = (void *)match->data; 29 30 /* This will also initialize the v4 mask correctly */ 31 memset(info->v6_mask, 0xFF, sizeof(info->v6_mask)); 32} 33 34static void prefix_to_netmask(u_int32_t *mask, unsigned int prefix_len) 35{ 36 if (prefix_len == 0) { 37 mask[0] = mask[1] = mask[2] = mask[3] = 0; 38 } else if (prefix_len <= 32) { 39 mask[0] <<= 32 - prefix_len; 40 mask[1] = mask[2] = mask[3] = 0; 41 } else if (prefix_len <= 64) { 42 mask[1] <<= 32 - (prefix_len - 32); 43 mask[2] = mask[3] = 0; 44 } else if (prefix_len <= 96) { 45 mask[2] <<= 32 - (prefix_len - 64); 46 mask[3] = 0; 47 } else if (prefix_len <= 128) { 48 mask[3] <<= 32 - (prefix_len - 96); 49 } 50 mask[0] = htonl(mask[0]); 51 mask[1] = htonl(mask[1]); 52 mask[2] = htonl(mask[2]); 53 mask[3] = htonl(mask[3]); 54} 55 56static int connlimit_parse(int c, char **argv, int invert, unsigned int *flags, 57 struct xt_connlimit_info *info, unsigned int family) 58{ 59 char *err; 60 int i; 61 62 switch (c) { 63 case 'A': 64 if (*flags & 0x1) 65 xtables_error(PARAMETER_PROBLEM, 66 "--connlimit-above may be given only once"); 67 *flags |= 0x1; 68 xtables_check_inverse(optarg, &invert, &optind, 0); 69 info->limit = strtoul(argv[optind-1], NULL, 0); 70 info->inverse = invert; 71 break; 72 case 'M': 73 if (*flags & 0x2) 74 xtables_error(PARAMETER_PROBLEM, 75 "--connlimit-mask may be given only once"); 76 77 *flags |= 0x2; 78 i = strtoul(argv[optind-1], &err, 0); 79 if (family == NFPROTO_IPV6) { 80 if (i > 128 || *err != '\0') 81 xtables_error(PARAMETER_PROBLEM, 82 "--connlimit-mask must be between " 83 "0 and 128"); 84 prefix_to_netmask(info->v6_mask, i); 85 } else { 86 if (i > 32 || *err != '\0') 87 xtables_error(PARAMETER_PROBLEM, 88 "--connlimit-mask must be between " 89 "0 and 32"); 90 if (i == 0) 91 info->v4_mask = 0; 92 else 93 info->v4_mask = htonl(0xFFFFFFFF << (32 - i)); 94 } 95 break; 96 default: 97 return 0; 98 } 99 100 return 1; 101} 102 103static int connlimit_parse4(int c, char **argv, int invert, 104 unsigned int *flags, const void *entry, 105 struct xt_entry_match **match) 106{ 107 return connlimit_parse(c, argv, invert, flags, 108 (void *)(*match)->data, NFPROTO_IPV4); 109} 110 111static int connlimit_parse6(int c, char **argv, int invert, 112 unsigned int *flags, const void *entry, 113 struct xt_entry_match **match) 114{ 115 return connlimit_parse(c, argv, invert, flags, 116 (void *)(*match)->data, NFPROTO_IPV6); 117} 118 119static void connlimit_check(unsigned int flags) 120{ 121 if (!(flags & 0x1)) 122 xtables_error(PARAMETER_PROBLEM, 123 "You must specify \"--connlimit-above\""); 124} 125 126static unsigned int count_bits4(u_int32_t mask) 127{ 128 unsigned int bits = 0; 129 130 for (mask = ~ntohl(mask); mask != 0; mask >>= 1) 131 ++bits; 132 133 return 32 - bits; 134} 135 136static unsigned int count_bits6(const u_int32_t *mask) 137{ 138 unsigned int bits = 0, i; 139 u_int32_t tmp[4]; 140 141 for (i = 0; i < 4; ++i) 142 for (tmp[i] = ~ntohl(mask[i]); tmp[i] != 0; tmp[i] >>= 1) 143 ++bits; 144 return 128 - bits; 145} 146 147static void connlimit_print4(const void *ip, 148 const struct xt_entry_match *match, int numeric) 149{ 150 const struct xt_connlimit_info *info = (const void *)match->data; 151 152 printf("#conn/%u %s %u ", count_bits4(info->v4_mask), 153 info->inverse ? "<=" : ">", info->limit); 154} 155 156static void connlimit_print6(const void *ip, 157 const struct xt_entry_match *match, int numeric) 158{ 159 const struct xt_connlimit_info *info = (const void *)match->data; 160 printf("#conn/%u %s %u ", count_bits6(info->v6_mask), 161 info->inverse ? "<=" : ">", info->limit); 162} 163 164static void connlimit_save4(const void *ip, const struct xt_entry_match *match) 165{ 166 const struct xt_connlimit_info *info = (const void *)match->data; 167 168 printf("%s--connlimit-above %u --connlimit-mask %u ", 169 info->inverse ? "! " : "", info->limit, 170 count_bits4(info->v4_mask)); 171} 172 173static void connlimit_save6(const void *ip, const struct xt_entry_match *match) 174{ 175 const struct xt_connlimit_info *info = (const void *)match->data; 176 177 printf("%s--connlimit-above %u --connlimit-mask %u ", 178 info->inverse ? "! " : "", info->limit, 179 count_bits6(info->v6_mask)); 180} 181 182static struct xtables_match connlimit_mt_reg[] = { 183 { 184 .name = "connlimit", 185 .family = NFPROTO_IPV4, 186 .version = XTABLES_VERSION, 187 .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), 188 .userspacesize = offsetof(struct xt_connlimit_info, data), 189 .help = connlimit_help, 190 .init = connlimit_init, 191 .parse = connlimit_parse4, 192 .final_check = connlimit_check, 193 .print = connlimit_print4, 194 .save = connlimit_save4, 195 .extra_opts = connlimit_opts, 196 }, 197 { 198 .name = "connlimit", 199 .family = NFPROTO_IPV6, 200 .version = XTABLES_VERSION, 201 .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), 202 .userspacesize = offsetof(struct xt_connlimit_info, data), 203 .help = connlimit_help, 204 .init = connlimit_init, 205 .parse = connlimit_parse6, 206 .final_check = connlimit_check, 207 .print = connlimit_print6, 208 .save = connlimit_save6, 209 .extra_opts = connlimit_opts, 210 }, 211}; 212 213void _init(void) 214{ 215 xtables_register_matches(connlimit_mt_reg, ARRAY_SIZE(connlimit_mt_reg)); 216} 217