LTP GCOV extension - code coverage report
Current view: directory - and-httpd/src - and-sock-filter.c
Test: And-httpd coverage
Date: 2006-09-11 Instrumented lines: 162
Code covered: 67.9 % Executed lines: 110

       1                 : /* parses input from "tcpdump -dd" outputs raw filter,
       2                 :  * Ie. sock filter compiler. Why can't tcpdump do this :( */
       3                 : #include "ex_utils.h"
       4                 : #include <limits.h>
       5                 : 
       6                 : #define CONF_USE_MMAP_DEF FALSE
       7                 : 
       8                 : /* not in glibc... */
       9                 : struct sock_filter
      10                 : {
      11                 :  uint16_t   code;   /* Actual filter code */
      12                 :  uint8_t    jt;     /* Jump true */
      13                 :  uint8_t    jf;     /* Jump false */
      14                 :  uint32_t   k;      /* Generic multiuse field */
      15                 : };
      16                 : 
      17                 : /* not needed here ... see ex_httpd etc. */
      18                 : struct sock_fprog
      19                 : {
      20                 :  unsigned short len;    /* Number of filter blocks */
      21                 :  struct sock_filter *filter;
      22                 : };
      23                 : 
      24                 : /* is the cstr a prefix of the vstr */
      25                 : #define VPREFIX(vstr, p, l, cstr)                                       \
      26                 :     (((l) >= strlen(cstr)) && vstr_cmp_bod_cstr_eq(vstr, p, l, cstr))
      27                 : 
      28                 : 
      29                 : #define SOCK_FILTER_OP(x, y, j, k) else if (VPREFIX(s2, pos, len, x))   \
      30                 :       do {                                                              \
      31                 :         *num_len = strlen(x);                                           \
      32                 :         *js = (j);                                                      \
      33                 :         *ks = (k);                                                      \
      34                 :         return (y);                                                     \
      35                 :       } while (FALSE)
      36                 : 
      37                 : /* add ops with X */
      38                 : #define SOCK_FILTER_OP_PX(x, y, j)                 \
      39                 :     SOCK_FILTER_OP(x "x", y | 0x8, j, FALSE);      \
      40                 :     SOCK_FILTER_OP(x, y, j, TRUE)
      41                 : 
      42                 : /* human version... */
      43                 : static unsigned int ex_sock_filter_parse_op(Vstr_base *s2,
      44                 :                                             size_t pos, size_t len,
      45                 :                                             size_t *num_len, int *js, int *ks)
      46              16 : {
      47              16 :   size_t tmp = 0;
      48                 :   
      49              16 :   tmp = vstr_spn_cstr_chrs_fwd(s2, pos, len, " ");
      50              16 :   len -= tmp; pos += tmp;
      51                 :   
      52                 :   if (0){ } /* FIXME: not all ops */
      53              16 :   SOCK_FILTER_OP("lda1",  0x30, FALSE, TRUE);
      54              16 :   SOCK_FILTER_OP("lda2",  0x28, FALSE, TRUE);
      55              16 :   SOCK_FILTER_OP("lda4",  0x20, FALSE, TRUE);
      56                 : 
      57              16 :   SOCK_FILTER_OP("ldlx",  0x81, FALSE, FALSE);
      58              16 :   SOCK_FILTER_OP("ldl",   0x80, FALSE, FALSE);
      59                 :   
      60               8 :   SOCK_FILTER_OP("ldmx",  0x61, FALSE, TRUE);
      61               8 :   SOCK_FILTER_OP("ldm",   0x60, FALSE, TRUE);
      62               8 :   SOCK_FILTER_OP("stmx",  0x03, FALSE, TRUE);
      63               8 :   SOCK_FILTER_OP("stm",   0x02, FALSE, TRUE);
      64                 :   
      65               8 :   SOCK_FILTER_OP_PX("add",  0x04, FALSE);
      66               8 :   SOCK_FILTER_OP_PX("sub",  0x14, FALSE);
      67               8 :   SOCK_FILTER_OP_PX("mul",  0x24, FALSE);
      68               8 :   SOCK_FILTER_OP_PX("div",  0x34, FALSE);
      69               8 :   SOCK_FILTER_OP_PX("or",   0x44, FALSE);
      70               8 :   SOCK_FILTER_OP_PX("and",  0x54, FALSE);
      71               8 :   SOCK_FILTER_OP_PX("lsh",  0x64, FALSE);
      72               8 :   SOCK_FILTER_OP_PX("rsh",  0x74, FALSE);
      73               8 :   SOCK_FILTER_OP_PX("neg",  0x84, FALSE);
      74                 :   
      75               8 :   SOCK_FILTER_OP_PX("ja",   0x05, TRUE);
      76               8 :   SOCK_FILTER_OP_PX("jeq",  0x15, TRUE);
      77               8 :   SOCK_FILTER_OP_PX("jgt",  0x25, TRUE);
      78               8 :   SOCK_FILTER_OP_PX("jge",  0x35, TRUE);
      79               8 :   SOCK_FILTER_OP_PX("jset", 0x45, TRUE);
      80                 :   
      81               8 :   SOCK_FILTER_OP("tax",  0x07, FALSE, FALSE);
      82               8 :   SOCK_FILTER_OP("txa",  0x87, FALSE, FALSE);
      83                 :   
      84               8 :   SOCK_FILTER_OP("reta", 0x16, FALSE, FALSE);
      85               0 :   SOCK_FILTER_OP("ret",  0x06, FALSE, TRUE);
      86                 : 
      87               0 :   return (0);
      88                 : }
      89                 : 
      90                 : static int ex_sock_filter_process(Vstr_base *s1, Vstr_base *s2)
      91               8 : {
      92               8 :   size_t srch = 0;
      93               8 :   int ret = FALSE;
      94                 :   struct sock_filter filter[1];
      95                 :   static unsigned int filter_count = 0;
      96                 :   static unsigned int line_count = 0;
      97                 :   
      98                 :   /* we don't want to create more data, if we are over our limit */
      99               8 :   if (s1->len > EX_MAX_W_DATA_INCORE)
     100               0 :     return (FALSE);
     101                 :   
     102              44 :   while ((srch = vstr_srch_chr_fwd(s2, 1, s2->len, '\n')))
     103                 :   {
     104              32 :     size_t pos = 1;
     105              32 :     size_t len = srch;
     106              32 :     size_t num_len = 0;
     107              32 :     int js = TRUE;
     108              32 :     int ks = TRUE;
     109                 :     unsigned int num_flags = (VSTR_FLAG_PARSE_NUM_SEP |
     110                 :                               VSTR_FLAG_PARSE_NUM_OVERFLOW |
     111                 :                               VSTR_FLAG_PARSE_NUM_SPACE |
     112              32 :                               VSTR_FLAG_PARSE_NUM_NO_NEGATIVE);
     113              32 :     int special_ld_cmd = FALSE;
     114                 :     
     115              32 :     ++line_count;
     116                 :     
     117              32 :     if (VPREFIX(s2, pos, len, "#"))
     118                 :     { /* comments */
     119              16 :       vstr_del(s2, 1, srch);
     120              16 :       ret = TRUE;
     121              16 :       continue;
     122                 :     }
     123              16 :     filter->code = filter->jt = filter->jf = filter->k = 0;
     124                 :     
     125              16 :     if (filter_count == USHRT_MAX)
     126               0 :       errno = ENOMEM, err(EXIT_FAILURE, "too many filters");
     127                 : 
     128              16 :     if (!VPREFIX(s2, pos, len, "{ "))
     129               0 :       errx(EXIT_FAILURE, "parse error 1, line %u", line_count);
     130              16 :     len -= strlen("{ "); pos += strlen("{ ");
     131                 : 
     132              16 :     filter->code = vstr_parse_uint(s2, pos, len, num_flags, &num_len, NULL);
     133              16 :     len -= num_len; pos += num_len;
     134                 : 
     135              16 :     if (!num_len)
     136                 :     {
     137              16 :       filter->code = ex_sock_filter_parse_op(s2, pos, len, &num_len, &js, &ks);
     138              16 :       len -= num_len; pos += num_len;
     139                 :     }
     140              16 :     if (!num_len)
     141               0 :       errx(EXIT_FAILURE, "parse error 2, line %u", line_count);
     142                 : 
     143              16 :     if ((filter->code == 0x30) || (filter->code == 0x28) ||
     144                 :         (filter->code == 0x20))
     145               0 :       special_ld_cmd = TRUE;
     146                 :     
     147              16 :     if (js)
     148                 :     {
     149               0 :       if (!VPREFIX(s2, pos, len, ", "))
     150               0 :         errx(EXIT_FAILURE, "parse error 3, line %u", line_count);
     151               0 :       len -= strlen(", "); pos += strlen(", ");
     152                 :       
     153               0 :       filter->jt   = vstr_parse_uint(s2, pos, len, num_flags, &num_len, NULL);
     154               0 :       len -= num_len; pos += num_len;
     155                 :       
     156               0 :       if (!VPREFIX(s2, pos, len, ", "))
     157               0 :         errx(EXIT_FAILURE, "parse error 4, line %u", line_count);
     158               0 :       len -= strlen(", "); pos += strlen(", ");
     159                 :     
     160               0 :       filter->jf   = vstr_parse_uint(s2, pos, len, num_flags, &num_len, NULL);
     161               0 :       len -= num_len; pos += num_len;
     162                 :     }
     163                 : 
     164              16 :     if (ks)
     165                 :     {
     166               0 :       if (!VPREFIX(s2, pos, len, ", "))
     167               0 :         errx(EXIT_FAILURE, "parse error 5, line %u", line_count);
     168               0 :       len -= strlen(", "); pos += strlen(", ");
     169                 :       
     170               0 :       num_len = vstr_spn_cstr_chrs_fwd(s2, pos, len, " ");
     171               0 :       len -= num_len; pos += num_len;
     172                 : 
     173               0 :       num_len = 0;
     174                 :       /* see linux/filter.h ... magic off sets as we start at TCP */
     175               0 :       if (!special_ld_cmd) { }
     176               0 :       else if (VPREFIX(s2, pos, len, "ad:"))
     177                 :       {
     178               0 :         num_len = strlen("ad:");
     179               0 :         filter->k = -0x1000;
     180                 :       }
     181               0 :       else if (VPREFIX(s2, pos, len, "net:"))
     182                 :       {
     183               0 :         num_len = strlen("net:");
     184               0 :         filter->k = -0x100000;
     185                 :       }
     186               0 :       else if (VPREFIX(s2, pos, len, "ll:"))
     187                 :       {
     188               0 :         num_len = strlen("ll:");
     189               0 :         filter->k = -0x200000;
     190                 :       }
     191               0 :       len -= num_len; pos += num_len;
     192                 :       
     193               0 :       filter->k += vstr_parse_uint(s2, pos, len, num_flags, &num_len, NULL);
     194               0 :       len -= num_len; pos += num_len;
     195                 :     }
     196                 :     
     197              16 :     if (!VPREFIX(s2, pos, len, " },"))
     198               0 :       errx(EXIT_FAILURE, "parse error 6, line %u", line_count);
     199                 :     
     200              16 :     ++filter_count;
     201              16 :     vstr_del(s2, 1, srch);
     202              16 :     ret = TRUE;
     203                 : 
     204              16 :     if (!vstr_add_buf(s1, s1->len, filter, sizeof(filter)))
     205               0 :       errno = ENOMEM, err(EXIT_FAILURE, "adding data");
     206                 :     
     207              16 :     if (s1->len > EX_MAX_W_DATA_INCORE)
     208               0 :       return (ret);
     209                 :   }
     210                 :   
     211               8 :   return (ret);
     212                 : }
     213                 : 
     214                 : static void ex_sock_filter_process_limit(Vstr_base *s1, Vstr_base *s2,
     215                 :                                          unsigned int lim)
     216              16 : {
     217              32 :   while (s2->len > lim)
     218                 :   { /* Finish processing read data (try writing if we need memory) */
     219               0 :     int proc_data = ex_sock_filter_process(s1, s2);
     220                 : 
     221               0 :     if (!proc_data && (io_put(s1, STDOUT_FILENO) == IO_BLOCK))
     222               0 :       io_block(-1, STDOUT_FILENO);
     223                 :   }
     224              16 : }
     225                 : 
     226                 : static void ex_sock_filter_read_fd_write_stdout(Vstr_base *s1, Vstr_base *s2,
     227                 :                                                 int fd)
     228              16 : {
     229                 :   /* read/process/write loop */
     230                 :   while (TRUE)
     231                 :   {
     232              16 :     int io_w_state = IO_OK;
     233              16 :     int io_r_state = io_get(s2, fd);
     234                 :     
     235              16 :     if (io_r_state == IO_EOF)
     236               8 :       break;
     237                 :     
     238               8 :     ex_sock_filter_process(s1, s2);
     239                 : 
     240               8 :     io_w_state = io_put(s1, STDOUT_FILENO);
     241                 : 
     242               8 :     io_limit(io_r_state, fd, io_w_state, STDOUT_FILENO, s1);
     243               8 :   }
     244                 : 
     245                 :   /* write out all of the end of the file,
     246                 :    * so the next file starts on a new line */
     247               8 :   ex_sock_filter_process_limit(s1, s2, 0);
     248               8 : }
     249                 : 
     250                 : int main(int argc, char *argv[])
     251              16 : {
     252              16 :   Vstr_base *s2 = NULL;
     253              16 :   Vstr_base *s1 = ex_init(&s2);
     254              16 :   int count = 1;
     255              16 :   int use_mmap = CONF_USE_MMAP_DEF;
     256                 : 
     257                 :   /* parse command line arguments... */
     258              32 :   while (count < argc)
     259                 :   { /* quick hack getopt_long */
     260              16 :     if (!strcmp("--", argv[count]))
     261                 :     {
     262               8 :       ++count;
     263               8 :       break;
     264                 :     }
     265               8 :     else if (!strcmp("--mmap", argv[count])) /* toggle use of mmap */
     266               0 :       use_mmap = !use_mmap;
     267               8 :     else if (!strcmp("--version", argv[count]))
     268                 :     { /* print version and exit */
     269               4 :       vstr_add_fmt(s1, 0, "%s", "\
     270                 : jsock_filter 1.0.0\n\
     271                 : Written by James Antill\n\
     272                 : \n\
     273                 : Uses Vstr string library.\n\
     274                 : ");
     275               4 :       goto out;
     276                 :     }
     277               4 :     else if (!strcmp("--help", argv[count]))
     278                 :     { /* print version and exit */
     279               4 :       vstr_add_fmt(s1, 0, "%s", "\
     280                 : Usage: jsock_filter [FILENAME]...\n\
     281                 :    or: jsock_filter OPTION\n\
     282                 : Output filenames.\n\
     283                 : \n\
     284                 :       --help     Display this help and exit\n\
     285                 :       --version  Output version information and exit\n\
     286                 :       --mmap     Toggle use of mmap() to load input files\n\
     287                 :       --         Treat rest of cmd line as input filenames\n\
     288                 : \n\
     289                 : Report bugs to James Antill <james@and.org>.\n\
     290                 : ");
     291               4 :       goto out;
     292                 :     }
     293                 :     else
     294               0 :       break;
     295               0 :     ++count;
     296                 :   }
     297                 :   
     298                 :   /* if no arguments are given just do stdin to stdout */
     299               8 :   if (count >= argc)
     300                 :   {
     301               0 :     io_fd_set_o_nonblock(STDIN_FILENO);
     302               0 :     ex_sock_filter_read_fd_write_stdout(s1, s2, STDIN_FILENO);
     303                 :   }
     304                 : 
     305                 :   /* loop through all arguments, open the file specified
     306                 :    * and do the read/write loop */
     307              20 :   while (count < argc)
     308                 :   {
     309               8 :     unsigned int ern = 0;
     310                 : 
     311               8 :     if (use_mmap)
     312               0 :       vstr_sc_mmap_file(s2, s2->len, argv[count], 0, 0, &ern);
     313                 : 
     314              12 :     if (!use_mmap ||
     315                 :         (ern == VSTR_TYPE_SC_MMAP_FILE_ERR_FSTAT_ERRNO) ||
     316                 :         (ern == VSTR_TYPE_SC_MMAP_FILE_ERR_MMAP_ERRNO) ||
     317                 :         (ern == VSTR_TYPE_SC_MMAP_FILE_ERR_TOO_LARGE))
     318                 :     {
     319               8 :       int fd = io_open(argv[count]);
     320                 : 
     321               8 :       ex_sock_filter_read_fd_write_stdout(s1, s2, fd);
     322                 : 
     323               8 :       if (close(fd) == -1)
     324               0 :         warn("close(%s)", argv[count]);
     325                 :     }
     326               0 :     else if (ern && (ern != VSTR_TYPE_SC_MMAP_FILE_ERR_CLOSE_ERRNO))
     327               0 :       err(EXIT_FAILURE, "add");
     328                 :     else
     329               0 :       ex_sock_filter_process_limit(s1, s2, EX_MAX_R_DATA_INCORE);
     330                 :     
     331               8 :     ++count;
     332                 :   }
     333                 : 
     334               8 :   ex_sock_filter_process_limit(s1, s2, 0);
     335                 : 
     336              16 :  out:
     337              16 :   io_put_all(s1, STDOUT_FILENO);
     338                 : 
     339              16 :   exit (ex_exit(s1, s2));
     340                 : }
     341                 : 

Generated by: LTP GCOV extension version 1.4