/*
    ettercap -- parsing utilities

    Copyright (C) 2001  ALoR <alor@users.sourceforge.net>, NaGA <crwm@freemail.it>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    $Id: ec_parser.c,v 1.39 2003/07/04 20:41:42 alor Exp $
*/


#include <ec_main.h>

#ifdef HAVE_GTK
   #include <ec_gtk_splash.h>
#endif

#include <ctype.h>
#ifdef HAVE_GETOPT_H
   #include <getopt.h>
#else
   #include "missing/getopt.h"
#endif

#include <ec_inet.h>
#include <ec_simple.h>
#include <ec_dissector.h>
#include <ec_inet_structures.h>
#include <ec_filterdrop.h>

extern char *Execute_Plugin;

char *loading_plugs;    // list of plugin to be loaded.  it has this form: "|dummy|foo|bar|..."

struct list {
   int n;
   int cur;
   u_char values[0xff];
};

// protos...

extern void Main_Usage(void);
void Parser_ParseConfFile(char *filename);
void Parser_Dissectors(char *toparse);
void Parser_Plugins(char *toparse);
char Parser_Activated_Plugin(char *name);
void Parser_ParseParameters(char *first, char *second, char *third, char *fourth);
int Parser_ParseOptions(int counter, char **values);
char *Parser_PrintFilter(DROP_FILTER *ptr, int i);
void Parser_LoadFilters(char *filename);
int Parser_HostList(char *to_parse);
char * Parser_AddStr(char *list, char *string);
int Parser_Expand_List(char *to_parse);
void Parser_Expand_Token(char *s, struct list *buf);
int match_pattern(const char *s, const char *pattern);
void Parser_Filters(char *line, DROP_FILTER *filter);
char *Parser_StrSpacetoUnder(char *h_name);
void Parser_StatusBar(int max);

//-----------------------------------


