"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