ec_redirect.c (ettercap-0.8.3) | : | ec_redirect.c (ettercap-0.8.3.1) | ||
---|---|---|---|---|
skipping to change at line 56 | skipping to change at line 56 | |||
enum { | enum { | |||
EC_REDIR_COMMAND_INSERT, | EC_REDIR_COMMAND_INSERT, | |||
EC_REDIR_COMMAND_REMOVE | EC_REDIR_COMMAND_REMOVE | |||
}; | }; | |||
/* | /* | |||
* execute the script to add or remove the redirection | * execute the script to add or remove the redirection | |||
*/ | */ | |||
int ec_redirect(ec_redir_act_t action, char *name, ec_redir_proto_t proto, | int ec_redirect(ec_redir_act_t action, char *name, ec_redir_proto_t proto, | |||
const char *source, const char *destination, | const char *destination, u_int16 sport, u_int16 dport) | |||
u_int16 sport, u_int16 dport) | ||||
{ | { | |||
char asc_sport[16]; | char asc_sport[16]; | |||
char asc_dport[16]; | char asc_dport[16]; | |||
char asc_source[MAX_ASCII_ADDR_LEN]; | ||||
char asc_destination[MAX_ASCII_ADDR_LEN]; | char asc_destination[MAX_ASCII_ADDR_LEN]; | |||
int ret_val = 0; | int ret_val = 0; | |||
char *param[4]; | char *param[4]; | |||
char *commands[2] = {NULL, NULL}; | char *commands[2] = {NULL, NULL}; | |||
char *command = NULL; | char *command = NULL; | |||
struct redir_entry *re, *tmp; | struct redir_entry *re, *tmp; | |||
char *str_dstnet = NULL; | ||||
char *str_dstmask = NULL; | ||||
char *str_tmp = NULL; | ||||
u_char *binmask = NULL; | ||||
/* undefined defaults to any */ | /* undefined defaults to any */ | |||
switch (proto) { | switch (proto) { | |||
case EC_REDIR_PROTO_IPV4: | case EC_REDIR_PROTO_IPV4: | |||
if (source == NULL || !strcmp(source, "0.0.0.0/0")) | if (destination == NULL) | |||
source = IPV4_ANY; | destination = "0.0.0.0/0"; | |||
if (destination == NULL || !strcmp(destination, "0.0.0.0/0")) | ||||
destination = IPV4_ANY; | ||||
break; | break; | |||
case EC_REDIR_PROTO_IPV6: | case EC_REDIR_PROTO_IPV6: | |||
if (source == NULL || !strcmp(source, "::/0")) | if (destination == NULL) | |||
source = IPV6_ANY; | destination = "::/0"; | |||
if (destination == NULL || !strcmp(destination, "::/0")) | ||||
destination = IPV6_ANY; | ||||
break; | break; | |||
default: | default: | |||
DEBUG_MSG("ec_redirect(): invalid address family given"); | DEBUG_MSG("ec_redirect(): invalid address family given"); | |||
return -E_INVALID; | return -E_INVALID; | |||
} | } | |||
DEBUG_MSG("ec_redirect(\"%s\", \"%s\", %s, %s, %s, %d, %d)", | DEBUG_MSG("ec_redirect(\"%s\", \"%s\", %s, %s, %d, %d)", | |||
(action == EC_REDIR_ACTION_INSERT ? "insert" : "remove"), | (action == EC_REDIR_ACTION_INSERT ? "insert" : "remove"), | |||
name, | name, | |||
(proto == EC_REDIR_PROTO_IPV4 ? "IPv4" : "IPv6"), | (proto == EC_REDIR_PROTO_IPV4 ? "IPv4" : "IPv6"), | |||
source, | ||||
destination, | destination, | |||
sport, | sport, | |||
dport); | dport); | |||
/* check and set redirects commands from etter.conf */ | /* check and set redirects commands from etter.conf */ | |||
set_redir_command(proto, commands); | set_redir_command(proto, commands); | |||
/* insert or remove commands */ | /* insert or remove commands */ | |||
switch (action) { | switch (action) { | |||
case EC_REDIR_ACTION_INSERT: | case EC_REDIR_ACTION_INSERT: | |||
/* check if entry is already present */ | /* check if entry is already present */ | |||
LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | |||
if (proto == re->proto && | if (proto == re->proto && | |||
!strcmp(source, re->source) && | ||||
!strcmp(destination, re->destination) && | !strcmp(destination, re->destination) && | |||
sport == re->from_port && dport == re->to_port) { | sport == re->from_port && dport == re->to_port) { | |||
DEBUG_MSG("ec_redirect(): redirect entry already present"); | DEBUG_MSG("ec_redirect(): redirect entry already present"); | |||
return -E_INVALID; | return -E_INVALID; | |||
} | } | |||
} | } | |||
/* get command and check if it's defined */ | ||||
command = commands[EC_REDIR_COMMAND_INSERT]; | command = commands[EC_REDIR_COMMAND_INSERT]; | |||
if (command == NULL) { | ||||
DEBUG_MSG("ec_redirect(): redirect insert command for %s desired " | ||||
"but not set in etter.conf - skipping...", | ||||
proto == EC_REDIR_PROTO_IPV4 ? "IPv4" : "IPv6"); | ||||
return -E_NOTHANDLED; | ||||
} | ||||
/* allocate memory for redirect entry and parse input and set values */ | ||||
SAFE_CALLOC(re, 1, sizeof(struct redir_entry)); | ||||
re->name = strdup(name); | ||||
re->proto = proto; | ||||
re->destination = strdup(destination); | ||||
re->from_port = sport; | ||||
re->to_port = dport; | ||||
re->orig_nport = htons(sport); | ||||
/* parse destination specification */ | ||||
str_tmp = strdup(destination); | ||||
str_dstnet = ec_strtok(str_tmp, "/", &str_dstmask); | ||||
if (str_dstnet != NULL) { | ||||
/* convert network */ | ||||
if (ip_addr_pton(str_dstnet, &re->dst_network) != E_SUCCESS) | ||||
goto clean_abort; | ||||
/* convert prefix length to netmask */ | ||||
if (str_dstmask != NULL && strlen(str_dstmask)) { | ||||
/* prefix length specified */ | ||||
u_int32 dstmask; | ||||
if ((dstmask = strtoul(str_dstmask, NULL, 10)) <= 128) { | ||||
binmask = ec_plen_to_binary(ntohs(re->dst_network.addr_len), d | ||||
stmask); | ||||
ip_addr_init(&re->dst_netmask, ntohs(re->dst_network.addr_type | ||||
), binmask); | ||||
SAFE_FREE(binmask); | ||||
SAFE_FREE(str_tmp); | ||||
} | ||||
else | ||||
goto clean_abort; | ||||
} | ||||
else { | ||||
/* no prefix length specified */ | ||||
u_int32 dstmask; | ||||
/* assume full (host) prefix length */ | ||||
dstmask = ntohs(re->dst_network.addr_len) * 8; | ||||
binmask = ec_plen_to_binary(ntohs(re->dst_network.addr_len), dstm | ||||
ask); | ||||
ip_addr_init(&re->dst_netmask, ntohs(re->dst_network.addr_type), | ||||
binmask); | ||||
SAFE_FREE(binmask); | ||||
SAFE_FREE(str_tmp); | ||||
} | ||||
} | ||||
else /* destination specification invalid */ | ||||
goto clean_abort; | ||||
/* sanity check */ | ||||
switch (proto) { | ||||
case EC_REDIR_PROTO_IPV4: | ||||
if (ntohs(re->dst_network.addr_type) != AF_INET) { | ||||
DEBUG_MSG("ec_redirect(): address family mixup! - aborting"); | ||||
goto clean_abort; | ||||
} | ||||
break; | ||||
case EC_REDIR_PROTO_IPV6: | ||||
if (ntohs(re->dst_network.addr_type) != AF_INET6) { | ||||
DEBUG_MSG("ec_redirect(): address family mixup! - aborting"); | ||||
goto clean_abort; | ||||
} | ||||
break; | ||||
default: | ||||
clean_abort: | ||||
SAFE_FREE(re->name); | ||||
SAFE_FREE(re->destination); | ||||
SAFE_FREE(re); | ||||
SAFE_FREE(str_tmp); | ||||
return -E_INVALID; | ||||
break; | ||||
} | ||||
break; | break; | |||
case EC_REDIR_ACTION_REMOVE: | case EC_REDIR_ACTION_REMOVE: | |||
/* check if entry is still present */ | /* check if entry is still present */ | |||
LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | |||
if (proto == re->proto && | if (proto == re->proto && | |||
!strcmp(source, re->source) && | ||||
!strcmp(destination, re->destination) && | !strcmp(destination, re->destination) && | |||
sport == re->from_port && dport == re->to_port) { | sport == re->from_port && dport == re->to_port) { | |||
/* entry present - ready to be removed */ | /* entry present - ready to be removed */ | |||
command = commands[EC_REDIR_COMMAND_REMOVE]; | command = commands[EC_REDIR_COMMAND_REMOVE]; | |||
if (command == NULL) { | ||||
DEBUG_MSG("ec_redirect(): redirect insert command for %s " | ||||
"desired but not set in etter.conf - skipping...", | ||||
proto == EC_REDIR_PROTO_IPV4 ? "IPv4" : "IPv6"); | ||||
return -E_NOTHANDLED; | ||||
} | ||||
break; | break; | |||
} | } | |||
} | } | |||
if (command == NULL) { | if (command == NULL) { | |||
DEBUG_MSG("ec_redirect(): redirect entry not present anymore"); | DEBUG_MSG("ec_redirect(): redirect entry not present anymore"); | |||
return -E_INVALID; | return -E_INVALID; | |||
} | } | |||
break; | break; | |||
default: | default: | |||
DEBUG_MSG("ec_redirect(): no valid action defined - aborting!"); | DEBUG_MSG("ec_redirect(): no valid action defined - aborting!"); | |||
return -E_FATAL; | return -E_FATAL; | |||
} | } | |||
/* ready to complete redirect commands */ | /* ready to complete redirect commands */ | |||
snprintf(asc_source, MAX_ASCII_ADDR_LEN, "%s", source); | if (!strcmp(destination, "0.0.0.0/0")) { | |||
snprintf(asc_destination, MAX_ASCII_ADDR_LEN, "%s", destination); | snprintf(asc_destination, MAX_ASCII_ADDR_LEN, "%s", IPV4_ANY); | |||
} | ||||
else if (!strcmp(destination, "::/0")) { | ||||
snprintf(asc_destination, MAX_ASCII_ADDR_LEN, "%s", IPV6_ANY); | ||||
} | ||||
else { | ||||
snprintf(asc_destination, MAX_ASCII_ADDR_LEN, "%s", destination); | ||||
} | ||||
snprintf(asc_sport, 16, "%u", sport); | snprintf(asc_sport, 16, "%u", sport); | |||
snprintf(asc_dport, 16, "%u", dport); | snprintf(asc_dport, 16, "%u", dport); | |||
/* make the substitutions in the script */ | /* make the substitutions in the script */ | |||
str_replace(&command, "%iface", EC_GBL_OPTIONS->iface); | str_replace(&command, "%iface", EC_GBL_OPTIONS->iface); | |||
str_replace(&command, "%source", asc_source); | ||||
str_replace(&command, "%destination", asc_destination); | str_replace(&command, "%destination", asc_destination); | |||
str_replace(&command, "%port", asc_sport); | str_replace(&command, "%port", asc_sport); | |||
str_replace(&command, "%rport", asc_dport); | str_replace(&command, "%rport", asc_dport); | |||
#if defined(OS_DARWIN) || defined(OS_BSD) | #if defined(OS_DARWIN) || defined(OS_BSD) | |||
str_replace(&command, "%set", IPFW_SET); | str_replace(&command, "%set", IPFW_SET); | |||
#endif | #endif | |||
DEBUG_MSG("ec_redirect(): execute [%s]", command); | DEBUG_MSG("ec_redirect(): execute [%s]", command); | |||
skipping to change at line 171 | skipping to change at line 256 | |||
/* execute the script */ | /* execute the script */ | |||
switch (fork()) { | switch (fork()) { | |||
case 0: | case 0: | |||
regain_privs(); | regain_privs(); | |||
execvp(param[0], param); | execvp(param[0], param); | |||
drop_privs(); | drop_privs(); | |||
WARN_MSG("Cannot setup redirect (command: %s), please edit your " | WARN_MSG("Cannot setup redirect (command: %s), please edit your " | |||
"etter.conf file and put a valid value in redir_command_on" | "etter.conf file and put a valid value in redir_command_on" | |||
"|redir_command_off field\n", param[0]); | "|redir_command_off field\n", param[0]); | |||
SAFE_FREE(command); | SAFE_FREE(command); | |||
SAFE_FREE(re->name); | ||||
SAFE_FREE(re->destination); | ||||
SAFE_FREE(re); | ||||
_exit(-E_INVALID); | _exit(-E_INVALID); | |||
case -1: | case -1: | |||
SAFE_FREE(command); | SAFE_FREE(command); | |||
return -E_INVALID; | return -E_INVALID; | |||
default: | default: | |||
wait(&ret_val); | wait(&ret_val); | |||
if (WIFEXITED(ret_val) && WEXITSTATUS(ret_val)) { | if (WIFEXITED(ret_val) && WEXITSTATUS(ret_val)) { | |||
DEBUG_MSG("ec_redirect(): child exited with non-zero return " | DEBUG_MSG("ec_redirect(): child exited with non-zero return " | |||
"code: %d", WEXITSTATUS(ret_val)); | "code: %d", WEXITSTATUS(ret_val)); | |||
USER_MSG("ec_redirect(): redir_command_on had non-zero exit " | USER_MSG("ec_redirect(): redir_command_on had non-zero exit " | |||
"status (%d): [%s]\n", WEXITSTATUS(ret_val), command); | "status (%d): [%s]\n", WEXITSTATUS(ret_val), command); | |||
SAFE_FREE(command); | SAFE_FREE(command); | |||
SAFE_FREE(re->name); | ||||
SAFE_FREE(re->destination); | ||||
SAFE_FREE(re); | ||||
return -E_INVALID; | return -E_INVALID; | |||
} | } | |||
else { /* redirect command exited normally */ | else { /* redirect command exited normally */ | |||
/* register entry */ | ||||
switch (action) { | switch (action) { | |||
case EC_REDIR_ACTION_INSERT: | case EC_REDIR_ACTION_INSERT: | |||
SAFE_CALLOC(re, 1, sizeof(struct redir_entry)); | /* register entry */ | |||
re->name = strdup(name); | ||||
re->proto = proto; | ||||
re->source = strdup(source); | ||||
re->destination = strdup(destination); | ||||
re->from_port = sport; | ||||
re->to_port = dport; | ||||
LIST_INSERT_HEAD(&redirect_entries, re, next); | LIST_INSERT_HEAD(&redirect_entries, re, next); | |||
register_redir_service(name, sport, dport); | register_redir_service(name, sport, dport); | |||
break; | break; | |||
case EC_REDIR_ACTION_REMOVE: | case EC_REDIR_ACTION_REMOVE: | |||
/* remove entry from list */ | /* remove entry from list */ | |||
LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | |||
if (re->proto == proto && | if (re->proto == proto && | |||
!strcmp(re->source, source) && | ||||
!strcmp(re->destination, destination) && | !strcmp(re->destination, destination) && | |||
sport == re->from_port && | sport == re->from_port && | |||
dport == re->to_port) { | dport == re->to_port) { | |||
LIST_REMOVE(re, next); | LIST_REMOVE(re, next); | |||
SAFE_FREE(re->name); | SAFE_FREE(re->name); | |||
SAFE_FREE(re->source); | ||||
SAFE_FREE(re->destination); | SAFE_FREE(re->destination); | |||
SAFE_FREE(re); | SAFE_FREE(re); | |||
} | } | |||
} | } | |||
break; | break; | |||
default: | default: | |||
break; | break; | |||
} | } | |||
} | } | |||
skipping to change at line 315 | skipping to change at line 394 | |||
LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | |||
func(re); | func(re); | |||
i++; | i++; | |||
} | } | |||
return i ? i : -E_NOTFOUND; | return i ? i : -E_NOTFOUND; | |||
} | } | |||
/* | /* | |||
* check if a packet matches a installed redirect | ||||
*/ | ||||
int ec_redirect_lookup(struct packet_object *po) | ||||
{ | ||||
struct redir_entry *re, *tmp; | ||||
struct ip_addr srv_network; | ||||
LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) { | ||||
if (po->L4.dst == re->orig_nport) { | ||||
/* port matched - now check on the IPs */ | ||||
ip_addr_get_network(&po->L3.dst, &re->dst_netmask, &srv_network); | ||||
if (!ip_addr_cmp(&re->dst_network, &srv_network)) | ||||
return E_SUCCESS; | ||||
} | ||||
else if (po->L4.src == re->orig_nport) { | ||||
/* port matched - now check on the IPs */ | ||||
ip_addr_get_network(&po->L3.src, &re->dst_netmask, &srv_network); | ||||
if (!ip_addr_cmp(&re->dst_network, &srv_network)) | ||||
return E_SUCCESS; | ||||
} | ||||
} | ||||
return -E_NOMATCH; | ||||
} | ||||
/* | ||||
* remove all registered redirects | * remove all registered redirects | |||
*/ | */ | |||
void ec_redirect_cleanup(void) | void ec_redirect_cleanup(void) | |||
{ | { | |||
struct redir_entry *re, *tmp; | struct redir_entry *re, *tmp; | |||
struct serv_entry *se, *stmp; | struct serv_entry *se, *stmp; | |||
DEBUG_MSG("ec_redirect_cleanup()"); | DEBUG_MSG("ec_redirect_cleanup()"); | |||
LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) | LIST_FOREACH_SAFE(re, &redirect_entries, next, tmp) | |||
ec_redirect(EC_REDIR_ACTION_REMOVE, re->name, re->proto, | ec_redirect(EC_REDIR_ACTION_REMOVE, re->name, re->proto, | |||
re->source, re->destination, re->from_port, re->to_port); | re->destination, re->from_port, re->to_port); | |||
SLIST_FOREACH_SAFE(se, &redirect_services, next, stmp) { | SLIST_FOREACH_SAFE(se, &redirect_services, next, stmp) { | |||
SAFE_FREE(se->name); | SAFE_FREE(se->name); | |||
SAFE_FREE(se); | SAFE_FREE(se); | |||
} | } | |||
} | } | |||
/* | /* | |||
* store redirect services in a unique list | * store redirect services in a unique list | |||
*/ | */ | |||
End of changes. 23 change blocks. | ||||
32 lines changed or deleted | 140 lines changed or added |