int Parser_ParseOptions(int counter, char **values)
{
   int c;

   static struct option long_options[] = {
      { "help", no_argument, NULL, 'h' },
      { "version", no_argument, NULL, 'v' },
      { "simple", no_argument, NULL, 'N' },
      { "gtk", no_argument, NULL, 'G' },
      { "list", no_argument, NULL, 'l' },
      { "arpsniff", no_argument, NULL, 'a' },
      { "sniff", no_argument, NULL, 's' },
      { "macsniff", no_argument, NULL, 'm' },
      { "iface", required_argument, NULL, 'i' },
      { "netmask", required_argument, NULL, 'n' },
      { "check", no_argument, NULL, 'c' },
      { "plugin", required_argument, NULL, 'p' },
      { "hexview", no_argument, NULL, '1' },
      { "textview", no_argument, NULL, '2' },
      { "ebcdicview", no_argument, NULL, '3' },
      { "silent", no_argument, NULL, 'z' },
      { "fingerprint", no_argument, NULL, 'f' },
      { "linktype", no_argument, NULL, 'g' },
      { "collect", no_argument, NULL, 'C' },
      { "broadping", no_argument, NULL, 'b' },
      { "logtofile", no_argument, NULL, 'L' },
      { "quiet", no_argument, NULL, 'q' },
      { "etterconf", required_argument, NULL, 'e' },
      { "dontresolve", no_argument, NULL, 'd' },
      { "newcert", no_argument, NULL, 'w' },
      { "filter", required_argument, NULL, 'F' },
      { "hosts", required_argument, NULL, 'H' },
      { "yes", no_argument, NULL, 'y' },
      { "delay", required_argument, NULL, 'D' },
      { "reverse", no_argument, NULL, 'R' },
      { "spoof", required_argument, NULL, 'S' },
      { "stormdelay", required_argument, NULL, 'Z' },
      { "bufferlen", required_argument, NULL, 'B' },
      { "passive", no_argument, NULL, 'O' },
      { "loadhosts", required_argument, NULL, 'j' },
      { "savehosts", no_argument, NULL, 'k' },
      { "proto", required_argument, NULL, 't' },
      { "readpcapfile", required_argument, NULL, 'T' },
      { "writepcapfile", required_argument, NULL, 'Y' },
      { "onlypoison", no_argument, NULL, 'J' },
      { "forceip", no_argument, NULL, 'X' },
      { "refresh", required_argument, NULL, 'r' },
      { 0 , 0 , 0 , 0}
   };

   DEBUG_MSG("Parser_ParseOptions -- [%d] [%s]", counter, *values);

   optind = 0;

   while ((c = getopt_long (counter, values, "hvyNGlasmci:p:123zfgCbn:Lqe:dwF:H:D:RS:Z:B:Oj:kt:T:Y:JXr:",long_options, (int *)0)) != EOF) {

      switch (c) {

         case 'h':
            Main_Usage();
         break;

         case 'v':   Options.version = 1;       break;

         case 'y':   Options.yes = 1;           break;

         case 'N':   Options.normal = 1;        break;

         case 'G':   Options.gtk = 1;           break;

         case 'l':   Options.list = 1;          break;

         case 'a':   Options.arpsniff = 1;      break;

         case 's':   Options.sniff = 1;         break;

         case 'm':   Options.macsniff = 1;      break;

         case 'c':   Options.check = 1;         break;

         case '1':   Options.hexview = 1;       break;
                     
         case '2':   Options.textview = 1;      break;
                     
         case '3':   Options.ebcdicview = 1;    break;

         case 'z':   Options.silent = 1;        break;

         case 'u':   Options.udp = 1;           break;

         case 'f':   Options.finger = 1;        break;

         case 'g':   Options.link = 1;          break;

         case 'C':   Options.collect = 1;       break;

         case 'b':   Options.broadping = 1;     break;

         case 'L':   Options.logtofile = 1;     break;

         case 'q':   Options.quiet = 1;         break;

         case 'd':   Options.dontresolve = 1;   break;

         case 'R':   Options.reverse = 1;       break;

         case 'O':   Options.passive = 1;
                     Options.silent = 1;        break;

         case 'p':
            #ifdef PERMIT_PLUGINS
                     Options.plugin = 1;
                     Execute_Plugin = strdup(optarg);

            #else
                     Error_msg("PLUGIN SUPPORT not supported on this OS.");
            #endif
         break;

         case 'i':
            strlcpy(Options.netiface, optarg, sizeof(Options.netiface));
         break;

         case 'j':
            Options.hostsfromfile = 1;
            Options.hostfile = strdup(optarg);
         break;

         case 'k':
            Options.hoststofile = 1;
         break;

         case 'T':
            Options.silent = 1;
            Options.dumpfile = strdup(optarg);
         break;

         case 'Y':
            Options.writedump = 1;
            Options.dumpfile = strdup(optarg);
         break;

         case 't':
            if (!strncasecmp(optarg, "tcp", 3)) Options.tcp = 1;
            else if (!strncasecmp(optarg, "udp", 3)) Options.udp = 1;
            else if (!strncasecmp(optarg, "all", 3)) {
               Options.tcp = 1;
               Options.udp = 1;
            } else
               Error_msg("[%s]: protocol unrecognized", optarg);

         break;

         case 'J':
            Options.normal = 1;
            Options.onlypoison = 1;
         break;
         
         case 'X':  
            Options.force_ip = 1;
         break;
           
         case 'n':
            strlcpy(Options.netmask, optarg, sizeof(Options.netmask));
         break;

         case 'D':
            Options.delay = atoi(optarg);
            if (Options.delay == 0) Options.delay = 1;      // at least one second...
         break;

         case 'Z':
            Options.storm_delay = atoi(optarg);
            if (Options.storm_delay == 0) Options.storm_delay = 1;      // at least one usec...
         break;

         case 'r':
            Options.refresh_delay = atoi(optarg);
            if (Options.refresh_delay == 0) Options.refresh_delay = 1;   // at least one sec...
         break;

	 case 'B':
            Options.buflen = atoi(optarg);
            if (Options.buflen > MAX_BUFLEN) Options.buflen = MAX_BUFLEN;     
         break;

         case 'S':
            Options.spoofIp = inet_addr(optarg);
         break;

         case 'e':
            if (!strcmp(values[0], "etter.conf"))
               Error_msg("You can't specify the --etterconf option in the conf file !! (safe exit avoiding loops)");
            else
               return 1;
         break;

         case 'w':
            Simple_CreateCertFile();
         break;

         case 'F':
            filter_on_source = 1;
            filter_on_dest = 1;
            Parser_LoadFilters(optarg);
            Options.filter = 1;
         break;

         case 'H':
            host_to_be_scanned = Parser_HostList(optarg);
         break;

         case ':': // missing parameter
            fprintf(stdout, "\nTry `%s --help' for more options.\n\n", PROGRAM);
            exit(0);
         break;

         case '?': // unknown option
            fprintf(stdout, "\nTry `%s --help' for more options.\n\n", PROGRAM);
            exit(0);
         break;
      }
   }

   Parser_ParseParameters(values[optind], values[optind+1], values[optind+2], values[optind+3]);

   return 0;
}


