4556570 [rkeene@sledge /home/rkeene/tmp/pnfq-0.1.15]$ cat -n pnfq.c
   1 #include <linux/netfilter.h>
   2 #include <sys/types.h>
   3 #include <sys/mman.h>
   4 #include <pthread.h>
   5 #include <libipq.h>
   6 #include <unistd.h>
   7 #include <stdlib.h>
   8 #include <stdint.h>
   9 #include <string.h>
  10 #include <assert.h>
  11 #include <stdio.h>
  12 #include <time.h>
  13 #include <tcl.h>
  14 
  15 #ifdef HAVE_CONFIG_H
  16 #include "config.h"
  17 #endif
  18 
  19 /*
  20  * Maximum size of packet to process
  21  */
  22 #ifndef PNFQ_PKT_BUF_LEN
  23 #define PNFQ_PKT_BUF_LEN 65535
  24 #endif
  25 
  26 /*
  27  * Abort after how many consecutive LIBIPQ errors
  28  */
  29 #ifndef PNFQ_MAX_READ_ERRORS
  30 #define PNFQ_MAX_READ_ERRORS 20
  31 #endif
  32 
  33 /*
  34  * Default number of Worker threads
  35  */
  36 #ifndef PNFQ_NUM_THREADS
  37 #define PNFQ_NUM_THREADS 4
  38 #endif
  39 
  40 /*
  41  * Sanity warning
  42  */
  43 #if defined(USE_TCL_PKT_HANDLER) && !defined(USE_THREADED_TCL)
  44 #warning *************************************
  45 #warning *** THIS IS NOT AN OPTIMAL BUILD! ***
  46 #warning *************************************
  47 #warning *** YOU SHOULD USE A THREADED TCL ***
  48 #warning *** FOR A RELEASE BUILD. REFER TO ***
  49 #warning *** <rootdir>/build/build_release ***
  50 #warning *** FOR ADDITIONAL INFO AND HELP. ***
  51 #warning *************************************
  52 #ifndef USE_FORCE
  53 #error ADD "-DUSE_FORCE=1" TO THE CFLAGS LINE IN THE "Makefile" TO FORCE BUILD
  54 #endif
  55 #endif
  56 
  57 typedef enum {
  58     PNFQ_CHECK_ACCEPT = NF_ACCEPT,
  59     PNFQ_CHECK_DROP = NF_DROP,
  60     PNFQ_CHECK_CONTINUE = (PNFQ_CHECK_ACCEPT + PNFQ_CHECK_DROP + 1),
  61     PNFQ_CHECK_DEFAULT = (PNFQ_CHECK_CONTINUE + PNFQ_CHECK_ACCEPT + PNFQ_CHECK_DROP + 1)
  62 } pnfq_check_result_t;
  63 
  64 struct pnfq_check_node;
  65 struct pnfq_check_node {
  66     pnfq_check_result_t action;
  67     struct pnfq_check_node *_zero;
  68     struct pnfq_check_node *_one;
  69 };
  70 
  71 struct pnfq_thread_info {
  72     struct ipq_handle *handle;
  73 
  74 #ifdef USE_TCL_PKT_HANDLER
  75 #ifndef USE_THREADED_TCL
  76     pthread_mutex_t *tcl_mutex;
  77 #endif
  78     const char *tcl_scpdir;
  79 #endif
  80 
  81     int thread_id;
  82 };
  83 
  84 #ifdef USE_IPV6
  85 typedef struct {
  86     uint32_t a[4];
  87 } uint128_t;
  88 
  89 typedef enum {
  90     PNFQ_ADDR_TYPE_IPV4,
  91     PNFQ_ADDR_TYPE_IPV6,
  92     PNFQ_ADDR_TYPE_UNKNOWN
  93 } pnfq_addr_type_t;
  94 
  95 typedef struct {
  96     pnfq_addr_type_t type;
  97     union {
  98         uint32_t ipv4;
  99         uint128_t ipv6;
 100     } addr;
 101 } pnfq_addr_t;
 102 
 103 struct pnfq_check_node pnfq_check_tree_v6 = {PNFQ_CHECK_CONTINUE, NULL, NULL};
 104 #else
 105 typedef uint32_t pnfq_addr_t;
 106 #endif
 107 
 108 struct pnfq_check_node pnfq_check_tree_v4 = {PNFQ_CHECK_CONTINUE, NULL, NULL};
 109 
 110 /*
 111  * CODE
 112  */
 113 void print_help(void) {
 114     printf("Usage:  pnfq [-Vhcl] [-T <tcl_script_dir>] [-t <num_threads>]\n");
 115     printf("  -V        Print out PNFQ Version information\n");
 116     printf("  -h        Print out usage information (this information)\n");
 117     printf("  -c        Print out build information\n");
 118     printf("  -l        Lock all memory pages into physical RAM (DANGEROUS)\n");
 119     printf("  -T <dir>  Set the directory where Tcl helper scripts live\n");
 120     printf("  -t <num>  Set the number of worker threads to create\n");
 121 
 122     return;
 123 }
 124 
 125 
 126 /*
 127  * IP Maniuplation Functions
 128  */
 129 static inline char *ipv4_to_str(uint32_t addr, char *buf, size_t buflen) {
 130     snprintf(buf, buflen, "%i.%i.%i.%i", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
 131     return(buf);
 132 }
 133 static inline uint32_t str_to_ipv4(char *ip) {
 134     uint32_t ret = 0;
 135     char *p;
 136     int i;
 137 
 138     p = ip;
 139 
 140     for (i = 0; i < 4; i++) {
 141         ret <<= 8;
 142         ret += strtoul(p, &p, 10);
 143 
 144         if (i != 3) {
 145             if (!p) {
 146                 return(0);
 147             }
 148             if (*p != '.') {
 149                 return(0);
 150             }
 151         }
 152         p++;
 153     }
 154 
 155     return(ret);
 156 }
 157 #ifdef USE_IPV6
 158 static inline char *ipv6_to_str(uint128_t addr, char *buf, size_t buflen) {
 159     snprintf(buf, buflen, "%x:%x:%x:%x:%x:%x:%x:%x",
 160              (addr.a[0] >> 16) & 0xffff,
 161              addr.a[0] & 0xffff,
 162              (addr.a[1] >> 16) & 0xffff,
 163              addr.a[1] & 0xffff,
 164              (addr.a[2] >> 16) & 0xffff,
 165              addr.a[2] & 0xffff,
 166              (addr.a[3] >> 16) & 0xffff,
 167              addr.a[3] & 0xffff);
 168     return(buf);
 169 }
 170 /*
 171  * NOTE: Does not support "captured zeros"
 172  */
 173 static inline uint128_t str_to_ipv6(char *ip) {
 174     uint128_t ret = {{0}}, error_ret = {{0}};
 175     char *p;
 176     int i;
 177 
 178     p = ip;
 179 
 180     for (i = 0; i < 8; i++) {
 181         ret.a[i/2] <<= 16;
 182         ret.a[i/2] += strtoul(p, &p, 16);
 183 
 184         if (i != 7) {
 185             if (!p) {
 186                 return(error_ret);
 187             }
 188             if (*p != ':') {
 189                 return(error_ret);
 190             }
 191         }
 192         p++;
 193     }
 194 
 195     return(ret);
 196 }
 197 static inline char *ip_to_str(pnfq_addr_t addr, char *buf, size_t buflen) {
 198     switch (addr.type) {
 199         case PNFQ_ADDR_TYPE_IPV4:
 200             return(ipv4_to_str(addr.addr.ipv4, buf, buflen));
 201         case PNFQ_ADDR_TYPE_IPV6:
 202             return(ipv6_to_str(addr.addr.ipv6, buf, buflen));
 203         case PNFQ_ADDR_TYPE_UNKNOWN:
 204             return("");
 205     }
 206 
 207     return("");
 208 }
 209 static inline pnfq_addr_t str_to_ip(char *ip) {
 210     pnfq_addr_t ret;
 211 
 212     if (strchr(ip, '.') != NULL) {
 213         ret.type = PNFQ_ADDR_TYPE_IPV4;
 214         ret.addr.ipv4 = str_to_ipv4(ip);
 215     } else if (strchr(ip, ':') != NULL) {
 216         ret.type = PNFQ_ADDR_TYPE_IPV6;
 217         ret.addr.ipv6 = str_to_ipv6(ip);
 218     } else {
 219         ret.type = PNFQ_ADDR_TYPE_UNKNOWN;
 220     }
 221 
 222     return(ret);
 223 }
 224 #else
 225 #define str_to_ip(x) str_to_ipv4(x)
 226 #define ip_to_str(x, y, z) ipv4_to_str(x, y, z)
 227 #endif
 228 
 229 /*
 230  * Packet Payload Inspection Routines
 231  */
 232 static inline void ipv4_pkt_info(const unsigned char *payload, uint32_t *src, uint32_t *dst) {
 233     /* IP Address                   Bytes 13 - 16 of IP header */
 234     *src = (payload[12] << 24) | (payload[13] << 16) | (payload[14] << 8) | payload[15];
 235     *dst = (payload[16] << 24) | (payload[17] << 16) | (payload[18] << 8) | payload[19];
 236 
 237     return;
 238 }
 239 #ifdef USE_IPV6
 240 static inline void ipv6_pkt_info(const unsigned char *payload, uint128_t *src, uint128_t *dst) {
 241     src->a[0] = (payload[8] << 24) | (payload[9] << 16) | (payload[10] << 8) | payload[11];
 242     src->a[1] = (payload[12] << 24) | (payload[13] << 16) | (payload[14] << 8) | payload[15];
 243     src->a[2] = (payload[16] << 24) | (payload[17] << 16) | (payload[18] << 8) | payload[19];
 244     src->a[3] = (payload[20] << 24) | (payload[21] << 16) | (payload[22] << 8) | payload[23];
 245 
 246     dst->a[0] = (payload[24] << 24) | (payload[25] << 16) | (payload[26] << 8) | payload[27];
 247     dst->a[1] = (payload[28] << 24) | (payload[29] << 16) | (payload[30] << 8) | payload[31];
 248     dst->a[2] = (payload[32] << 24) | (payload[33] << 16) | (payload[34] << 8) | payload[35];
 249     dst->a[3] = (payload[36] << 24) | (payload[37] << 16) | (payload[38] << 8) | payload[39];
 250 
 251     return;
 252 }
 253 #endif
 254 static inline void pkt_info(ipq_packet_msg_t *pkt, pnfq_addr_t *src, pnfq_addr_t *dst) {
 255     unsigned char *payload;
 256     int ip_header_length, header_size;;
 257     int version, data_len;
 258 
 259     assert(pkt != NULL);
 260 
 261     assert(src != NULL);
 262 
 263     assert(dst != NULL);
 264 
 265     data_len = pkt->data_len;
 266     if (data_len <= 19) {
 267         return;
 268     }
 269 
 270     /* Get IP Version               Byte 1 of IP Header */
 271     payload = pkt->payload;
 272     version = payload[0] & 0xF0;
 273     version >>= 4;
 274 
 275     /* Get IP Header length         Byte 2 of IP Header
 276      * Header length is usually 20, or 5 32-bit words */
 277     ip_header_length = payload[0] & 0x0F;
 278     header_size = ip_header_length * 4;
 279 
 280     if (data_len < header_size) {
 281         return;
 282     }
 283 
 284     switch (version) {
 285 #ifdef USE_IPV6
 286         case 4:
 287             src->type = PNFQ_ADDR_TYPE_IPV4;
 288             dst->type = PNFQ_ADDR_TYPE_IPV4;
 289             ipv4_pkt_info(payload, &src->addr.ipv4, &dst->addr.ipv4);
 290             break;
 291         case 6:
 292             src->type = PNFQ_ADDR_TYPE_IPV6;
 293             dst->type = PNFQ_ADDR_TYPE_IPV6;
 294             ipv6_pkt_info(payload, &src->addr.ipv6, &dst->addr.ipv6);
 295             break;
 296 #else
 297         case 4:
 298             ipv4_pkt_info(payload, src, dst);
 299             break;
 300 #endif
 301         default:
 302             break;
 303     }
 304 }
 305 
 306 /*
 307  * Packet Filtering Binary Tree Manipulation Routines
 308  */
 309 static inline void pnfq_addr_add_ipv4(uint32_t addr, uint32_t mask, pnfq_check_result_t action) {
 310     struct pnfq_check_node *currnode;
 311     uint32_t bitval, maskval;
 312     int bit;
 313 
 314     assert(action != PNFQ_CHECK_DEFAULT);
 315 
 316     currnode = &pnfq_check_tree_v4;
 317 
 318     for (bit = -1; bit < 33; bit++) {
 319         if (currnode == NULL) {
 320             break;
 321         }
 322 
 323         bitval = (addr >> (32 - bit - 1)) & 1;
 324 
 325         /*
 326          * Always take the same route from the HEAD (-1'th) bit.
 327          */
 328         if (bit == -1) {
 329             bitval = 0;
 330         }
 331 
 332         maskval = (mask >> (32 - bit - 1)) & 1;
 333         if ((maskval == 0 && bit != -1) || bit == 32) {
 334             currnode->action = action;
 335             break;
 336         }
 337 
 338         if (bitval == 0) {
 339             if (currnode->_zero == NULL) {
 340                 currnode->_zero = malloc(sizeof(*currnode->_zero));
 341                 currnode->_zero->action = PNFQ_CHECK_CONTINUE;
 342                 currnode->_zero->_zero = NULL;
 343                 currnode->_zero->_one = NULL;
 344             }
 345             currnode = currnode->_zero;
 346         } else {
 347             if (currnode->_one == NULL) {
 348                 currnode->_one = malloc(sizeof(*currnode->_one));
 349                 currnode->_one->action = PNFQ_CHECK_CONTINUE;
 350                 currnode->_one->_zero = NULL;
 351                 currnode->_one->_one = NULL;
 352             }
 353             currnode = currnode->_one;
 354         }
 355     }
 356 
 357     return;
 358 }
 359 static inline void pnfq_addr_del_ipv4(uint32_t addr, uint32_t mask) {
 360     pnfq_addr_add_ipv4(addr, mask, PNFQ_CHECK_CONTINUE);
 361 }
 362 static inline pnfq_check_result_t pnfq_addr_check_ipv4(uint32_t addr) {
 363     pnfq_check_result_t retval = PNFQ_CHECK_DEFAULT;
 364     struct pnfq_check_node *currnode;
 365     uint32_t bitval;
 366     int bit;
 367 
 368     if (addr == 0) {
 369         return(PNFQ_CHECK_DROP);
 370     }
 371 
 372     currnode = &pnfq_check_tree_v4;
 373 
 374     for (bit = -1; bit < 33; bit++) {
 375         if (currnode == NULL) {
 376             break;
 377         }
 378 
 379         bitval = (addr >> (32 - bit - 1)) & 1;
 380 
 381         /*
 382          * Always take the same route from the HEAD (-1'th) bit.
 383          */
 384         if (bit == -1) {
 385             bitval = 0;
 386         }
 387 
 388         if (currnode->action != PNFQ_CHECK_CONTINUE) {
 389             retval = currnode->action;
 390         }
 391 
 392         if (bitval == 0) {
 393             currnode = currnode->_zero;
 394         } else {
 395             currnode = currnode->_one;
 396         }
 397     }
 398 
 399     return(retval);
 400 }
 401 #ifdef USE_IPV6
 402 static inline void pnfq_addr_add_ipv6(uint128_t addr, uint128_t mask, pnfq_check_result_t action) {
 403     struct pnfq_check_node *currnode;
 404     uint32_t bitval, maskval;
 405     int bit;
 406 
 407     assert(action != PNFQ_CHECK_DEFAULT);
 408 
 409     currnode = &pnfq_check_tree_v6;
 410 
 411     for (bit = -1; bit < 129; bit++) {
 412         if (currnode == NULL) {
 413             break;
 414         }
 415 
 416         bitval = (addr.a[bit / 32] >> (32 - (bit % 32) - 1)) & 1;
 417 
 418         /*
 419          * Always take the same route from the HEAD (-1'th) bit.
 420          */
 421         if (bit == -1) {
 422             bitval = 0;
 423         }
 424 
 425         maskval = (mask.a[bit / 32] >> (32 - (bit % 32) - 1)) & 1;
 426         if ((maskval == 0 && bit != -1) || bit == 128) {
 427             currnode->action = action;
 428             break;
 429         }
 430 
 431         if (bitval == 0) {
 432             if (currnode->_zero == NULL) {
 433                 currnode->_zero = malloc(sizeof(*currnode->_zero));
 434                 currnode->_zero->action = PNFQ_CHECK_CONTINUE;
 435                 currnode->_zero->_zero = NULL;
 436                 currnode->_zero->_one = NULL;
 437             }
 438             currnode = currnode->_zero;
 439         } else {
 440             if (currnode->_one == NULL) {
 441                 currnode->_one = malloc(sizeof(*currnode->_one));
 442                 currnode->_one->action = PNFQ_CHECK_CONTINUE;
 443                 currnode->_one->_zero = NULL;
 444                 currnode->_one->_one = NULL;
 445             }
 446             currnode = currnode->_one;
 447         }
 448     }
 449 
 450     return;
 451 }
 452 static inline void pnfq_addr_del_ipv6(uint128_t addr, uint128_t mask) {
 453     pnfq_addr_add_ipv6(addr, mask, PNFQ_CHECK_CONTINUE);
 454     return;
 455 }
 456 static inline pnfq_check_result_t pnfq_addr_check_ipv6(uint128_t addr) {
 457     pnfq_check_result_t retval = PNFQ_CHECK_DEFAULT;
 458     struct pnfq_check_node *currnode;
 459     uint32_t bitval;
 460     int bit;
 461 
 462     currnode = &pnfq_check_tree_v6;
 463 
 464     for (bit = -1; bit < 129; bit++) {
 465         if (currnode == NULL) {
 466             break;
 467         }
 468 
 469         bitval = (addr.a[bit / 32] >> (32 - (bit % 32) - 1)) & 1;
 470 
 471         /*
 472          * Always take the same route from the HEAD (-1'th) bit.
 473          */
 474         if (bit == -1) {
 475             bitval = 0;
 476         }
 477 
 478         if (currnode->action != PNFQ_CHECK_CONTINUE) {
 479             retval = currnode->action;
 480         }
 481 
 482         if (bitval == 0) {
 483             currnode = currnode->_zero;
 484         } else {
 485             currnode = currnode->_one;
 486         }
 487     }
 488 
 489     return(retval);
 490     return(retval);
 491 }
 492 static inline void pnfq_addr_add(pnfq_addr_t addr, pnfq_addr_t mask, pnfq_check_result_t action) {
 493     assert (addr.type == mask.type);
 494 
 495     switch (addr.type) {
 496         case PNFQ_ADDR_TYPE_IPV4:
 497             pnfq_addr_add_ipv4(addr.addr.ipv4, mask.addr.ipv4, action);
 498             break;
 499         case PNFQ_ADDR_TYPE_IPV6:
 500             pnfq_addr_add_ipv6(addr.addr.ipv6, mask.addr.ipv6, action);
 501             break;
 502         case PNFQ_ADDR_TYPE_UNKNOWN:
 503             return;
 504     }
 505 
 506     return;
 507 }
 508 static inline void pnfq_addr_del(pnfq_addr_t addr, pnfq_addr_t mask) {
 509     assert (addr.type == mask.type);
 510 
 511     switch (addr.type) {
 512         case PNFQ_ADDR_TYPE_IPV4:
 513             pnfq_addr_del_ipv4(addr.addr.ipv4, mask.addr.ipv4);
 514             break;
 515         case PNFQ_ADDR_TYPE_IPV6:
 516             pnfq_addr_del_ipv6(addr.addr.ipv6, mask.addr.ipv6);
 517             break;
 518         case PNFQ_ADDR_TYPE_UNKNOWN:
 519             break;
 520     }
 521 
 522     return;
 523 }
 524 static inline pnfq_check_result_t pnfq_addr_check(pnfq_addr_t addr) {
 525     switch (addr.type) {
 526         case PNFQ_ADDR_TYPE_IPV4:
 527             return(pnfq_addr_check_ipv4(addr.addr.ipv4));
 528         case PNFQ_ADDR_TYPE_IPV6:
 529             return(pnfq_addr_check_ipv6(addr.addr.ipv6));
 530         case PNFQ_ADDR_TYPE_UNKNOWN:
 531             return(NF_DROP);
 532     }
 533 
 534     return(PNFQ_CHECK_DROP);
 535 }
 536 #else
 537 #define pnfq_addr_add(x, y, z) pnfq_addr_add_ipv4(x, y, z)
 538 #define pnfq_addr_del(x, y) pnfq_addr_del_ipv4(x, y)
 539 #define pnfq_addr_check(x) pnfq_addr_check_ipv4(x)
 540 #endif
 541 
 542 /*
 543  * TCL Interface Routines
 544  */
 545 int pnfq_addr_add_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) {
 546     pnfq_check_result_t action_val;
 547     pnfq_addr_t addr_val, mask_val;
 548     char *addr, *mask, *action;
 549 
 550     if (argc != 4) {
 551         return(TCL_ERROR);
 552     }
 553 
 554     addr = argv[1];
 555     mask = argv[2];
 556     action = argv[3];
 557 
 558     if (strcasecmp(action, "accept") == 0) {
 559         action_val = PNFQ_CHECK_ACCEPT;
 560     } else if (strcasecmp(action, "drop") == 0) {
 561         action_val = PNFQ_CHECK_DROP;
 562     } else {
 563         return(TCL_ERROR);
 564     }
 565 
 566     addr_val = str_to_ip(addr);
 567     mask_val = str_to_ip(mask);
 568 
 569 #ifdef USE_IPV6
 570     if (addr_val.type == PNFQ_ADDR_TYPE_UNKNOWN || mask_val.type == PNFQ_ADDR_TYPE_UNKNOWN) {
 571 #else
 572     if (addr_val == 0 || mask_val == 0) {
 573 #endif
 574 #ifndef NDEBUG
 575         printf("Invalid address specified from Tcl: %s (%s)\n", addr, mask);
 576 #endif
 577         return(TCL_ERROR);
 578     }
 579     
 580 
 581     pnfq_addr_add(addr_val, mask_val, action_val);
 582 
 583     return(TCL_OK);
 584 }
 585 int pnfq_addr_del_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) {
 586     pnfq_addr_t addr_val, mask_val;
 587     char *addr, *mask;
 588 
 589     if (argc != 3) {
 590         return(TCL_ERROR);
 591     }
 592 
 593     addr = argv[1];
 594     mask = argv[2];
 595 
 596     addr_val = str_to_ip(addr);
 597     mask_val = str_to_ip(mask);
 598 
 599 #ifdef USE_IPV6
 600     if (addr_val.type == PNFQ_ADDR_TYPE_UNKNOWN || mask_val.type == PNFQ_ADDR_TYPE_UNKNOWN) {
 601 #else
 602     if (addr_val == 0 || mask_val == 0) {
 603 #endif
 604 #ifndef NDEBUG
 605         printf("Invalid address specified from Tcl: %s (%s)\n", addr, mask);
 606 #endif
 607         return(TCL_ERROR);
 608     }
 609     
 610     pnfq_addr_del(addr_val, mask_val);
 611 
 612     return(TCL_OK);
 613 }
 614 void pnfq_addr_get_tcl_loop(Tcl_Interp *interp, char *var, struct pnfq_check_node *node, int bit, uint32_t bitval) {
 615 #if !defined(USE_TCL_PKT_HANDLER) || !defined(USE_THREADED_TCL)
 616     static
 617 #endif
 618     char valbuf[256], ipbuf[256], maskbuf[256];
 619     uint32_t maskval = 0;
 620     int i;
 621 
 622     if (node->action != PNFQ_CHECK_CONTINUE && bit != -1) {
 623         for (i = 0; i < bit; i++) {
 624             maskval |= 1;
 625             maskval <<= 1;
 626         }
 627         if (bit == 32) {
 628             maskval |= 1;
 629         } else {
 630             maskval <<= (32 - bit - 1);
 631         }
 632 
 633         snprintf(valbuf, sizeof(valbuf), "%s %s %s",
 634                  ipv4_to_str(bitval, ipbuf, sizeof(ipbuf)),
 635                  ipv4_to_str(maskval, maskbuf, sizeof(maskbuf)),
 636                  (node->action == PNFQ_CHECK_ACCEPT) ? "ACCEPT" : "DROP"
 637         );
 638 
 639         Tcl_SetVar(interp, var, valbuf, TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
 640     }
 641 
 642     if (node->_zero) {
 643         pnfq_addr_get_tcl_loop(interp, var, node->_zero, bit + 1, bitval);
 644     }
 645     if (node->_one) {
 646         bitval |= 1 << (32 - bit - 1);
 647         pnfq_addr_get_tcl_loop(interp, var, node->_one, bit + 1, bitval);
 648     }
 649 }
 650 int pnfq_addr_get_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) {
 651     char *var;
 652 
 653     if (argc != 2) {
 654         return(TCL_ERROR);
 655     }
 656 
 657     var = argv[1];
 658 
 659     Tcl_SetVar(interp, var, "", 0);
 660 
 661     pnfq_addr_get_tcl_loop(interp, var, &pnfq_check_tree_v4, -1, 0);
 662 
 663     return(TCL_OK);
 664 }
 665 
 666 
 667 /*
 668  * Worker Thread Loop:  Packet Processing Loop
 669  */
 670 void *pnfq_handle_packets(void *arg) {
 671     unsigned char pktbuf[PNFQ_PKT_BUF_LEN];
 672     pnfq_check_result_t s_verdict, d_verdict, verdict;
 673     pnfq_addr_t srcaddr, dstaddr;
 674     ipq_packet_msg_t *pkt;
 675     ssize_t ipqr_ret;
 676     struct pnfq_thread_info *tinfo;
 677     struct ipq_handle *handle;
 678     int ipqmt_msgtype;
 679     int error_count = 0;
 680 #if !defined(NDEBUG) || defined(USE_TCL_PKT_HANDLER)
 681     char s_ipstrbuf[256], d_ipstrbuf[256];
 682 #endif
 683 #ifdef USE_TCL_PKT_HANDLER
 684 #ifndef USE_THREADED_TCL
 685     pthread_mutex_t *tcl_mutex;
 686 #endif
 687     Tcl_Interp *interp;
 688     CONST char *tcl_retstr;
 689     const char *verdict_str;
 690     char cmdbuf[8192];
 691     int tcl_eval_ret;
 692 #endif
 693 
 694     tinfo = arg;
 695 
 696     handle = tinfo->handle;
 697 
 698 #ifdef USE_TCL_PKT_HANDLER
 699     if (tinfo->tcl_scpdir) {
 700 #ifndef USE_THREADED_TCL
 701         tcl_mutex = tinfo->tcl_mutex;
 702 
 703         pthread_mutex_lock(tcl_mutex);
 704 #endif
 705 
 706         interp = Tcl_CreateInterp();
 707         Tcl_Init(interp);
 708 
 709         Tcl_CreateCommand(interp, "pnfq_add", (Tcl_CmdProc *) pnfq_addr_add_tcl, NULL, NULL);
 710         Tcl_CreateCommand(interp, "pnfq_delete", (Tcl_CmdProc *) pnfq_addr_del_tcl, NULL, NULL); 
 711         Tcl_CreateCommand(interp, "pnfq_get", (Tcl_CmdProc *) pnfq_addr_get_tcl, NULL, NULL);
 712 
 713         Tcl_Eval(interp, "proc pnfq_handle_pkt args { return [lindex $args 0] }");
 714 
 715         snprintf(cmdbuf, sizeof(cmdbuf), "source %s/worker.tcl", tinfo->tcl_scpdir);
 716         Tcl_Eval(interp, cmdbuf);
 717 
 718 #ifndef USE_THREADED_TCL
 719         pthread_mutex_unlock(tcl_mutex);
 720 #endif
 721     } else {
 722         interp = NULL;
 723     }
 724 #endif
 725 
 726     while (1) {
 727         if (error_count > PNFQ_MAX_READ_ERRORS) {
 728             break;
 729         }
 730 
 731         ipqr_ret = ipq_read(handle, pktbuf, sizeof(pktbuf), 0);
 732 
 733         if (ipqr_ret <= 0) {
 734             fprintf(stderr, "ipq_read warning: %s\n", ipq_errstr());
 735             error_count++;
 736             continue;
 737         }
 738 
 739         ipqmt_msgtype = ipq_message_type(pktbuf);
 740         if (ipqmt_msgtype == NLMSG_ERROR) {
 741             fprintf(stderr, "Netlink transport terminal warning: %s\n", strerror(ipq_get_msgerr(pktbuf)));
 742 
 743             break;
 744         } else if (ipqmt_msgtype != IPQM_PACKET) {
 745             fprintf(stderr, "Unknown message warning: %i\n", ipqmt_msgtype);
 746 
 747             error_count++;
 748 
 749             continue;
 750         }
 751 
 752         pkt = ipq_get_packet(pktbuf);
 753         if (!pkt) {
 754             continue;
 755         }
 756 
 757         error_count = 0;
 758 
 759         pkt_info(pkt, &srcaddr, &dstaddr);
 760 
 761         s_verdict = pnfq_addr_check(srcaddr);
 762         d_verdict = pnfq_addr_check(dstaddr);
 763 
 764         if (s_verdict == PNFQ_CHECK_DROP || d_verdict == PNFQ_CHECK_DROP) {
 765             verdict = PNFQ_CHECK_DROP;
 766         } else if (s_verdict == PNFQ_CHECK_ACCEPT || d_verdict == PNFQ_CHECK_ACCEPT) {
 767             verdict = PNFQ_CHECK_ACCEPT;
 768         } else if (s_verdict == d_verdict) {
 769             verdict = s_verdict;
 770         } else {
 771             /* What should we do here ? */
 772             verdict = s_verdict;
 773         }
 774 #ifndef NDEBUG
 775         switch (verdict) {
 776             case PNFQ_CHECK_ACCEPT:
 777                 printf("[%i] Accepting packet from %s to %s\n",
 778                        tinfo->thread_id,
 779                        ip_to_str(srcaddr, s_ipstrbuf, sizeof(s_ipstrbuf)),
 780                        ip_to_str(dstaddr, d_ipstrbuf, sizeof(d_ipstrbuf))
 781                 );
 782                 break;
 783             case PNFQ_CHECK_DROP:
 784                 printf("[%i] Dropping packet from %s to %s\n",
 785                        tinfo->thread_id,
 786                        ip_to_str(srcaddr, s_ipstrbuf, sizeof(s_ipstrbuf)),
 787                        ip_to_str(dstaddr, d_ipstrbuf, sizeof(d_ipstrbuf))
 788                 );
 789                 break;
 790             case PNFQ_CHECK_DEFAULT:
 791                 printf("[%i] No match for packet from %s to %s\n",
 792                        tinfo->thread_id,
 793                        ip_to_str(srcaddr, s_ipstrbuf, sizeof(s_ipstrbuf)),
 794                        ip_to_str(dstaddr, d_ipstrbuf, sizeof(d_ipstrbuf))
 795                 );
 796                 break;
 797             case PNFQ_CHECK_CONTINUE:
 798                 printf("[%i] Weird packet from %s to %s\n",
 799                        tinfo->thread_id,
 800                        ip_to_str(srcaddr, s_ipstrbuf, sizeof(s_ipstrbuf)),
 801                        ip_to_str(dstaddr, d_ipstrbuf, sizeof(d_ipstrbuf))
 802                 );
 803                 break;
 804         }
 805 #endif
 806 
 807 #ifdef USE_TCL_PKT_HANDLER
 808         if (interp) {
 809             switch (verdict) {
 810                 case PNFQ_CHECK_ACCEPT:
 811                     verdict_str = "ACCEPT";
 812                     break;
 813                 case PNFQ_CHECK_DROP:
 814                     verdict_str = "DROP";
 815                     break;
 816                 case PNFQ_CHECK_DEFAULT:
 817                     verdict_str = "DEFAULT";
 818                     break;
 819                 case PNFQ_CHECK_CONTINUE:
 820                     verdict_str = "ERROR";
 821                     break;
 822             }
 823             /*
 824              * Call the Tcl procedure "pnfq_handle_pkt" with three args:
 825              *     verdict    Existing verdict:
 826              *                      ACCEPT
 827              *                      DROP
 828              *                      DEFAULT
 829              *     src        Packet SRC IP address (dotted quad format)
 830              *     dst        Packet DST IP address (dotted quad format)
 831              * Return value from the procedure should be "1" (for ACCEPT) or "0" (for DROP)
 832              */
 833             snprintf(cmdbuf, sizeof(cmdbuf), "pnfq_handle_pkt %s %s %s",
 834                      verdict_str,
 835                      ip_to_str(srcaddr, s_ipstrbuf, sizeof(s_ipstrbuf)),
 836                      ip_to_str(dstaddr, d_ipstrbuf, sizeof(d_ipstrbuf))
 837             );
 838 
 839 #ifndef USE_THREADED_TCL
 840             pthread_mutex_lock(tcl_mutex);
 841 #endif
 842 
 843             tcl_eval_ret = Tcl_Eval(interp, cmdbuf);
 844             if (tcl_eval_ret == TCL_OK) {
 845                 tcl_retstr = Tcl_GetStringResult(interp);
 846             } else {
 847                 tcl_retstr = NULL;
 848             }
 849 
 850 #ifndef USE_THREADED_TCL
 851             pthread_mutex_unlock(tcl_mutex);
 852 #endif
 853 
 854             if (tcl_retstr != NULL) {
 855                 if (tcl_retstr[0] == 'A') {
 856 #ifndef NDEBUG
 857                     printf("Setting Verdict from pnfq_handle_pkt: %s (ACCEPT)\n", tcl_retstr);
 858 #endif
 859                     verdict = PNFQ_CHECK_ACCEPT;
 860                 } else if (tcl_retstr[0] == 'D' && tcl_retstr[1] == 'E') {
 861 #ifndef NDEBUG
 862                     printf("Setting Verdict from pnfq_handle_pkt: %s (DEFAULT)\n", tcl_retstr);
 863 #endif
 864                     verdict = PNFQ_CHECK_DEFAULT;
 865                 } else {
 866 #ifndef NDEBUG
 867                     printf("Setting Verdict from pnfq_handle_pkt: %s (DROP)\n", tcl_retstr);
 868 #endif
 869                     verdict = PNFQ_CHECK_DROP;
 870                 }
 871             }
 872         }
 873 #endif
 874 
 875         /*
 876          * POLICY:  Unmatched packets are accepted
 877          */
 878         if (verdict == PNFQ_CHECK_DEFAULT) {
 879             verdict = PNFQ_CHECK_ACCEPT;
 880         }
 881         ipq_set_verdict(handle, pkt->packet_id, verdict, 0, NULL);
 882     }
 883 
 884     return(NULL);
 885 }
 886 
 887 /*
 888  * Program Entry Point and Tcl Event Loop
 889  */
 890 int main(int argc, char **argv) {
 891     Tcl_Interp *main_interp = NULL;
 892     pthread_t *threads = NULL;
 893 #ifdef USE_TCL_PKT_HANDLER
 894 #ifndef USE_THREADED_TCL
 895     pthread_mutex_t tcl_mutex = PTHREAD_MUTEX_INITIALIZER;
 896 #endif
 897 #endif
 898     struct pnfq_thread_info *tinfo = NULL;
 899     struct ipq_handle *handle_v4;
 900 #ifdef USE_IPV6
 901     struct ipq_handle *handle_v6;
 902 #endif
 903 #ifndef USE_THREADED_TCL
 904     struct timespec waittime;
 905 #endif
 906     char cmdbuf[8192], *scpdir = NULL;
 907     int num_threads = PNFQ_NUM_THREADS;
 908     int tcl_eval_ret;
 909     int ipqsm_ret;
 910     int i, ch;
 911 
 912 #ifdef PNFQ_SCRIPTDIR
 913     scpdir = PNFQ_SCRIPTDIR;
 914 #endif
 915 
 916     while ((ch = getopt(argc, argv, "VhclT:t:")) != -1) {
 917         switch (ch) {
 918             case 'l':
 919 #ifndef NDEBUG
 920                 printf("Locking all pages to physical RAM.\n");
 921 #endif
 922                 if (mlockall(MCL_FUTURE) != 0) {
 923                     perror("mlockall");
 924                     fprintf(stderr, "Unable to lock memory pages, aborting.\n");
 925                     return(EXIT_FAILURE);
 926                 }
 927                 break;
 928             case 't':
 929                 num_threads = atoi(optarg);
 930                 if (num_threads <= 1 || num_threads > 128) {
 931                     fprintf(stderr, "Invalid number of threads (%i), min: 2, max: 128, aborting.\n", num_threads);
 932                     return(EXIT_FAILURE);
 933                 }
 934                 break;
 935             case 'T':
 936                 /* TCL Script Dir */
 937                 scpdir = optarg;
 938                 break;
 939             case 'c':
 940                 printf("PNFQ Version %s", PACKAGE_VERSION);
 941 #ifdef NDEBUG
 942                 printf("-rel");
 943 #else
 944                 printf("-dbg");
 945 #endif
 946 #ifdef PNFQ_PROFILING
 947                 printf("-prof");
 948 #endif
 949 #ifdef PNFQ_EXTRAVERS
 950                 printf("-%s", PNFQ_EXTRAVERS);
 951 #endif
 952                 printf(" was built at %s on %s using:\n", __TIME__, __DATE__);
 953                 printf("  $ ./configure");
 954 #ifdef PNFQ_SCRIPTDIR
 955                 printf(" --datadir=%s/../", PNFQ_SCRIPTDIR);
 956 #endif
 957 #ifdef NDEBUG
 958                 printf(" --without-debug");
 959 #else
 960                 printf(" --with-debug");
 961 #endif
 962 #ifdef PNFQ_PROFILING
 963                 printf(" --with-profile");
 964 #else
 965                 printf(" --without-profile");
 966 #endif
 967 #ifdef TCLLIBDIR
 968                 printf(" --with-tcllibdir=\"%s\"", TCLLIBDIR);
 969 #endif
 970 #ifdef TCLINCDIR
 971                 printf(" --with-tclincdir=\"%s\"", TCLINCDIR);
 972 #endif
 973 #ifdef USE_TCL_PKT_HANDLER
 974                 printf(" --with-tclpkt");
 975 #else
 976                 printf(" --without-tclpkt");
 977 #endif
 978 #ifdef USE_IPV6
 979                 printf(" --with-ipv6");
 980 #else
 981                 printf(" --without-ipv6");
 982 #endif
 983                 printf("\n");
 984                 return(EXIT_SUCCESS);
 985             case 'V':
 986                 printf("PNFQ Version %s", PACKAGE_VERSION);
 987 #ifdef NDEBUG
 988                 printf("-rel");
 989 #else
 990                 printf("-dbg");
 991 #endif
 992 #ifdef PNFQ_PROFILING
 993                 printf("-prof");
 994 #endif
 995 #ifdef PNFQ_EXTRAVERS
 996                 printf("-%s", PNFQ_EXTRAVERS);
 997 #endif
 998 #ifdef USE_TCL_PKT_HANDLER
 999                 printf(" [TCLPKT]");
1000 #endif
1001 #ifdef USE_THREADED_TCL
1002                 printf(" [TCLTHREADED]");
1003 #else
1004                 printf(" [TCLUNTHREADED]");
1005 #endif
1006 #ifdef USE_IPV6
1007                 printf(" [IPV6]");
1008 #endif
1009                 printf(" [PKTBUFLEN=%i]", PNFQ_PKT_BUF_LEN);
1010                 printf(" [DEFTHREADS=%i]\n", PNFQ_NUM_THREADS);
1011                 return(EXIT_SUCCESS);
1012             case 'h':
1013                 print_help();
1014                 return(EXIT_SUCCESS);
1015             case ':':
1016             case '?':
1017                 return(EXIT_FAILURE);
1018                 break;
1019         }
1020     }
1021 
1022     /*
1023      * Verify that the "ip_queue" module is loaded
1024      */
1025     if (access("/proc/net/ip_queue", F_OK) != 0) {
1026         system("/sbin/modprobe ip_queue");
1027     }
1028     if (access("/proc/net/ip_queue", F_OK) != 0) {
1029         fprintf(stderr, "Please make sure ip_queue is installed, or that you have\n");
1030         fprintf(stderr, "compiled a kernel with the Netfilter QUEUE target built in.\n");
1031         fprintf(stderr, "Aborting.\n");
1032 
1033         exit(EXIT_FAILURE);
1034     }
1035 
1036 #ifdef USE_IPV6
1037     if (access("/proc/net/ip6_queue", F_OK) != 0) {
1038         system("/sbin/modprobe ip6_queue");
1039     }
1040     if (access("/proc/net/ip6_queue", F_OK) != 0) {
1041         fprintf(stderr, "Please make sure ip6_queue is installed, or that you have\n");
1042         fprintf(stderr, "compiled a kernel with the Netfilter QUEUE target built in.\n");
1043         fprintf(stderr, "Aborting.\n");
1044 
1045         exit(EXIT_FAILURE);
1046     }
1047 #endif
1048 
1049     threads = malloc(sizeof(*threads) * num_threads);
1050     if (threads == NULL) {
1051         perror("malloc");
1052         exit(EXIT_FAILURE);
1053     }
1054 
1055     /*
1056      * Create IPQ Interface Handle
1057      */
1058     handle_v4 = ipq_create_handle(0, PF_INET);
1059     if (handle_v4 == NULL) {
1060         fprintf(stderr, "Error creating IPQ Handler.  Aborting.\n");
1061         exit(EXIT_FAILURE);
1062     }
1063 
1064 #ifdef USE_IPV6
1065     handle_v6 = ipq_create_handle(0, PF_INET6);
1066     if (handle_v6 == NULL) {
1067         fprintf(stderr, "[ipv6] Error creating IPQ Handler.  Aborting.\n");
1068         exit(EXIT_FAILURE);
1069     }
1070 #endif
1071 
1072     /*
1073      * Set IPQ Interface Handle to Copy mode (so we can get the IP address
1074      * from the packets)
1075      */
1076     ipqsm_ret = ipq_set_mode(handle_v4, IPQ_COPY_PACKET, PNFQ_PKT_BUF_LEN);
1077     if (ipqsm_ret == -1) {
1078         fprintf(stderr, "ipq_set_mode error: %s\n", ipq_errstr());
1079         if (errno == 111) {
1080             fprintf(stderr, "Try loading the \"ip_queue\" module\n");
1081         }
1082 
1083         fprintf(stderr, "Aborting.\n");
1084 
1085         ipq_destroy_handle(handle_v4);
1086 
1087         exit(EXIT_FAILURE);
1088     }
1089 
1090 #ifdef USE_IPV6
1091     ipqsm_ret = ipq_set_mode(handle_v6, IPQ_COPY_PACKET, PNFQ_PKT_BUF_LEN);
1092     if (ipqsm_ret == -1) {
1093         fprintf(stderr, "[ipv6] ipq_set_mode error: %s\n", ipq_errstr());
1094         if (errno == 111) {
1095             fprintf(stderr, "[ipv6] Try loading the \"ip6_queue\" module\n");
1096         }
1097 
1098         fprintf(stderr, "[ipv6] Aborting.\n");
1099 
1100         ipq_destroy_handle(handle_v4);
1101         ipq_destroy_handle(handle_v6);
1102 
1103         exit(EXIT_FAILURE);
1104     }
1105 #endif
1106 
1107     /*
1108      * Create resources for each worker thread
1109      */
1110     tinfo = malloc(sizeof(*tinfo) * num_threads);
1111     if (tinfo == NULL) {
1112         perror("malloc");
1113 
1114         ipq_destroy_handle(handle_v4);
1115 #ifdef USE_IPV6
1116         ipq_destroy_handle(handle_v6);
1117 #endif
1118 
1119         exit(EXIT_FAILURE);
1120     }
1121 
1122 #ifdef USE_TCL_PKT_HANDLER
1123 #ifndef USE_THREADED_TCL
1124     pthread_mutex_init(&tcl_mutex, NULL);
1125 #endif
1126 #endif
1127 
1128     /*
1129      * Initialize resources for each worker thread
1130      */
1131     for (i = 0; i < num_threads; i++) {
1132         tinfo[i].thread_id = i;
1133 #ifndef USE_IPV6
1134         tinfo[i].handle = handle_v4;
1135 #else
1136         if ((i % 2) == 0) {
1137             tinfo[i].handle = handle_v4;
1138         } else {
1139             tinfo[i].handle = handle_v6;
1140         }
1141 #endif
1142 
1143 #ifdef USE_TCL_PKT_HANDLER
1144         tinfo[i].tcl_scpdir = scpdir;
1145 #ifndef USE_THREADED_TCL
1146         tinfo[i].tcl_mutex = &tcl_mutex;
1147 #endif
1148 #endif
1149     }
1150 
1151     /*
1152      * Create each worker thread
1153      */
1154     for (i = 0; i < num_threads; i++) {
1155         pthread_create(&threads[i], NULL, pnfq_handle_packets, &tinfo[i]);
1156     }
1157 
1158     /*
1159      * Create the main interface Tcl Interpreter
1160      */
1161     if (scpdir) {
1162 #ifdef USE_TCL_PKT_HANDLER
1163 #ifndef USE_THREADED_TCL
1164         pthread_mutex_lock(&tcl_mutex);
1165 #endif
1166 #endif
1167 
1168         main_interp = Tcl_CreateInterp();
1169         Tcl_Init(main_interp);
1170 
1171         Tcl_CreateCommand(main_interp, "pnfq_add", (Tcl_CmdProc *) pnfq_addr_add_tcl, NULL, NULL);
1172         Tcl_CreateCommand(main_interp, "pnfq_delete", (Tcl_CmdProc *) pnfq_addr_del_tcl, NULL, NULL); 
1173         Tcl_CreateCommand(main_interp, "pnfq_get", (Tcl_CmdProc *) pnfq_addr_get_tcl, NULL, NULL);
1174 
1175         snprintf(cmdbuf, sizeof(cmdbuf), "source %s/feeder.tcl", scpdir);
1176         tcl_eval_ret = Tcl_Eval(main_interp, cmdbuf);
1177         if (tcl_eval_ret != TCL_OK) {
1178             printf("Error While Loading %s/feeder.tcl: %s", scpdir, Tcl_GetVar(main_interp, "errorInfo",
	TCL_GLOBAL_ONLY));
1179         }
1180 
1181 #ifdef USE_TCL_PKT_HANDLER
1182 #ifndef USE_THREADED_TCL
1183         pthread_mutex_unlock(&tcl_mutex);
1184 #endif
1185 #endif
1186     } else {
1187         main_interp = NULL;
1188     }
1189 
1190     while (1) {
1191 #ifdef USE_TCL_PKT_HANDLER
1192 #ifndef USE_THREADED_TCL
1193         pthread_mutex_lock(&tcl_mutex);
1194 #endif
1195 #endif
1196 
1197 #ifndef USE_THREADED_TCL
1198         /*
1199          * If using an Unthreaded Tcl Build:
1200          *     a. We can't wait inside the Tcl Library when using a
1201          *        TCL_PKT_HANDLER because then no other threads can
1202          *        invoke their handlers.
1203          *     b. The Tcl_DoOneEvent() doesn't wait forever anyway,
1204          *        resulting in a busy loop.
1205          */
1206         Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
1207 #else
1208         Tcl_DoOneEvent(TCL_ALL_EVENTS);
1209 #endif
1210 
1211 #ifdef USE_TCL_PKT_HANDLER
1212 #ifndef USE_THREADED_TCL
1213         pthread_mutex_unlock(&tcl_mutex);
1214 #endif
1215 #endif
1216 
1217 #ifndef USE_THREADED_TCL
1218         waittime.tv_sec = 5;
1219         waittime.tv_nsec = 0;
1220         nanosleep(&waittime, NULL);
1221 #endif
1222     }
1223 
1224     ipq_destroy_handle(handle_v4);
1225 #ifdef USE_IPV6
1226     ipq_destroy_handle(handle_v6);
1227 #endif
1228 
1229     return(EXIT_FAILURE);
1230 }
4556571 [rkeene@sledge /home/rkeene/tmp/pnfq-0.1.15]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2006-12-11 18:18:14