1 #include <stdio.h> 2 #include <netdb.h> 3 #include <string.h> 4 #include <xtables.h> 5 #include <linux/netfilter/xt_connlimit.h> 6 7 enum { 8 O_UPTO = 0, 9 O_ABOVE, 10 O_MASK, 11 O_SADDR, 12 O_DADDR, 13 F_UPTO = 1 << O_UPTO, 14 F_ABOVE = 1 << O_ABOVE, 15 F_MASK = 1 << O_MASK, 16 F_SADDR = 1 << O_SADDR, 17 F_DADDR = 1 << O_DADDR, 18 }; 19 20 static void connlimit_help(void) 21 { 22 printf( 23 "connlimit match options:\n" 24 " --connlimit-upto n match if the number of existing connections is 0..n\n" 25 " --connlimit-above n match if the number of existing connections is >n\n" 26 " --connlimit-mask n group hosts using prefix length (default: max len)\n" 27 " --connlimit-saddr select source address for grouping\n" 28 " --connlimit-daddr select destination addresses for grouping\n"); 29 } 30 31 #define s struct xt_connlimit_info 32 static const struct xt_option_entry connlimit_opts[] = { 33 {.name = "connlimit-upto", .id = O_UPTO, .excl = F_ABOVE, 34 .type = XTTYPE_UINT32, .flags = XTOPT_INVERT | XTOPT_PUT, 35 XTOPT_POINTER(s, limit)}, 36 {.name = "connlimit-above", .id = O_ABOVE, .excl = F_UPTO, 37 .type = XTTYPE_UINT32, .flags = XTOPT_INVERT | XTOPT_PUT, 38 XTOPT_POINTER(s, limit)}, 39 {.name = "connlimit-mask", .id = O_MASK, .type = XTTYPE_PLENMASK, 40 .flags = XTOPT_PUT, XTOPT_POINTER(s, mask)}, 41 {.name = "connlimit-saddr", .id = O_SADDR, .excl = F_DADDR, 42 .type = XTTYPE_NONE}, 43 {.name = "connlimit-daddr", .id = O_DADDR, .excl = F_SADDR, 44 .type = XTTYPE_NONE}, 45 XTOPT_TABLEEND, 46 }; 47 #undef s 48 49 static void connlimit_init(struct xt_entry_match *match) 50 { 51 struct xt_connlimit_info *info = (void *)match->data; 52 53 /* This will also initialize the v4 mask correctly */ 54 memset(info->v6_mask, 0xFF, sizeof(info->v6_mask)); 55 } 56 57 static void connlimit_parse(struct xt_option_call *cb, uint8_t family) 58 { 59 struct xt_connlimit_info *info = cb->data; 60 const unsigned int revision = (*cb->match)->u.user.revision; 61 62 xtables_option_parse(cb); 63 switch (cb->entry->id) { 64 case O_ABOVE: 65 if (cb->invert) 66 info->flags |= XT_CONNLIMIT_INVERT; 67 break; 68 case O_UPTO: 69 if (!cb->invert) 70 info->flags |= XT_CONNLIMIT_INVERT; 71 break; 72 case O_SADDR: 73 if (revision < 1) 74 xtables_error(PARAMETER_PROBLEM, 75 "xt_connlimit.0 does not support " 76 "--connlimit-daddr"); 77 info->flags &= ~XT_CONNLIMIT_DADDR; 78 break; 79 case O_DADDR: 80 if (revision < 1) 81 xtables_error(PARAMETER_PROBLEM, 82 "xt_connlimit.0 does not support " 83 "--connlimit-daddr"); 84 info->flags |= XT_CONNLIMIT_DADDR; 85 break; 86 } 87 } 88 89 static void connlimit_parse4(struct xt_option_call *cb) 90 { 91 return connlimit_parse(cb, NFPROTO_IPV4); 92 } 93 94 static void connlimit_parse6(struct xt_option_call *cb) 95 { 96 return connlimit_parse(cb, NFPROTO_IPV6); 97 } 98 99 static void connlimit_check(struct xt_fcheck_call *cb) 100 { 101 if ((cb->xflags & (F_UPTO | F_ABOVE)) == 0) 102 xtables_error(PARAMETER_PROBLEM, 103 "You must specify \"--connlimit-above\" or " 104 "\"--connlimit-upto\"."); 105 } 106 107 static unsigned int count_bits4(uint32_t mask) 108 { 109 unsigned int bits = 0; 110 111 for (mask = ~ntohl(mask); mask != 0; mask >>= 1) 112 ++bits; 113 114 return 32 - bits; 115 } 116 117 static unsigned int count_bits6(const uint32_t *mask) 118 { 119 unsigned int bits = 0, i; 120 uint32_t tmp[4]; 121 122 for (i = 0; i < 4; ++i) 123 for (tmp[i] = ~ntohl(mask[i]); tmp[i] != 0; tmp[i] >>= 1) 124 ++bits; 125 return 128 - bits; 126 } 127 128 static void connlimit_print4(const void *ip, 129 const struct xt_entry_match *match, int numeric) 130 { 131 const struct xt_connlimit_info *info = (const void *)match->data; 132 133 printf(" #conn %s/%u %s %u", 134 (info->flags & XT_CONNLIMIT_DADDR) ? "dst" : "src", 135 count_bits4(info->v4_mask), 136 (info->flags & XT_CONNLIMIT_INVERT) ? "<=" : ">", info->limit); 137 } 138 139 static void connlimit_print6(const void *ip, 140 const struct xt_entry_match *match, int numeric) 141 { 142 const struct xt_connlimit_info *info = (const void *)match->data; 143 144 printf(" #conn %s/%u %s %u", 145 (info->flags & XT_CONNLIMIT_DADDR) ? "dst" : "src", 146 count_bits6(info->v6_mask), 147 (info->flags & XT_CONNLIMIT_INVERT) ? "<=" : ">", info->limit); 148 } 149 150 static void connlimit_save4(const void *ip, const struct xt_entry_match *match) 151 { 152 const struct xt_connlimit_info *info = (const void *)match->data; 153 const int revision = match->u.user.revision; 154 155 if (info->flags & XT_CONNLIMIT_INVERT) 156 printf(" --connlimit-upto %u", info->limit); 157 else 158 printf(" --connlimit-above %u", info->limit); 159 printf(" --connlimit-mask %u", count_bits4(info->v4_mask)); 160 if (revision >= 1) { 161 if (info->flags & XT_CONNLIMIT_DADDR) 162 printf(" --connlimit-daddr"); 163 else 164 printf(" --connlimit-saddr"); 165 } 166 } 167 168 static void connlimit_save6(const void *ip, const struct xt_entry_match *match) 169 { 170 const struct xt_connlimit_info *info = (const void *)match->data; 171 const int revision = match->u.user.revision; 172 173 if (info->flags & XT_CONNLIMIT_INVERT) 174 printf(" --connlimit-upto %u", info->limit); 175 else 176 printf(" --connlimit-above %u", info->limit); 177 printf(" --connlimit-mask %u", count_bits6(info->v6_mask)); 178 if (revision >= 1) { 179 if (info->flags & XT_CONNLIMIT_DADDR) 180 printf(" --connlimit-daddr"); 181 else 182 printf(" --connlimit-saddr"); 183 } 184 } 185 186 static struct xtables_match connlimit_mt_reg[] = { 187 { 188 .name = "connlimit", 189 .revision = 0, 190 .family = NFPROTO_IPV4, 191 .version = XTABLES_VERSION, 192 .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), 193 .userspacesize = offsetof(struct xt_connlimit_info, data), 194 .help = connlimit_help, 195 .init = connlimit_init, 196 .x6_parse = connlimit_parse4, 197 .x6_fcheck = connlimit_check, 198 .print = connlimit_print4, 199 .save = connlimit_save4, 200 .x6_options = connlimit_opts, 201 }, 202 { 203 .name = "connlimit", 204 .revision = 0, 205 .family = NFPROTO_IPV6, 206 .version = XTABLES_VERSION, 207 .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), 208 .userspacesize = offsetof(struct xt_connlimit_info, data), 209 .help = connlimit_help, 210 .init = connlimit_init, 211 .x6_parse = connlimit_parse6, 212 .x6_fcheck = connlimit_check, 213 .print = connlimit_print6, 214 .save = connlimit_save6, 215 .x6_options = connlimit_opts, 216 }, 217 { 218 .name = "connlimit", 219 .revision = 1, 220 .family = NFPROTO_IPV4, 221 .version = XTABLES_VERSION, 222 .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), 223 .userspacesize = offsetof(struct xt_connlimit_info, data), 224 .help = connlimit_help, 225 .init = connlimit_init, 226 .x6_parse = connlimit_parse4, 227 .x6_fcheck = connlimit_check, 228 .print = connlimit_print4, 229 .save = connlimit_save4, 230 .x6_options = connlimit_opts, 231 }, 232 { 233 .name = "connlimit", 234 .revision = 1, 235 .family = NFPROTO_IPV6, 236 .version = XTABLES_VERSION, 237 .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), 238 .userspacesize = offsetof(struct xt_connlimit_info, data), 239 .help = connlimit_help, 240 .init = connlimit_init, 241 .x6_parse = connlimit_parse6, 242 .x6_fcheck = connlimit_check, 243 .print = connlimit_print6, 244 .save = connlimit_save6, 245 .x6_options = connlimit_opts, 246 }, 247 }; 248 249 void _init(void) 250 { 251 xtables_register_matches(connlimit_mt_reg, ARRAY_SIZE(connlimit_mt_reg)); 252 } 253