void Parser_ParseParameters(char *first, char *second, char *third, char *fourth)
{

#ifdef DEBUG
   if (first)  DEBUG_MSG("Parser_ParseParameters -- 1 [%s]", first); else goto exit_debug;
   if (second) DEBUG_MSG("Parser_ParseParameters -- 2 [%s]", second); else goto exit_debug;
   if (third)  DEBUG_MSG("Parser_ParseParameters -- 3 [%s]", third); else goto exit_debug;
   if (fourth) DEBUG_MSG("Parser_ParseParameters -- 4 [%s]", fourth); else goto exit_debug;
exit_debug:
#endif

#define R(a,b,c) (a & b) | ((a ^ b) & c)     // returns true if more than one was selected

   if (!Options.normal &&
                   (Options.reverse || Options.collect || Options.list ||
                    Options.finger || Options.logtofile || Options.quiet ||
                    Options.check))
      Error_msg("Perhaps you have forgotten the -N option...\n");

   if (!Options.normal) Options.reverse = 0;

   if (Options.quiet && !Options.normal ) 
      Error_msg("Demonization is only useful with -N *cannot daemonize the interface* !!\n\n");
   
   if ( R(Options.arpsniff, Options.sniff, Options.macsniff) )
      Error_msg("Please select only one sniffing method !!\n\n");

   if (Options.silent && Options.broadping)
      Error_msg("Please select only one start up method !!\n\n");

   if (Options.collect && !(Options.sniff || Options.arpsniff || Options.macsniff))
      Error_msg("Please select one sniffing method to be used for collecting password !!\n\n");

   if (Options.normal && Options.passive && (Options.sniff || Options.arpsniff || Options.macsniff))
      Error_msg("Passive scanning can't be combined with a sniffing method !!\n\n");

   if (Options.dumpfile && Options.arpsniff && !Options.writedump)
      Error_msg("You can't ARP sniff from a file !!\n\n");

   if (Options.onlypoison && (Options.passive || Options.filter || 
                              Options.sniff || Options.arpsniff || Options.macsniff ||
                              Options.logtofile))
      Error_msg("This options can't be used in conjunction with -J !!\n\n");
   
   if (Options.sniff || Options.macsniff)
      Options.silent = 1;

   if (Options.silent)
   {
      if (Options.macsniff)
      {
         char check[6];

         if (first)
         {
            sscanf(first, "%17s", Host_Dest.mac);
            if (second)
               sscanf(second, "%17s", Host_Source.mac);
         }

         if ( strcmp(Host_Dest.mac, "") && Inet_GetMACfromString(Host_Dest.mac, check ) == -1)   // check for valid mac
            Error_msg("Incorrect parsing of MAC [%s] !!\nIt must be in the form 01:02:03:04:05:06 !!", Host_Dest.mac);
         if ( strcmp(Host_Source.mac, "") && Inet_GetMACfromString(Host_Source.mac, check ) == -1)   // check for valid mac
            Error_msg("Incorrect parsing of MAC [%s] !!\nIt must be in the form 01:02:03:04:05:06 !!", Host_Source.mac);
         if ( !strcmp(Host_Source.mac, Host_Dest.mac) && strcmp(Host_Source.mac, ""))
            Error_msg("SOURCE and DEST MAC address must be different !!");
      }

      if (Options.arpsniff || Options.onlypoison)
      {
         int i=0;
         char check[6];

         if (first)
         {
            i++;
            sscanf(first, "%128[^:]:%d", Host_Dest.name, &Host_Dest.port);
            if (second)
            {
               i++;
               sscanf(second, "%128[^:]:%d", Host_Source.name, &Host_Source.port);
               if (third)
               {
                  i++;
                  sscanf(third, "%17s", Host_Dest.mac);
                  if (fourth)
                  {
                     i++;
                     sscanf(fourth, "%17s", Host_Source.mac);
                  }
               }
            }
         }
         if (i == 2)       // PUBLIC ARP
         {
            sscanf(second, "%17s", Host_Dest.mac);    // rescan the second parameter
            Host_Source.port = 0;
            strcpy(Host_Source.name, "");
            strcpy(Host_Source.ip, "");
            Host_Source.port = 0;

            if (Inet_GetMACfromString(Host_Dest.mac, check ) == -1)   // check for valid mac
               Error_msg("Incorrect parsing of MAC [%s] !!\nIt must be in the form 01:02:03:04:05:06 !!", Host_Dest.mac);
         }
         else if (i == 4)  // ARP BASED
         {
            if (Inet_GetMACfromString(Host_Dest.mac, check ) == -1)   // check for valid mac
               Error_msg("Incorrect parsing of MAC [%s] !!\nIt must be in the form 01:02:03:04:05:06 !!", Host_Dest.mac);
            if (Inet_GetMACfromString(Host_Source.mac, check ) == -1)   // check for valid mac
               Error_msg("Incorrect parsing of MAC [%s] !!\nIt must be in the form 01:02:03:04:05:06 !!", Host_Source.mac);
         }
         else
            Error_msg("Please specify both source and destination IP and MAC for ARP Based (full-duplex)\n"
                      "or only one IP and MAC for PUBLIC ARP (half-duplex)");

         if ( !strcmp(Host_Source.ip, Host_Dest.ip) && strcmp(Host_Source.ip, "") )
            Error_msg("SOURCE and DEST IP address must be different !!");
         if ( !strcmp(Host_Source.mac, Host_Dest.mac) && strcmp(Host_Source.mac, ""))
            Error_msg("SOURCE and DEST MAC address must be different !!");

      }

      if (Options.sniff || Options.plugin)
      {
         if (first)
         {
            sscanf(first, "%128[^:]:%d", Host_Dest.name, &Host_Dest.port);
            if (second) sscanf(second, "%128[^:]:%d", Host_Source.name, &Host_Source.port);

            if (!strcasecmp(Host_Source.name, "ANY") || !strcmp(Host_Source.name, "0") )
               strcpy(Host_Source.name, "");

            if (!strcasecmp(Host_Dest.name, "ANY") || !strcmp(Host_Dest.name, "0") )
               strcpy(Host_Dest.name, "");

            if ( !strcmp(Host_Source.name, Host_Dest.name) && strcmp(Host_Source.name, "") )
               Error_msg("SOURCE and DEST IP address must be different !!");
         }
      }

      if (Options.check)   Error_msg("You can't check for poisoners in silent mode !!");

      if (Options.list)    Error_msg("You can't make the list in silent mode !!");
   }
   else // !silent
   {
      if ((Options.arpsniff || Options.onlypoison) && !first)
         Error_msg("Please specify  source and destination IP for ARP Based (full-duplex)\n"
                   "or only one IP for PUBLIC ARP (half-duplex)");

      if (first)
      {
         sscanf(first, "%128[^:]:%d", Host_Dest.name, &Host_Dest.port);
         if (second)
         {
            char check[6];
            if (Inet_GetMACfromString(second, check ) == -1)   // if it is a mac take it in dest, else it is the source ip
               sscanf(second, "%128[^:]:%d", Host_Source.name, &Host_Source.port);
            else
               sscanf(second, "%17s", Host_Dest.mac);
         }
      }
   }

   if (strcmp(Host_Source.name, ""))
      strcpy(Host_Source.ip, Inet_NameToIp(Host_Source.name));

   if (strcmp(Host_Dest.name, ""))
      strcpy(Host_Dest.ip, Inet_NameToIp(Host_Dest.name));



   DEBUG_MSG("Parser_ParseParameters - name - [%s][%s]", Host_Dest.name, Host_Source.name);
   DEBUG_MSG("Parser_ParseParameters -  IP  - [%s][%s]", Host_Dest.ip, Host_Source.ip);
   DEBUG_MSG("Parser_ParseParameters - port - [%d][%d]", Host_Dest.port, Host_Source.port);
   DEBUG_MSG("Parser_ParseParameters -  MAC - [%s][%s]", Host_Dest.mac, Host_Source.mac);

}



