"Fossies" - the Fresh Open Source Software Archive

Member "ettercap-0.8.3.1/src/ec_redirect.c" (1 Aug 2020, 15184 Bytes) of package /linux/privat/ettercap-0.8.3.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ec_redirect.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.8.3_vs_0.8.3.1.

    1 /*
    2     ettercap -- manage traffic redirect
    3 
    4     Copyright (C) ALoR & NaGA
    5 
    6     This program is free software; you can redistribute it and/or modify
    7     it under the terms of the GNU General Public License as published by
    8     the Free Software Foundation; either version 2 of the License, or
    9     (at your option) any later version.
   10 
   11     This program is distributed in the hope that it will be useful,
   12     but WITHOUT ANY WARRANTY; without even the implied warranty of
   13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14     GNU General Public License for more details.
   15 
   16     You should have received a copy of the GNU General Public License
   17     along with this program; if not, write to the Free Software
   18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   19 
   20 */
   21 
   22 #include <ec.h>
   23 #include <ec_redirect.h>
   24 
   25 #ifndef OS_WINDOWS
   26    #include <sys/wait.h>
   27 #endif
   28 
   29 #if defined(OS_DARWIN) || defined(OS_BSD)
   30    #define IPFW_SET "20"
   31    #define IPV4_ANY "any"
   32    #define IPV6_ANY "any"
   33 #else
   34    #define IPV4_ANY "0.0.0.0/0"
   35    #define IPV6_ANY "::/0"
   36 #endif
   37 
   38 
   39 /* proto */
   40 static int set_redir_command(ec_redir_proto_t proto, char *commands[]);
   41 static void register_redir_service(char *name,
   42       u_int16 from_port, u_int16 to_port);
   43 
   44 /* globals */
   45 static LIST_HEAD (, redir_entry) redirect_entries;
   46 static SLIST_HEAD (, serv_entry) redirect_services;
   47 
   48 enum {
   49    EC_REDIR_COMMAND_INSERT,
   50    EC_REDIR_COMMAND_REMOVE
   51 };
   52 
   53 /*
   54  * execute the script to add or remove the redirection
   55  */
   56 int ec_redirect(ec_redir_act_t action, char *name, ec_redir_proto_t proto,
   57       const char *destination, u_int16 sport, u_int16 dport)
   58 {
   59    char asc_sport[16];
   60    char asc_dport[16];
   61    char asc_destination[MAX_ASCII_ADDR_LEN];
   62    int  ret_val = 0;
   63    char *param[4];
   64    char *commands[2] = {NULL, NULL};
   65    char *command = NULL;
   66    struct redir_entry *re, *tmp;
   67    char *str_dstnet = NULL;
   68    char *str_dstmask = NULL;
   69    char *str_tmp = NULL;
   70    u_char *binmask = NULL;
   71 
   72    /* undefined defaults to any */
   73    switch (proto) {
   74       case EC_REDIR_PROTO_IPV4:
   75          if (destination == NULL)
   76             destination = "0.0.0.0/0";
   77          break;
   78       case EC_REDIR_PROTO_IPV6:
   79          if (destination == NULL)
   80             destination = "::/0";
   81          break;
   82       default:
   83          DEBUG_MSG("ec_redirect(): invalid address family given");
   84          return -E_INVALID;
   85    }
   86 
   87 
   88    DEBUG_MSG("ec_redirect(\"%s\", \"%s\", %s, %s, %d, %d)",
   89          (action == EC_REDIR_ACTION_INSERT ? "insert" : "remove"),
   90          name,
   91          (proto == EC_REDIR_PROTO_IPV4 ? "IPv4" : "IPv6"),
   92          destination,
   93          sport,
   94          dport);
   95    /* check and set redirects commands from etter.conf */
   96    set_redir_command(proto, commands);
   97 
   98 
   99    /* insert or remove commands */
  100    switch (action) {
  101       case EC_REDIR_ACTION_INSERT:
  102          /* check if entry is already present */
  103          LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) {
  104             if (proto == re->proto &&
  105                 !strcmp(destination, re->destination) &&
  106                 sport == re->from_port && dport == re->to_port) {
  107                DEBUG_MSG("ec_redirect(): redirect entry already present");
  108                return -E_INVALID;
  109             }
  110          }
  111          /* get command and check if it's defined */
  112          command = commands[EC_REDIR_COMMAND_INSERT];
  113          if (command == NULL) {
  114             DEBUG_MSG("ec_redirect(): redirect insert command for %s desired "
  115                   "but not set in etter.conf - skipping...",
  116                   proto == EC_REDIR_PROTO_IPV4 ? "IPv4" : "IPv6");
  117             return -E_NOTHANDLED;
  118          }
  119 
  120          /* allocate memory for redirect entry and parse input and set values */
  121          SAFE_CALLOC(re, 1, sizeof(struct redir_entry));
  122 
  123          re->name = strdup(name);
  124          re->proto = proto;
  125          re->destination = strdup(destination);
  126          re->from_port = sport;
  127          re->to_port = dport;
  128          re->orig_nport = htons(sport);
  129 
  130          /* parse destination specification */
  131          str_tmp = strdup(destination);
  132          str_dstnet = ec_strtok(str_tmp, "/", &str_dstmask);
  133          if (str_dstnet != NULL) {
  134             /* convert network */
  135             if (ip_addr_pton(str_dstnet, &re->dst_network) != E_SUCCESS)
  136                goto clean_abort;
  137 
  138             /* convert prefix length to netmask */
  139             if (str_dstmask != NULL && strlen(str_dstmask)) {
  140                /* prefix length specified */
  141                u_int32 dstmask;
  142                if ((dstmask = strtoul(str_dstmask, NULL, 10)) <= 128) {
  143                   binmask = ec_plen_to_binary(ntohs(re->dst_network.addr_len), dstmask);
  144                   ip_addr_init(&re->dst_netmask, ntohs(re->dst_network.addr_type), binmask);
  145                   SAFE_FREE(binmask);
  146                   SAFE_FREE(str_tmp);
  147                }
  148                else
  149                   goto clean_abort;
  150             }
  151             else {
  152                /* no prefix length specified */
  153                u_int32 dstmask;
  154 
  155                /* assume full (host) prefix length */
  156                dstmask = ntohs(re->dst_network.addr_len) * 8;
  157                binmask = ec_plen_to_binary(ntohs(re->dst_network.addr_len), dstmask);
  158                ip_addr_init(&re->dst_netmask, ntohs(re->dst_network.addr_type), binmask);
  159                SAFE_FREE(binmask);
  160                SAFE_FREE(str_tmp);
  161             }
  162          }
  163          else /* destination specification invalid */
  164             goto clean_abort;
  165 
  166          /* sanity check */
  167          switch (proto) {
  168             case EC_REDIR_PROTO_IPV4:
  169                if (ntohs(re->dst_network.addr_type) != AF_INET) {
  170                   DEBUG_MSG("ec_redirect(): address family mixup! - aborting");
  171                   goto clean_abort;
  172                }
  173                break;
  174             case EC_REDIR_PROTO_IPV6:
  175                if (ntohs(re->dst_network.addr_type) != AF_INET6) {
  176                   DEBUG_MSG("ec_redirect(): address family mixup! - aborting");
  177                   goto clean_abort;
  178                }
  179                break;
  180             default:
  181 clean_abort:
  182                SAFE_FREE(re->name);
  183                SAFE_FREE(re->destination);
  184                SAFE_FREE(re);
  185                SAFE_FREE(str_tmp);
  186                return -E_INVALID;
  187                break;
  188          }
  189          break;
  190       case EC_REDIR_ACTION_REMOVE:
  191          /* check if entry is still present */
  192          LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) {
  193             if (proto == re->proto &&
  194                 !strcmp(destination, re->destination) &&
  195                 sport == re->from_port && dport == re->to_port) {
  196                /* entry present - ready to be removed */
  197                command = commands[EC_REDIR_COMMAND_REMOVE];
  198                if (command == NULL) {
  199                   DEBUG_MSG("ec_redirect(): redirect insert command for %s "
  200                         "desired but not set in etter.conf - skipping...",
  201                         proto == EC_REDIR_PROTO_IPV4 ? "IPv4" : "IPv6");
  202                   return -E_NOTHANDLED;
  203                }
  204                break;
  205             }
  206          }
  207          if (command == NULL) {
  208             DEBUG_MSG("ec_redirect(): redirect entry not present anymore");
  209             return -E_INVALID;
  210          }
  211          break;
  212       default:
  213          DEBUG_MSG("ec_redirect(): no valid action defined - aborting!");
  214          return -E_FATAL;
  215    }
  216 
  217    /* ready to complete redirect commands */
  218    if (!strcmp(destination, "0.0.0.0/0")) {
  219       snprintf(asc_destination, MAX_ASCII_ADDR_LEN, "%s", IPV4_ANY);
  220    }
  221    else if (!strcmp(destination, "::/0")) {
  222       snprintf(asc_destination, MAX_ASCII_ADDR_LEN, "%s", IPV6_ANY);
  223    }
  224    else {
  225       snprintf(asc_destination, MAX_ASCII_ADDR_LEN, "%s", destination);
  226    }
  227 
  228    snprintf(asc_sport, 16, "%u", sport);
  229    snprintf(asc_dport, 16, "%u", dport);
  230 
  231 
  232    /* make the substitutions in the script */
  233    str_replace(&command, "%iface", EC_GBL_OPTIONS->iface);
  234    str_replace(&command, "%destination", asc_destination);
  235    str_replace(&command, "%port", asc_sport);
  236    str_replace(&command, "%rport", asc_dport);
  237 
  238 #if defined(OS_DARWIN) || defined(OS_BSD)
  239    str_replace(&command, "%set", IPFW_SET);
  240 #endif
  241 
  242    DEBUG_MSG("ec_redirect(): execute [%s]", command);
  243 
  244    /* construct the params array for execvp */
  245    param[0] = "sh";
  246    param[1] = "-c";
  247    param[2] = command;
  248    param[3] = NULL;
  249 
  250    /* execute the script */
  251    switch (fork()) {
  252       case 0:
  253          regain_privs();
  254          execvp(param[0], param);
  255          drop_privs();
  256          WARN_MSG("Cannot setup redirect (command: %s), please edit your "
  257                "etter.conf file and put a valid value in redir_command_on"
  258                "|redir_command_off field\n", param[0]);
  259          SAFE_FREE(command);
  260          SAFE_FREE(re->name);
  261          SAFE_FREE(re->destination);
  262          SAFE_FREE(re);
  263          _exit(-E_INVALID);
  264       case -1:
  265          SAFE_FREE(command);
  266          return -E_INVALID;
  267       default:
  268          wait(&ret_val);
  269          if (WIFEXITED(ret_val) && WEXITSTATUS(ret_val)) {
  270             DEBUG_MSG("ec_redirect(): child exited with non-zero return "
  271                   "code: %d", WEXITSTATUS(ret_val));
  272             USER_MSG("ec_redirect(): redir_command_on had non-zero exit "
  273                   "status (%d): [%s]\n", WEXITSTATUS(ret_val), command);
  274             SAFE_FREE(command);
  275             SAFE_FREE(re->name);
  276             SAFE_FREE(re->destination);
  277             SAFE_FREE(re);
  278             return -E_INVALID;
  279          }
  280          else { /* redirect command exited normally */
  281             switch (action) {
  282                case EC_REDIR_ACTION_INSERT:
  283                   /* register entry */
  284                   LIST_INSERT_HEAD(&redirect_entries, re, next);
  285                   register_redir_service(name, sport, dport);
  286                   break;
  287                case EC_REDIR_ACTION_REMOVE:
  288                   /* remove entry from list */
  289                   LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) {
  290                      if (re->proto == proto && 
  291                          !strcmp(re->destination, destination) &&
  292                          sport == re->from_port &&
  293                          dport == re->to_port) {
  294                         LIST_REMOVE(re, next);
  295                         SAFE_FREE(re->name);
  296                         SAFE_FREE(re->destination);
  297                         SAFE_FREE(re);
  298                      }
  299                   }
  300 
  301                   break;
  302                default:
  303                   break;
  304             }
  305          }
  306    }
  307 
  308    SAFE_FREE(command);
  309    return E_SUCCESS;
  310 }
  311 
  312 /* check and set redirect commands from etter.conf */
  313 static int set_redir_command(ec_redir_proto_t proto, char *commands[])
  314 {
  315 
  316    switch (proto) {
  317       case EC_REDIR_PROTO_IPV4:
  318          /* the script is not defined */
  319          if (EC_GBL_CONF->redir_command_on == NULL)
  320          {
  321             USER_MSG("set_redir_commands(): cannot setup the redirect, did "
  322                   "you uncomment the redir_command_on command on your "
  323                   "etter.conf file?\n");
  324             return -E_FATAL;
  325          }
  326 
  327          commands[EC_REDIR_COMMAND_INSERT] =
  328             strdup(EC_GBL_CONF->redir_command_on);
  329 
  330          /* the script is not defined */
  331          if (EC_GBL_CONF->redir_command_off == NULL)
  332          {
  333             USER_MSG("set_redir_commands(): cannot remove the redirect, did "
  334                   "you uncomment the redir_command_off command on your "
  335                   "etter.conf file?\n");
  336             return -E_FATAL;
  337          }
  338 
  339          commands[EC_REDIR_COMMAND_REMOVE] =
  340             strdup(EC_GBL_CONF->redir_command_off);
  341          break;
  342 
  343 #ifdef WITH_IPV6
  344       case EC_REDIR_PROTO_IPV6:
  345 
  346          /* IPv6 redirect script is optional */
  347          if (EC_GBL_CONF->redir6_command_on == NULL)
  348          {
  349             USER_MSG("set_redir_commands(): cannot setup the redirect for "
  350                   "IPv6, did you uncomment the redir6_command_on command on "
  351                   "your etter.conf file?\n");
  352             return -E_FATAL;
  353          }
  354 
  355          commands[EC_REDIR_COMMAND_INSERT] =
  356             strdup(EC_GBL_CONF->redir6_command_on);
  357 
  358          if (EC_GBL_CONF->redir6_command_off == NULL)
  359          {
  360             USER_MSG("set_redir_commands(): cannot remove the redirect for "
  361                   "IPv6, did you uncommend the redir6_command_off command in "
  362                   "your etter.conf file?\n");
  363             return -E_FATAL;
  364          }
  365 
  366          commands[EC_REDIR_COMMAND_REMOVE] =
  367             strdup(EC_GBL_CONF->redir6_command_off);
  368          break;
  369 #endif
  370 
  371       default:
  372          return -E_INVALID;
  373    }
  374 
  375    return E_SUCCESS;
  376 
  377 }
  378 
  379 /*
  380  * compile the list of registered redirects
  381  */
  382 int ec_walk_redirects(void (*func)(struct redir_entry*))
  383 {
  384    struct redir_entry *re, *tmp;
  385    int i = 0;
  386 
  387    DEBUG_MSG("ec_walk_redirects()");
  388 
  389    LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) {
  390       func(re);
  391       i++;
  392    }
  393 
  394    return i ? i : -E_NOTFOUND;
  395 }
  396 
  397 /*
  398  * check if a packet matches a installed redirect
  399  */
  400 int ec_redirect_lookup(struct packet_object *po)
  401 {
  402    struct redir_entry *re, *tmp;
  403    struct ip_addr srv_network;
  404 
  405    LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) {
  406       if (po->L4.dst == re->orig_nport) {
  407          /* port matched - now check on the IPs */
  408          ip_addr_get_network(&po->L3.dst, &re->dst_netmask, &srv_network);
  409          if (!ip_addr_cmp(&re->dst_network, &srv_network))
  410             return E_SUCCESS;
  411       }
  412       else if (po->L4.src == re->orig_nport) {
  413          /* port matched - now check on the IPs */
  414          ip_addr_get_network(&po->L3.src, &re->dst_netmask, &srv_network);
  415          if (!ip_addr_cmp(&re->dst_network, &srv_network))
  416             return E_SUCCESS;
  417       }
  418    }
  419    return -E_NOMATCH;
  420 }
  421 
  422 /*
  423  * remove all registered redirects
  424  */
  425 void ec_redirect_cleanup(void)
  426 {
  427    struct redir_entry *re, *tmp;
  428    struct serv_entry *se, *stmp;
  429 
  430    DEBUG_MSG("ec_redirect_cleanup()");
  431 
  432    LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp)
  433       ec_redirect(EC_REDIR_ACTION_REMOVE, re->name, re->proto,
  434             re->destination, re->from_port, re->to_port);
  435 
  436    SLIST_FOREACH_SAFE(se, &redirect_services, next, stmp) {
  437       SAFE_FREE(se->name);
  438       SAFE_FREE(se);
  439    }
  440 }
  441 
  442 /*
  443  * store redirect services in a unique list
  444  */
  445 static void register_redir_service(char *name,
  446       u_int16 from_port, u_int16 to_port)
  447 {
  448    struct serv_entry *se;
  449 
  450    DEBUG_MSG("register_redir_service(%s)", name);
  451 
  452    /* avoid duplicates */
  453    SLIST_FOREACH(se, &redirect_services, next)
  454       if (se->from_port == from_port && se->to_port == to_port)
  455          return;
  456 
  457    SAFE_CALLOC(se, 1, sizeof(struct serv_entry));
  458    se->name = strdup(name);
  459    se->from_port = from_port;
  460    se->to_port = to_port;
  461 
  462    SLIST_INSERT_HEAD(&redirect_services, se, next);
  463 
  464 }
  465 
  466 /*
  467  * compile the list of redirectable services
  468  */
  469 int ec_walk_redirect_services(void (*func)(struct serv_entry*))
  470 {
  471    struct serv_entry *se, *tmp;
  472    int i = 0;
  473 
  474    DEBUG_MSG("ec_walk_redirect_services()");
  475 
  476    SLIST_FOREACH_SAFE(se, &redirect_services, next, tmp) {
  477       func(se);
  478       i++;
  479    }
  480 
  481    return i ? i : -E_NOTFOUND;
  482 }
  483 
  484 /* EOF */
  485 
  486 // vim:ts=3:expandtab
  487