1/* 2 * (C) 2006-2012 by Pablo Neira Ayuso <pablo@netfilter.org> 3 * (C) 2011-2012 by Vyatta Inc <http://www.vyatta.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20#include "filter.h" 21#include "bitops.h" 22#include "jhash.h" 23#include "hash.h" 24#include "vector.h" 25#include "conntrackd.h" 26#include "log.h" 27 28#include <libnetfilter_conntrack/libnetfilter_conntrack.h> 29#include <stdlib.h> 30#include <string.h> 31#include <errno.h> 32#include <limits.h> 33 34struct ct_filter { 35 int logic[CT_FILTER_MAX]; 36 u_int32_t l4protomap[IPPROTO_MAX/32]; 37 u_int16_t statemap[IPPROTO_MAX]; 38 struct hashtable *h; 39 struct hashtable *h6; 40 struct vector *v; 41 struct vector *v6; 42}; 43 44/* XXX: These should be configurable, better use a rb-tree */ 45#define FILTER_POOL_SIZE 128 46#define FILTER_POOL_LIMIT INT_MAX 47 48static uint32_t ct_filter_hash(const void *data, const struct hashtable *table) 49{ 50 const uint32_t *f = data; 51 52 return jhash_1word(*f, 0) % table->hashsize; 53} 54 55static uint32_t ct_filter_hash6(const void *data, const struct hashtable *table) 56{ 57 return jhash2(data, 4, 0) % table->hashsize; 58} 59 60static int ct_filter_compare(const void *data1, const void *data2) 61{ 62 const struct ct_filter_ipv4_hnode *f1 = data1; 63 const uint32_t *f2 = data2; 64 65 return f1->ip == *f2; 66} 67 68static int ct_filter_compare6(const void *data1, const void *data2) 69{ 70 const struct ct_filter_ipv6_hnode *f = data1; 71 72 return memcmp(f->ipv6, data2, sizeof(uint32_t)*4) == 0; 73} 74 75struct ct_filter *ct_filter_create(void) 76{ 77 int i; 78 struct ct_filter *filter; 79 80 filter = calloc(sizeof(struct ct_filter), 1); 81 if (!filter) 82 return NULL; 83 84 filter->h = hashtable_create(FILTER_POOL_SIZE, 85 FILTER_POOL_LIMIT, 86 ct_filter_hash, 87 ct_filter_compare); 88 if (!filter->h) { 89 free(filter); 90 return NULL; 91 } 92 93 filter->h6 = hashtable_create(FILTER_POOL_SIZE, 94 FILTER_POOL_LIMIT, 95 ct_filter_hash6, 96 ct_filter_compare6); 97 if (!filter->h6) { 98 free(filter->h); 99 free(filter); 100 return NULL; 101 } 102 103 filter->v = vector_create(sizeof(struct ct_filter_netmask_ipv4)); 104 if (!filter->v) { 105 free(filter->h6); 106 free(filter->h); 107 free(filter); 108 return NULL; 109 } 110 111 filter->v6 = vector_create(sizeof(struct ct_filter_netmask_ipv6)); 112 if (!filter->v6) { 113 free(filter->v); 114 free(filter->h6); 115 free(filter->h); 116 free(filter); 117 return NULL; 118 } 119 120 for (i=0; i<CT_FILTER_MAX; i++) 121 filter->logic[i] = -1; 122 123 return filter; 124} 125 126void ct_filter_destroy(struct ct_filter *filter) 127{ 128 hashtable_destroy(filter->h); 129 hashtable_destroy(filter->h6); 130 vector_destroy(filter->v); 131 vector_destroy(filter->v6); 132 free(filter); 133} 134 135/* this is ugly, but it simplifies read_config_yy.y */ 136static struct ct_filter *__filter_alloc(struct ct_filter *filter) 137{ 138 if (!STATE(us_filter)) { 139 STATE(us_filter) = ct_filter_create(); 140 if (!STATE(us_filter)) { 141 fprintf(stderr, "Can't create ignore pool!\n"); 142 exit(EXIT_FAILURE); 143 } 144 } 145 146 return STATE(us_filter); 147} 148 149void ct_filter_set_logic(struct ct_filter *filter, 150 enum ct_filter_type type, 151 enum ct_filter_logic logic) 152{ 153 filter = __filter_alloc(filter); 154 filter->logic[type] = logic; 155} 156 157int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family) 158{ 159 int id; 160 filter = __filter_alloc(filter); 161 162 switch(family) { 163 case AF_INET: 164 id = hashtable_hash(filter->h, data); 165 if (!hashtable_find(filter->h, data, id)) { 166 struct ct_filter_ipv4_hnode *n; 167 n = malloc(sizeof(struct ct_filter_ipv4_hnode)); 168 if (n == NULL) 169 return 0; 170 memcpy(&n->ip, data, sizeof(uint32_t)); 171 hashtable_add(filter->h, &n->node, id); 172 return 0; 173 } 174 break; 175 case AF_INET6: 176 id = hashtable_hash(filter->h6, data); 177 if (!hashtable_find(filter->h6, data, id)) { 178 struct ct_filter_ipv6_hnode *n; 179 n = malloc(sizeof(struct ct_filter_ipv6_hnode)); 180 if (n == NULL) 181 return 0; 182 memcpy(n->ipv6, data, sizeof(uint32_t)*4); 183 hashtable_add(filter->h6, &n->node, id); 184 return 0; 185 } 186 break; 187 } 188 return 1; 189} 190 191static int cmp_ipv4_addr(const void *a, const void *b) 192{ 193 return memcmp(a, b, sizeof(struct ct_filter_netmask_ipv4)) == 0; 194} 195 196static int cmp_ipv6_addr(const void *a, const void *b) 197{ 198 return memcmp(a, b, sizeof(struct ct_filter_netmask_ipv6)) == 0; 199} 200 201int ct_filter_add_netmask(struct ct_filter *filter, void *data, uint8_t family) 202{ 203 filter = __filter_alloc(filter); 204 205 switch(family) { 206 case AF_INET: 207 if (vector_iterate(filter->v, data, cmp_ipv4_addr)) { 208 errno = EEXIST; 209 return 0; 210 } 211 vector_add(filter->v, data); 212 break; 213 case AF_INET6: 214 if (vector_iterate(filter->v, data, cmp_ipv6_addr)) { 215 errno = EEXIST; 216 return 0; 217 } 218 vector_add(filter->v6, data); 219 break; 220 } 221 return 1; 222} 223 224void ct_filter_add_proto(struct ct_filter *f, int protonum) 225{ 226 f = __filter_alloc(f); 227 228 set_bit_u32(protonum, f->l4protomap); 229} 230 231void ct_filter_add_state(struct ct_filter *f, int protonum, int val) 232{ 233 f = __filter_alloc(f); 234 235 set_bit_u16(val, &f->statemap[protonum]); 236} 237 238static inline int 239__ct_filter_test_ipv4(struct ct_filter *f, const struct nf_conntrack *ct) 240{ 241 int id_src, id_dst; 242 uint32_t src, dst; 243 244 /* we only use the real source and destination address */ 245 src = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC); 246 dst = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); 247 248 id_src = hashtable_hash(f->h, &src); 249 id_dst = hashtable_hash(f->h, &dst); 250 251 return hashtable_find(f->h, &src, id_src) || 252 hashtable_find(f->h, &dst, id_dst); 253} 254 255static inline int 256__ct_filter_test_ipv6(struct ct_filter *f, const struct nf_conntrack *ct) 257{ 258 int id_src, id_dst; 259 const uint32_t *src, *dst; 260 261 src = nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC); 262 dst = nfct_get_attr(ct, ATTR_REPL_IPV6_SRC); 263 264 id_src = hashtable_hash(f->h6, src); 265 id_dst = hashtable_hash(f->h6, dst); 266 267 return hashtable_find(f->h6, src, id_src) || 268 hashtable_find(f->h6, dst, id_dst); 269} 270 271static int 272__ct_filter_test_mask4(const void *ptr, const void *ct) 273{ 274 const struct ct_filter_netmask_ipv4 *elem = ptr; 275 const uint32_t src = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC); 276 const uint32_t dst = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); 277 278 return ((elem->ip & elem->mask) == (src & elem->mask) || 279 (elem->ip & elem->mask) == (dst & elem->mask)); 280} 281 282static int 283__ct_filter_test_mask6(const void *ptr, const void *ct) 284{ 285 const struct ct_filter_netmask_ipv6 *elem = ptr; 286 const uint32_t *src = nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC); 287 const uint32_t *dst = nfct_get_attr(ct, ATTR_REPL_IPV6_SRC); 288 289 return (((elem->ip[0] & elem->mask[0]) == (src[0] & elem->mask[0]) && 290 (elem->ip[1] & elem->mask[1]) == (src[1] & elem->mask[1]) && 291 (elem->ip[2] & elem->mask[2]) == (src[2] & elem->mask[2]) && 292 (elem->ip[3] & elem->mask[3]) == (src[3] & elem->mask[3])) || 293 ((elem->ip[0] & elem->mask[0]) == (dst[0] & elem->mask[0]) && 294 (elem->ip[1] & elem->mask[1]) == (dst[1] & elem->mask[1]) && 295 (elem->ip[2] & elem->mask[2]) == (dst[2] & elem->mask[2]) && 296 (elem->ip[3] & elem->mask[3]) == (dst[3] & elem->mask[3]))); 297} 298 299static int 300__ct_filter_test_state(struct ct_filter *f, const struct nf_conntrack *ct) 301{ 302 uint16_t val = 0; 303 uint8_t protonum = nfct_get_attr_u8(ct, ATTR_L4PROTO); 304 305 switch(protonum) { 306 case IPPROTO_TCP: 307 if (!nfct_attr_is_set(ct, ATTR_TCP_STATE)) 308 return -1; 309 310 val = nfct_get_attr_u8(ct, ATTR_TCP_STATE); 311 break; 312 default: 313 return -1; 314 } 315 316 return test_bit_u16(val, &f->statemap[protonum]); 317} 318 319static int 320ct_filter_check(struct ct_filter *f, const struct nf_conntrack *ct) 321{ 322 int ret, protonum = nfct_get_attr_u8(ct, ATTR_L4PROTO); 323 324 /* no event filtering at all */ 325 if (f == NULL) 326 return 1; 327 328 if (f->logic[CT_FILTER_L4PROTO] != -1) { 329 ret = test_bit_u32(protonum, f->l4protomap); 330 if (ret ^ f->logic[CT_FILTER_L4PROTO]) 331 return 0; 332 } 333 334 if (f->logic[CT_FILTER_ADDRESS] != -1) { 335 switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { 336 case AF_INET: 337 ret = vector_iterate(f->v, ct, __ct_filter_test_mask4); 338 if (ret ^ f->logic[CT_FILTER_ADDRESS]) 339 return 0; 340 ret = __ct_filter_test_ipv4(f, ct); 341 if (ret ^ f->logic[CT_FILTER_ADDRESS]) 342 return 0; 343 break; 344 case AF_INET6: 345 ret = vector_iterate(f->v6, ct, __ct_filter_test_mask6); 346 if (ret ^ f->logic[CT_FILTER_ADDRESS]) 347 return 0; 348 ret = __ct_filter_test_ipv6(f, ct); 349 if (ret ^ f->logic[CT_FILTER_ADDRESS]) 350 return 0; 351 break; 352 default: 353 break; 354 } 355 } 356 357 if (f->logic[CT_FILTER_STATE] != -1) { 358 ret = __ct_filter_test_state(f, ct); 359 /* ret is -1 if we don't know what to do */ 360 if (ret != -1 && ret ^ f->logic[CT_FILTER_STATE]) 361 return 0; 362 } 363 364 return 1; 365} 366 367static inline int ct_filter_sanity_check(const struct nf_conntrack *ct) 368{ 369 if (!nfct_attr_is_set(ct, ATTR_L3PROTO)) { 370 dlog(LOG_ERR, "missing layer 3 protocol"); 371 return 0; 372 } 373 374 switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { 375 case AF_INET: 376 if (!nfct_attr_is_set(ct, ATTR_IPV4_SRC) || 377 !nfct_attr_is_set(ct, ATTR_IPV4_DST)) { 378 dlog(LOG_ERR, "missing IPv4 address. " 379 "You forgot to load " 380 "nf_conntrack_ipv4?"); 381 return 0; 382 } 383 break; 384 case AF_INET6: 385 if (!nfct_attr_is_set(ct, ATTR_IPV6_SRC) || 386 !nfct_attr_is_set(ct, ATTR_IPV6_DST)) { 387 dlog(LOG_ERR, "missing IPv6 address. " 388 "You forgot to load " 389 "nf_conntrack_ipv6?"); 390 return 0; 391 } 392 break; 393 } 394 return 1; 395} 396 397/* we do user-space filtering for dump and resyncs */ 398int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace) 399{ 400 /* missing mandatory attributes in object */ 401 if (!ct_filter_sanity_check(ct)) 402 return 1; 403 404 if (userspace && !ct_filter_check(STATE(us_filter), ct)) 405 return 1; 406 407 return 0; 408} 409 410struct exp_filter { 411 struct list_head list; 412}; 413 414struct exp_filter *exp_filter_create(void) 415{ 416 struct exp_filter *f; 417 418 f = calloc(1, sizeof(struct exp_filter)); 419 if (f == NULL) 420 return NULL; 421 422 INIT_LIST_HEAD(&f->list); 423 return f; 424} 425 426struct exp_filter_item { 427 struct list_head head; 428 char helper_name[NFCT_HELPER_NAME_MAX]; 429}; 430 431/* this is ugly, but it simplifies read_config_yy.y */ 432static struct exp_filter *exp_filter_alloc(void) 433{ 434 if (STATE(exp_filter) == NULL) { 435 STATE(exp_filter) = exp_filter_create(); 436 if (STATE(exp_filter) == NULL) { 437 fprintf(stderr, "Can't init expectation filtering!\n"); 438 return NULL; 439 } 440 } 441 return STATE(exp_filter);; 442} 443 444int exp_filter_add(struct exp_filter *f, const char *helper_name) 445{ 446 struct exp_filter_item *item; 447 448 f = exp_filter_alloc(); 449 if (f == NULL) 450 return -1; 451 452 list_for_each_entry(item, &f->list, head) { 453 if (strncasecmp(item->helper_name, helper_name, 454 NFCT_HELPER_NAME_MAX) == 0) { 455 return -1; 456 } 457 } 458 item = calloc(1, sizeof(struct exp_filter_item)); 459 if (item == NULL) 460 return -1; 461 462 strncpy(item->helper_name, helper_name, NFCT_HELPER_NAME_MAX); 463 list_add(&item->head, &f->list); 464 return 0; 465} 466 467int exp_filter_find(struct exp_filter *f, const struct nf_expect *exp) 468{ 469 struct exp_filter_item *item; 470 471 /* if filtering is not active, accept everything. */ 472 if (f == NULL) 473 return 1; 474 475 list_for_each_entry(item, &f->list, head) { 476 const char *name; 477 478 if (nfexp_attr_is_set(exp, ATTR_EXP_HELPER_NAME)) 479 name = nfexp_get_attr(exp, ATTR_EXP_HELPER_NAME); 480 else { 481 /* No helper name, this is likely to be a kernel older 482 * which does not include the helper name, just skip 483 * this so we don't crash. 484 */ 485 return 0; 486 } 487 488 /* we allow partial matching to support things like sip-PORT. */ 489 if (strncasecmp(item->helper_name, name, 490 strlen(item->helper_name)) == 0) { 491 return 1; 492 } 493 } 494 return 0; 495} 496