char * Parser_AddStr(char *list, char *string)
{
   int len = strlen(list)+strlen(string)+1;

   list = realloc(list, len);
   if (list == NULL)
      ERROR_MSG("realloc()");
   strlcat(list, string, len);

   return list;
}



void Parser_ParseConfFile(char *filename)
{

   FILE *etterconf;
   char line[1024];
   char *to_be_parsed = NULL;
   char *option = NULL;
   char *ptr;
   int pargc = 0;
   char *pargv[256];
   char dissectors = 0;
#ifdef PERMIT_PLUGINS
   char plugins = 0;
#endif

   DEBUG_MSG("Parser_ParseConfFile - %s", filename);

   memset(&pargv, 0, 256*sizeof(int));

   fprintf (stdout, "Loading options from %s...\n", filename);

   to_be_parsed = calloc(1, 1);
   to_be_parsed = Parser_AddStr(to_be_parsed, "etter.conf ");

   etterconf = fopen(filename, "r");
   if (etterconf == NULL)
      ERROR_MSG("fopen()");

   do
   {
      fgets(line, 100, etterconf);
      if ( (ptr = strchr(line, '#')) )
         *ptr = 0;

      if ( (ptr = strchr(line, '\n')) )
         *ptr = 0;

      if (!strlen(line))   // skip 0 length line
         continue;

      DEBUG_MSG("Parser_ParseConfFile - [%s]", line);

      if (!strncasecmp(line, "OPTIONS: ", 9))
      {
         option = strdup(strchr(line, '-'));
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "IFACE: ", 7))
      {
         option = strdup(line+7);
         to_be_parsed = Parser_AddStr(to_be_parsed, " --iface ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "NETMASK: ", 9))
      {
         option = strdup(line+9);
         to_be_parsed = Parser_AddStr(to_be_parsed, " --netmask ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "DELAY: ", 7))
      {
         option = strdup(line+7);
         to_be_parsed = Parser_AddStr(to_be_parsed, " --delay ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "HOSTS: ", 7))
      {
         option = strdup(line+7);
         to_be_parsed = Parser_AddStr(to_be_parsed, " --hosts ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

#ifdef PERMIT_PLUGINS
      if (!strncasecmp(line, "PLUGIN: ", 8))
      {
         option = strdup(line+8);
         to_be_parsed = Parser_AddStr(to_be_parsed, " --plugin ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }
#endif

      if (!strncasecmp(line, "FILTER: ", 8))
      {
         option = strdup(line+8);
         to_be_parsed = Parser_AddStr(to_be_parsed, " --filter ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "IP1: ", 5))
      {
         option = strdup(line+5);
         to_be_parsed = Parser_AddStr(to_be_parsed, " ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "IP2: ", 5))
      {
         option = strdup(line+5);
         to_be_parsed = Parser_AddStr(to_be_parsed, " ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "MAC1: ", 6))
      {
         option = strdup(line+6);
         to_be_parsed = Parser_AddStr(to_be_parsed, " ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "MAC2: ", 6))
      {
         option = strdup(line+6);
         to_be_parsed = Parser_AddStr(to_be_parsed, " ");
         to_be_parsed = Parser_AddStr(to_be_parsed, option);
         free(option);
      }

      if (!strncasecmp(line, "GWIP: ", 6))
      {
         extern int illithid_gwip;

         option = strdup(line+6);
         if ( inet_aton(option, (struct in_addr *)&illithid_gwip) == 0)
            Error_msg("Incorrect GWIP (%s) in the conf file !!", option);
         free(option);
      }

      if (!strncasecmp(line, "</dissectors>", 13))
         dissectors = 0;

      if (dissectors)
         Parser_Dissectors(line);

      if (!strncasecmp(line, "<dissectors>", 12))
      {
         fprintf (stdout, "Setting dissectors handlers...\n");
         dissectors = 1;
      }
#ifdef PERMIT_PLUGINS
      if (!strncasecmp(line, "</hooking plugins>", 18))
         plugins = 0;

      if (plugins)
         Parser_Plugins(line);

      if (!strncasecmp(line, "<hooking plugins>", 17))
      {
         fprintf (stdout, "Plugins to be loaded...\n");
         plugins = 1;
      }
#endif

   } while (!feof(etterconf));


   if (!strcmp(to_be_parsed, "etter.conf ")) // no options in the file....
      return;

   DEBUG_MSG("Parser_ParseConfFile - [%s]", to_be_parsed);

   ptr = strtok(to_be_parsed, " ");
   pargv[pargc++] = strdup(ptr);

   while( (ptr = strtok(NULL, " ")) )
      pargv[pargc++] = strdup(ptr);

#ifdef DEBUG
{
   int i;
   for(i=0; i<pargc; i++)
      DEBUG_MSG("Parser_ParseConfFile - [%d] %s", i, pargv[i]);

   DEBUG_MSG("Parser_ParseConfFile - pargc [%d]", pargc);
}
#endif

   free(to_be_parsed);

   Parser_ParseOptions(pargc, pargv);
}




void Parser_Dissectors(char *toparse)
{
   char name[30]; // doubled this from 15
   char arguments[25];
   char *parseport;
   char *proto;
   short port=0;

   if (!strchr(toparse, '='))    // malformed line
      return;

   memset(name, 0, sizeof(name));
   memset(arguments, 0, sizeof(arguments));

   strlcpy(name, strtok(toparse, "="), sizeof(name));

   strlcpy(arguments, strtok(NULL, "="), sizeof(arguments));

   if (!strncmp(arguments, "OFF", 3))
   {
      fprintf(stdout, "%11s... disabled!\n", name);
      Dissector_SetHandle(name, 0, 0, 0); // disable this dissector
   }
   else if (!strncmp(arguments, "ON", 2))
   {
      if ( (parseport = strchr(arguments, '|')) )
      {
         parseport++;

         proto = strchr(parseport, '/');
         if (proto)
         {
            proto++;
            port = atoi(strtok(parseport, "/"));

            if (!strncasecmp(proto, "tcp", 3))
               Dissector_SetHandle(name, 1, port, IPPROTO_TCP);
            else if (!strncasecmp(proto, "udp", 3))
               Dissector_SetHandle(name, 1, port, IPPROTO_UDP);
            else if (!strcmp(name, "PROXYHTTPS"))
            {
#if defined (HAVE_OPENSSL) && defined (PERMIT_HTTPS)
               extern int Grell_ProxyIP;
               extern int Grell_ProxyPort;
               Grell_ProxyIP = inet_addr(strtok(NULL, "/"));
               Grell_ProxyPort = port;
               Dissector_SetHandle(name, 1, port, IPPROTO_TCP);
#else
               fprintf(stdout, "%11s... not compiled in ettercap !!\n", name);
               return;
#endif
            }
            else
               return;
         }
         else
            return;

         fprintf(stdout, "%11s... moved on port %d/%s\n", name, port, proto);
      }
   }
}



void Parser_Plugins(char *toparse)
{
   char name[20], l_name[22];
   char args[4];

   if (!strchr(toparse, '='))    // malformed line
      return;

   if (!loading_plugs) loading_plugs = (char *)calloc(1,1);

   memset(name, 0, sizeof(name));
   strlcpy(name, strtok(toparse, "="), 20);
   strlcpy(args, strtok(NULL, "="), 4);

   if (!strncmp(args, "ON", 2))
   {
      snprintf(l_name, sizeof(l_name), "|%s|", name);
      loading_plugs = (char *)realloc(loading_plugs, strlen(loading_plugs)+strlen(l_name)+2);
      strcat(loading_plugs, l_name);
      fprintf(stdout, "%s\n", name);
   }
}




char Parser_Activated_Plugin(char *name)
{
   char l_name[22];
   snprintf(l_name, sizeof(l_name), "|%s|", name);

   if (!loading_plugs) return 0;

   if (strstr(loading_plugs, l_name)) return 1;

   return 0;
}



void Parser_Filters(char *line, DROP_FILTER *filter)
{
   int i, j;
   char tmp[50];
   char tmp_search[MAX_FILTER+1];
   char *p, *q;


   if ((p = strstr(line, "<search>")))
   {
      q = strstr(p, "</search>");
      i = ((int)q-(int)p) - strlen("<search>");
      if (i==0) return;
      snprintf(tmp, sizeof(tmp), "<search>%%%dc</search>", i);
      sscanf(p, tmp, filter->display_search);
      filter->wildcard = FilterDrop_ParseWildcard(tmp_search, filter->display_search, sizeof(tmp_search));
      filter->slen = FilterDrop_strescape(filter->search, tmp_search);
      return;
   }

   if ((p = strstr(line, "<replace>")))
   {
      q = strstr(p, "</replace>");
      i = ((int)q-(int)p) - strlen("<replace>");
      if (i==0) return;
      snprintf(tmp,sizeof(tmp) ,"<replace>%%%dc</replace>", i);
      sscanf(p, tmp, filter->display_replace);
      filter->rlen = FilterDrop_strescape(filter->replace, filter->display_replace);
      return;
   }

   if ((p = strstr(line, "<action>")))
   {
      sscanf(p, "<action>%c</action>", &filter->type);
      filter->type = toupper(filter->type);
      return;
   }

   if ((p = strstr(line, "<goto>")))
   {
      j = sscanf(p, "<goto>%d</goto>", &filter->go_to);
      if (j == 0) filter->go_to = -1;
   }

   if ((p = strstr(line, "<elsegoto>")))
   {
      j = sscanf(p, "<elsegoto>%d</elsegoto>", &filter->else_go_to);
      if (j == 0) filter->else_go_to = -1;
   }

   if ((p = strstr(line, "<proto>")))
   {
      sscanf(p, "<proto>%c</proto>", &filter->proto);
      filter->proto = toupper(filter->proto);
      return;
   }

   if ((p = strstr(line, "<source>")))
      sscanf(p, "<source>%d</source>", &filter->source);

   if ((p = strstr(line, "<dest>")))
      sscanf(p, "<dest>%d</dest>", &filter->dest);

}



void Parser_LoadFilters(char *filename)
{
   FILE *etterfilter;
   char line[1024];
   char *ptr;
   char filter=0;
   DROP_FILTER filter_tmp;
   extern char *Filter_File;

   if (Filter_File)
   {
      etterfilter = fopen(Filter_File, "r");
      DEBUG_MSG("Parser_LoadFilters - [%s]", Filter_File);
   }
   else if (!strcmp(filename, ""))
   {
      strcpy(line, "./etter.filter");
      etterfilter = fopen(line, "r");
      if (etterfilter == NULL)
      {
         strlcpy(line, DATA_PATH, sizeof(line));
         strlcat(line, "/etter.filter", sizeof(line));
         etterfilter = fopen(line, "r");
      }
      Filter_File = strdup(line);
      DEBUG_MSG("Parser_LoadFilters - [%s]", line);
   }
   else
   {
      etterfilter = fopen(filename, "r");
      Filter_File = strdup(filename);
      DEBUG_MSG("Parser_LoadFilters - [%s]", filename);
   }

   if (etterfilter == NULL)
         Error_msg("CAN'T find a filter file in ./ or in %s", DATA_PATH);

   Filter_Source = 0;
   Filter_Dest = 0;

   if (Filter_Array_Source) free(Filter_Array_Source);
   if (Filter_Array_Dest) free(Filter_Array_Dest);

   Filter_Array_Source = NULL;
   Filter_Array_Dest = NULL;

   do
   {
      fgets(line, 1024, etterfilter);

      if ( (ptr = strchr(line, '#')) )
         *ptr = 0;

      if (!strlen(line))   // skip 0 length line
         continue;

      if (!strncasecmp(line, "</filter source>", 16))
      {
         filter = 0;
         memcpy(&Filter_Array_Source[Filter_Source-1], &filter_tmp, sizeof(DROP_FILTER));
      }

      if (!strncasecmp(line, "</filter dest>", 14))
      {
         filter = 0;
         memcpy(&Filter_Array_Dest[Filter_Dest-1], &filter_tmp, sizeof(DROP_FILTER));
      }

      if (filter)
         Parser_Filters(line, &filter_tmp);

      if (!strncasecmp(line, "<filter source>", 15))
      {
         Filter_Source++;
         filter = 1;
         memset(&filter_tmp, 0, sizeof(DROP_FILTER));
         Filter_Array_Source = (DROP_FILTER *)realloc(Filter_Array_Source, (Filter_Source) * sizeof(DROP_FILTER));
         if (Filter_Array_Source == NULL)
            ERROR_MSG("realloc()");
      }

      if (!strncasecmp(line, "<filter dest>", 13))
      {
         Filter_Dest++;
         filter = 1;
         memset(&filter_tmp, 0, sizeof(DROP_FILTER));
         Filter_Array_Dest = (DROP_FILTER *)realloc(Filter_Array_Dest, (Filter_Dest) * sizeof(DROP_FILTER));
         if (Filter_Array_Dest == NULL)
            ERROR_MSG("realloc()");
      }

   } while (!feof(etterfilter));

   fclose(etterfilter);

#ifdef DEBUG
{
   short i;
   for (i=0; i<Filter_Source; i++)
      DEBUG_MSG("\tSOURCE: %s", Parser_PrintFilter(Filter_Array_Source, i));

   for (i=0; i<Filter_Dest; i++)
      DEBUG_MSG("\tDEST  : %s", Parser_PrintFilter(Filter_Array_Dest, i));
}
#endif

}


char * Parser_PrintFilter(DROP_FILTER *ptr, int i)
{
   static char tmp[100];
   int j;

   j = snprintf(tmp, sizeof(tmp), "%2d | %5d:%-5d %c [%-10.10s] %c ", i,  ptr[i].source, ptr[i].dest, ptr[i].proto, ptr[i].display_search, ptr[i].type);
   if (ptr[i].type == 'R')
      j += sprintf(tmp+j, "[%-10.10s] ", ptr[i].display_replace);
   else
      j += sprintf(tmp+j, "             ");
   if (ptr[i].go_to >= 0 || ptr[i].else_go_to >= 0)
      j += sprintf(tmp+j, "| => ");
   if (ptr[i].go_to >= 0)
      j += sprintf(tmp+j, "%2d ", ptr[i].go_to);
   else
      j += sprintf(tmp+j, "   ");
   if (ptr[i].else_go_to >= 0)
      j += sprintf(tmp+j, "! %-2d ", ptr[i].else_go_to);

  return tmp;
}



void Parser_Expand_Token(char *s, struct list *buf)
{
/*
 * This function parses the input in the form [1-3,17,5-11]
 * and fill the structure with expanded numbers.
 */

   char *str = strdup(s);
   char *p, *q, r;
   char *end;
   u_int a = 0, b = 0;
          
   p = str;
   end = p + strlen(p);
   
   while (p < end) {
      q = p;
      
      while ( isdigit((int)*q) && q++ < end);
      
      r = *q;   
      *q = 0;
      a = atoi(p);
      if (a > 255) 
         Error_msg("Invalid IP range !!");
      
      if ( r == '-') {
         p = ++q;
         while ( isdigit((int)*q) && q++ < end);
         *q = 0;
         if (*p == '\0') 
            Error_msg("Invalid IP range !!");
         b = atoi(p);
         if (b > 255 || b < a) 
            Error_msg("Invalid IP range !!");
      } else {
         b = a; 
      } 
      
      for(; a <= b; a++) {
         buf->n++;
         buf->values[buf->n - 1] = (u_char) a;
      }
      
      if (q == end) break;
      else  p = q + 1;      
   }
  
   free(str);
}



int Parser_Expand_List(char *to_parse)
{
   struct list ADDR[4];
   char *addr[4];
   char parsed_ip[16];
   char *p, *q;
   int i = 0, j;
   int permut = 1;
   static int k = 0;
 
   memset(&ADDR, 0, sizeof(ADDR));
   
   p = to_parse;
   
   while ( (q = strtok(p, ".")) ) {
      addr[i++] = strdup(q);
      if (p != NULL) p = NULL;
      if (i > 4) break;
   }
  
   if (i != 4) 
      Error_msg("Invalid IP format !!");
   
   DEBUG_MSG("Parser_Expand_List -- [%s] [%s] [%s] [%s]", addr[0], addr[1], addr[2], addr[3]);
  
   for (i = 0; i < 4; i++) {
      p = addr[i];
      Parser_Expand_Token(p, &ADDR[i]);
   }

   for (i = 0; i < 4; i++)     /* count the free permutations */
      permut *= ADDR[i].n; 
   
   for (i = 0; i < permut; i++) {
     
      sprintf(parsed_ip, "%d.%d.%d.%d",  ADDR[0].values[ADDR[0].cur],
                                         ADDR[1].values[ADDR[1].cur],
                                         ADDR[2].values[ADDR[2].cur],
                                         ADDR[3].values[ADDR[3].cur]);
      
   DEBUG_MSG("\t\t%s", parsed_ip);
      
      Host_List[k++] = strdup(parsed_ip);
      Host_List = realloc(Host_List, (k+2)*sizeof(char *));
      if (Host_List == NULL)
         ERROR_MSG("realloc()");
      
      
      ADDR[3].cur++;                /* give the impulse to the last octet */
      
      for (j = 2; j >= 0; j--) {    /* adjust the other as in a digital counter */
         if ( ADDR[j+1].cur >= ADDR[j+1].n  ) {
            ADDR[j].cur++;
            ADDR[j+1].cur = 0;
         }
      }
      
      Parser_StatusBar(permut);
      
   }
   
   for (i = 0; i < 4; i++)
      free(addr[i]);
              
   return permut;
}


int Parser_HostList(char *to_parse)
{
   char *ip;
   int i = 0;

   fprintf(stdout, "Expanding the -H option hosts list...\n\n");
   
   DEBUG_MSG("Parser_HostList - [%s]", to_parse);

   if (strstr(to_parse, " ") || strstr(to_parse, "%") )
      Error_msg("\nThe host list has an invalid format...");

   Host_List = calloc(2, sizeof(char *)); /* the list is modified by Parser_Expand_List */
   if (Host_List == NULL)
      ERROR_MSG("calloc()");
   
   for(ip=strsep(&to_parse, ";"); ip != NULL; ip=strsep(&to_parse, ";")) 
      i += Parser_Expand_List(ip);

   fprintf(stdout, "\n");

   DEBUG_MSG("Parser_HostList - expanded hosts [%d]", i);
   
   return i;
}



/* Pattern matching code from OpenSSH. */
int match_pattern(const char *s, const char *pattern)
{
   for (;;) {
      if (!*pattern) return (!*s);

      if (*pattern == '*') {
         pattern++;

         if (!*pattern) return (1);

         if (*pattern != '?' && *pattern != '*') {
            for (; *s; s++) {
               if (*s == *pattern && match_pattern(s + 1, pattern + 1))
                  return (1);
            }
            return (0);
         }
         for (; *s; s++) {
            if (match_pattern(s, pattern))
               return (1);
         }
         return (0);
      }
      if (!*s) return (0);

      if (*pattern != '?' && *pattern != *s)
         return (0);

      s++;
      pattern++;
   }
   /* NOTREACHED */
}


char *Parser_StrSpacetoUnder(char *h_name)
{
   int i;
   static char toggle_name[200];

   strcpy(toggle_name, h_name);
   i = strlen(toggle_name);

   for (i--;i>=0;i--)
      if (toggle_name[i]==' ')
         toggle_name[i]='_';

   return toggle_name;
}



void Parser_StatusBar(int max)
{
   static int progress = 1;

   if (!Options.onscreen && !Options.gtk) {
      float percent;
      int i;

      percent = (float)(progress)*100/(max);

   /* we use stderr to avoid scrambling of logfile generated by: ettercap -Nl > logfile */

      switch(progress % 4) {
         case 0:
               fprintf(stderr, "\r| |");
               break;
         case 1:
               fprintf(stderr, "\r/ |");
               break;
         case 2:
               fprintf(stderr, "\r- |");
               break;
         case 3:
               fprintf(stderr, "\r\\ |");
               break;
      }

      for (i=0; i < percent/2; i++)
         fprintf(stderr, "=");

      fprintf(stderr, ">");

      for(; i < 50; i++)
         fprintf(stderr, " ");

      fprintf(stderr, "| %6.2f %%", percent );

      fflush(stderr);

      if (progress == max) {
         progress = 1;
         fprintf(stderr, "\r* |==================================================>| 100.00 %%\n");
         return;
      }

      progress++;

   } 
#ifdef HAVE_GTK
   else if(Options.gtk) {
      gdouble percent;

      percent = (gdouble)(progress)/(max);
      Ginterface_Splash_Progress_Change(percent);
      progress++;
   }
#endif
}






/* EOF */


// vim:ts=3:expandtab

