diff --git a/iputils/iputils.c b/iputils/iputils.c index 389ea06ea06068bfa2523c6ca16403dceddeb515..0e16de9e96a627a1a61d89a10493d12fb23424e8 100644 --- a/iputils/iputils.c +++ b/iputils/iputils.c @@ -8,11 +8,17 @@ static bool LOG_VERBOSE = false; +/** + * Set verbose mode + */ void iputils_set_verbose(void) { LOG_VERBOSE = true; } +/** + * Reset verbose mode + */ void iputils_reset_verbose(void) { LOG_VERBOSE = false; diff --git a/iputils/iputils.h b/iputils/iputils.h index 3929172c013ee6ea1d43212944980076cab2c29a..244f566801bf73861d27ff8955eba6575db13715 100644 --- a/iputils/iputils.h +++ b/iputils/iputils.h @@ -32,12 +32,33 @@ int ping_util6(const char *addr, int count); /** + * Tracepath host * + * @addr[in] host name or IP address + * @hops[out] hops count + * @time_usec[out] latency in microseconds + * @return 0 Ok, -1 error */ int tracepath_util(const char *addr, int *hops, int *time_usec); + +/** + * Traceroute host + * + * @addr[in] host name or IP address + * @hops[out] hops count + * @time_usec[out] latency in microseconds + * @return 0 Ok, -1 error + */ int traceroute_util(const char *addr, int *hops, int *time_usec); + +/** + * Set verbose mode + */ void iputils_set_verbose(void); +/** + * Reset verbose mode + */ void iputils_reset_verbose(void); @@ -47,7 +68,7 @@ int log_printf(const char *format, ...); #define PACKAGE_NAME "iputils" #define PACKAGE_VERSION "0.1" #define IPUTILS_VERSION(_prog) "%s from %s %s\n", _prog, PACKAGE_NAME, PACKAGE_VERSION - +#define UNUSED(x) (void)(x) #ifdef __cplusplus } #endif diff --git a/iputils/ping.c b/iputils/ping.c index a5d320a4f8da227896396b2736cbeff3873a48b6..0c3ec725e875fc74aecc6554c3e617473612cb82 100644 --- a/iputils/ping.c +++ b/iputils/ping.c @@ -217,8 +217,7 @@ static double ping_strtod(const char *str, const char *err_msg) return 0.0; } -static int -ping_main(int argc, char **argv) +static int ping_main(int argc, char **argv) { struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_protocol = IPPROTO_UDP, .ai_socktype = SOCK_DGRAM, .ai_flags = getaddrinfo_flags }; diff --git a/iputils/tracepath.c b/iputils/tracepath.c index 5319e74f4025de42c2726254f5b45d289e8d0e26..7eda079a53be11edd3317acf6f2c9aee5c3ecf67 100755 --- a/iputils/tracepath.c +++ b/iputils/tracepath.c @@ -373,6 +373,7 @@ static int recverr(struct run_state * const ctl) return 0; } goto restart; + return 0; } static int probe_ttl(struct run_state * const ctl) @@ -716,6 +717,14 @@ int tracepath_main(int argc, char **argv, struct run_state *ctl) return -1; //exit(1); } +/** + * Tracepath host + * + * @addr[in] host name or IP address + * @hops[out] hops count + * @time_usec[out] latency in microseconds + * @return 0 Ok, -1 error + */ int tracepath_util(const char *addr, int *hops, int *time_usec) { int type = 4; // 4 or 6 @@ -761,7 +770,6 @@ int tracepath_util(const char *addr, int *hops, int *time_usec) deltatime->tv_sec * 1000000 + deltatime->tv_usec); }*/ } - //g_free((char*) argv[2]); if(hops) { *hops = total_hops; } diff --git a/iputils/traceroute/as_lookups.c b/iputils/traceroute/as_lookups.c index aedf7e1f2d631f86340102a7b6b3778154e02f71..873180375802bce154e491966ea68f81eab98522 100755 --- a/iputils/traceroute/as_lookups.c +++ b/iputils/traceroute/as_lookups.c @@ -66,7 +66,7 @@ const char *get_as_path (const char *query) { goto err_sk; n = snprintf (buf, sizeof (buf), "%s\r\n", query); - if (n >= sizeof (buf)) goto err_sk; + if (n >= (int)sizeof (buf)) goto err_sk; if (write (sk, buf, n) < n) goto err_sk; diff --git a/iputils/traceroute/clif.c b/iputils/traceroute/clif.c index 4ef20e454c27f4b7bdaccdcac85f47329ddb232d..4380e8ecd061e5becee1f296c89a8c8bbf127b51 100755 --- a/iputils/traceroute/clif.c +++ b/iputils/traceroute/clif.c @@ -1,19 +1,19 @@ /* - Copyright (c) 2000, 2003 Dmitry Butskoy - <buc@citadel.stu.neva.ru> - License: LGPL v2.1 or any later + Copyright (c) 2000, 2003 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: LGPL v2.1 or any later - See COPYING.LIB for the status of this software. -*/ + See COPYING.LIB for the status of this software. + */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdarg.h> +#include "../iputils.h" #include "clif.h" - #if 1 /* Bad idea, anyway... */ #define MAX_ARGC_NUMBER 256 typedef unsigned char _CLIF_index; @@ -22,1238 +22,1263 @@ typedef unsigned char _CLIF_index; typedef unsigned short _CLIF_index; #endif - /* This is needed for some print info functions. - This is ugly for thread-safe (is it really actual on program invoking?), - and for several CLIF_parse_cmdline invoking... But foo on this. Yeah... -*/ + This is ugly for thread-safe (is it really actual on program invoking?), + and for several CLIF_parse_cmdline invoking... But foo on this. Yeah... + */ static struct { - int argc; - char **argv; - CLIF_option *option_list; - CLIF_argument *argument_list; - unsigned int parse_flags; + int argc; + char **argv; + CLIF_option *option_list; + CLIF_argument *argument_list; + unsigned int parse_flags; } curr = { 0, }; - -static void err_report (const char *format, ...) { - va_list ap; +static void err_report(const char *format, ...) { + va_list ap; - if (curr.parse_flags & CLIF_SILENT) - return; + if(curr.parse_flags & CLIF_SILENT) + return; - va_start (ap, format); + va_start(ap, format); - vfprintf (stderr, format, ap); + vfprintf(stderr, format, ap); - va_end (ap); + va_end(ap); - fprintf (stderr, "\n"); + fprintf(stderr, "\n"); - return; + return; } - /* info generation stuff... */ #define SHORT_PLUS_MINUS "+/-" #define LONG_PLUS_MINUS "++/--" #define EXCL_DLM " | " -static char *show_short (const CLIF_option *optn) { - static char buf[80]; - char *p = buf; - unsigned int flags = optn->flags | curr.parse_flags; +static char *show_short(const CLIF_option *optn) { + static char buf[80]; + char *p = buf; + unsigned int flags = optn->flags | curr.parse_flags; - if (optn->function_plus) { - if (!optn->function) *p++ = '+'; - else { - strcpy (p, SHORT_PLUS_MINUS); - p += sizeof (SHORT_PLUS_MINUS) - 1; - } - } else - *p++ = '-'; + if(optn->function_plus) { + if(!optn->function) + *p++ = '+'; + else { + strcpy(p, SHORT_PLUS_MINUS); + p += sizeof(SHORT_PLUS_MINUS) - 1; + } + } else + *p++ = '-'; - *p++ = optn->short_opt[0]; + *p++ = optn->short_opt[0]; - if (optn->arg_name) { - char *endp = buf + sizeof (buf) - sizeof (",...]"); - const char *s; + if(optn->arg_name) { + char *endp = buf + sizeof(buf) - sizeof(",...]"); + const char *s; - if (!(flags & _CLIF_STRICT_JOIN_ARG)) *p++ = ' '; - if (flags & CLIF_OPTARG) *p++ = '['; + if(!(flags & _CLIF_STRICT_JOIN_ARG)) + *p++ = ' '; + if(flags & CLIF_OPTARG) + *p++ = '['; - s = optn->arg_name; - while (*s && p < endp) *p++ = *s++; + s = optn->arg_name; + while(*s && p < endp) + *p++ = *s++; - if (flags & CLIF_SEVERAL) { - strcpy (p, ",..."); - p += sizeof (",...") - 1; /* last '\0' ... */ - } + if(flags & CLIF_SEVERAL) { + strcpy(p, ",..."); + p += sizeof(",...") - 1; /* last '\0' ... */ + } - if (flags & CLIF_OPTARG) *p++ = ']'; - } + if(flags & CLIF_OPTARG) + *p++ = ']'; + } - *p = '\0'; + *p = '\0'; - return buf; + return buf; } - -static char *show_long (const CLIF_option *optn) { - static char buf[80]; - char *p = buf; - char *endp; - const char *s; - unsigned int flags = optn->flags | curr.parse_flags; - - - if (!(flags & _CLIF_STRICT_KEYWORD)) { - - if (!(flags & _CLIF_STRICT_ONEDASH)) { - if (optn->function_plus) { - if (!optn->function) { *p++ = '+'; *p++ = '+'; } - else { - strcpy (p, LONG_PLUS_MINUS); - p += sizeof (LONG_PLUS_MINUS) - 1; - } - } else { *p++ = '-'; *p++ = '-'; } - - } else { - if (optn->function_plus) { - if (!optn->function) *p++ = '+'; - else { - strcpy (p, SHORT_PLUS_MINUS); - p += sizeof (SHORT_PLUS_MINUS) - 1; - } - } else *p++ = '-'; - } - } - - s = optn->long_opt; - endp = buf + sizeof (buf) - sizeof (" ["); - while (*s && p < endp) *p++ = *s++; - - if (optn->arg_name) { - - if (flags & _CLIF_STRICT_NOEQUAL) { - *p++ = ' '; - if (flags & CLIF_OPTARG) *p++ = '['; - } else { - if (flags & CLIF_OPTARG) *p++ = '['; - *p++ = '='; - } - - s = optn->arg_name; - endp = buf + sizeof (buf) - sizeof (",...]"); - while (*s && p < endp) *p++ = *s++; - - if (flags & CLIF_SEVERAL) { - strcpy (p, ",..."); - p += sizeof (",...") - 1; /* last '\0' ... */ - } - - if (flags & CLIF_OPTARG) *p++ = ']'; - } - - *p = '\0'; - - return buf; + +static char *show_long(const CLIF_option *optn) { + static char buf[80]; + char *p = buf; + char *endp; + const char *s; + unsigned int flags = optn->flags | curr.parse_flags; + + if(!(flags & _CLIF_STRICT_KEYWORD)) { + + if(!(flags & _CLIF_STRICT_ONEDASH)) { + if(optn->function_plus) { + if(!optn->function) { + *p++ = '+'; + *p++ = '+'; + } + else { + strcpy(p, LONG_PLUS_MINUS); + p += sizeof(LONG_PLUS_MINUS) - 1; + } + } else { + *p++ = '-'; + *p++ = '-'; + } + + } else { + if(optn->function_plus) { + if(!optn->function) + *p++ = '+'; + else { + strcpy(p, SHORT_PLUS_MINUS); + p += sizeof(SHORT_PLUS_MINUS) - 1; + } + } else + *p++ = '-'; + } + } + + s = optn->long_opt; + endp = buf + sizeof(buf) - sizeof(" ["); + while(*s && p < endp) + *p++ = *s++; + + if(optn->arg_name) { + + if(flags & _CLIF_STRICT_NOEQUAL) { + *p++ = ' '; + if(flags & CLIF_OPTARG) + *p++ = '['; + } else { + if(flags & CLIF_OPTARG) + *p++ = '['; + *p++ = '='; + } + + s = optn->arg_name; + endp = buf + sizeof(buf) - sizeof(",...]"); + while(*s && p < endp) + *p++ = *s++; + + if(flags & CLIF_SEVERAL) { + strcpy(p, ",..."); + p += sizeof(",...") - 1; /* last '\0' ... */ + } + + if(flags & CLIF_OPTARG) + *p++ = ']'; + } + + *p = '\0'; + + return buf; } -static char *show_excl (const CLIF_option *option_list, int *cnt_p) { - static char buf[256]; - const CLIF_option *optn; - char *p = buf; - char *endp = buf + sizeof (buf) - sizeof (EXCL_DLM); - int excl_cnt = 0; +static char *show_excl(const CLIF_option *option_list, int *cnt_p) { + static char buf[256]; + const CLIF_option *optn; + char *p = buf; + char *endp = buf + sizeof(buf) - sizeof(EXCL_DLM); + int excl_cnt = 0; - *p = '\0'; - if (cnt_p) *cnt_p = 0; - if (!option_list) return buf; + *p = '\0'; + if(cnt_p) + *cnt_p = 0; + if(!option_list) + return buf; - for (optn = option_list; optn->short_opt || optn->long_opt; optn++) { - char *s; + for(optn = option_list; optn->short_opt || optn->long_opt; optn++) { + char *s; - if (!(optn->flags & CLIF_EXCL)) continue; + if(!(optn->flags & CLIF_EXCL)) + continue; - if (optn->short_opt) s = show_short (optn); - else s = show_long (optn); + if(optn->short_opt) + s = show_short(optn); + else + s = show_long(optn); - if (excl_cnt > 0) { /* i.e., second etc... */ - strcpy (p, EXCL_DLM); - p += sizeof (EXCL_DLM) - 1; - } + if(excl_cnt > 0) { /* i.e., second etc... */ + strcpy(p, EXCL_DLM); + p += sizeof(EXCL_DLM) - 1; + } - while (*s && p < endp) *p++ = *s++; + while(*s && p < endp) + *p++ = *s++; - excl_cnt++; - } + excl_cnt++; + } - *p = '\0'; + *p = '\0'; - if (cnt_p) *cnt_p = excl_cnt; + if(cnt_p) + *cnt_p = excl_cnt; - return buf; + return buf; } +static int is_keyword(const CLIF_option *optn) { + unsigned int flags = optn->flags | curr.parse_flags; -static int is_keyword (const CLIF_option *optn) { - unsigned int flags = optn->flags | curr.parse_flags; - - return (flags & _CLIF_STRICT_KEYWORD) != 0; + return (flags & _CLIF_STRICT_KEYWORD) != 0; } - -static void err_bad_opt (const char *arg, char c, int n) { - char sym = (*arg == '+') ? '+' : '-'; - - if (c) err_report ("Bad option `%c%c' (argc %d)", sym, c, n); - else { - char *p = strchr (arg, '='); - const char *type = (*arg == sym) ? "option" : "keyword"; - - if (p) - err_report ("Bad %s `%s' (with arg `%s') (argc %d)", - type, arg, p + 1, n); - else - err_report ("Bad %s `%s' (argc %d)", type, arg, n); - } +static void err_bad_opt(const char *arg, char c, int n) { + char sym = (*arg == '+') ? '+' : '-'; + + if(c) + err_report("Bad option `%c%c' (argc %d)", sym, c, n); + else { + char *p = strchr(arg, '='); + const char *type = (*arg == sym) ? "option" : "keyword"; + + if(p) + err_report("Bad %s `%s' (with arg `%s') (argc %d)", + type, arg, p + 1, n); + else + err_report("Bad %s `%s' (argc %d)", type, arg, n); + } } -static void err_bad_arg (const CLIF_option *optn, char c, int n) { - CLIF_option tmp = *optn; - char ss[80]; - char *s; - - tmp.arg_name = NULL; - - if (c) { - s = show_short (&tmp); /* always without arg... */ - strncpy (ss, s, sizeof (ss)); - s = show_short (optn); - } else { - s = show_long (&tmp); /* always without arg... */ - strncpy (ss, s, sizeof (ss)); - s = show_long (optn); - } - - err_report ("%s `%s' (argc %d) requires an argument: `%s'", - (c || !is_keyword (optn)) ? "Option" : "Keyword", ss, n, s); +static void err_bad_arg(const CLIF_option *optn, char c, int n) { + CLIF_option tmp = *optn; + char ss[80]; + char *s; + + tmp.arg_name = NULL; + + if(c) { + s = show_short(&tmp); /* always without arg... */ + strncpy(ss, s, sizeof(ss)); + s = show_short(optn); + } else { + s = show_long(&tmp); /* always without arg... */ + strncpy(ss, s, sizeof(ss)); + s = show_long(optn); + } + + err_report("%s `%s' (argc %d) requires an argument: `%s'", + (c || !is_keyword(optn)) ? "Option" : "Keyword", ss, n, s); } - -static void err_bad_res (const CLIF_option *optn, char c, - const char *opt_arg, int n) { - CLIF_option tmp = *optn; - char *ss; - const char *type; - - tmp.arg_name = NULL; - - if (c) { - ss = show_short (&tmp); - type = "option"; - } else { - ss = show_long (&tmp); - type = is_keyword (optn) ? "keyword" : "option"; - } - - if (optn->arg_name) - err_report ("Cannot handle `%s' %s with arg `%s' (argc %d)", - ss, type, opt_arg, n); - else - err_report ("Cannot handle `%s' %s (argc %d)", ss, type, n); + +static void err_bad_res(const CLIF_option *optn, char c, + const char *opt_arg, int n) { + CLIF_option tmp = *optn; + char *ss; + const char *type; + + tmp.arg_name = NULL; + + if(c) { + ss = show_short(&tmp); + type = "option"; + } else { + ss = show_long(&tmp); + type = is_keyword(optn) ? "keyword" : "option"; + } + + if(optn->arg_name) + err_report("Cannot handle `%s' %s with arg `%s' (argc %d)", + ss, type, opt_arg, n); + else + err_report("Cannot handle `%s' %s (argc %d)", ss, type, n); } -static void err_bad_excl (const CLIF_option *optn, char c, int n) { - CLIF_option tmp = *optn; - char *ss; - char *excl = show_excl (curr.option_list, 0); - /* Note: show_(short|long)() nested!!! */ +static void err_bad_excl(const CLIF_option *optn, char c, int n) { + CLIF_option tmp = *optn; + char *ss; + char *excl = show_excl(curr.option_list, 0); + /* Note: show_(short|long)() nested!!! */ - tmp.arg_name = NULL; + tmp.arg_name = NULL; - if (c) ss = show_short (&tmp); - else ss = show_long (&tmp); + if(c) + ss = show_short(&tmp); + else + ss = show_long(&tmp); - err_report ("%s `%s' (argc %d): Only one of:\n %s\n" - "may be specified.", - (c || !is_keyword (optn)) ? "Option" : "Keyword", - ss, n, excl); + err_report("%s `%s' (argc %d): Only one of:\n %s\n" + "may be specified.", + (c || !is_keyword(optn)) ? "Option" : "Keyword", + ss, n, excl); } - -static CLIF_option *find_long (char *arg, char **arg_p, - unsigned int match, unsigned int nomatch) { - CLIF_option *optn; - CLIF_option *abbrev = NULL; - char *abbrev_arg = NULL; - int abbrev_found = 0; - - - for (optn = curr.option_list; - optn->short_opt || optn->long_opt; - optn++ - ) { - char *a; - const char *o; - unsigned int flags; - - if (!optn->long_opt) continue; - - flags = curr.parse_flags | optn->flags; - if (flags & nomatch) continue; - if (match && !(flags & match)) continue; /* XXX: optimize it */ - - - for (a = arg, o = optn->long_opt; *o && *a == *o; a++, o++) ; - - if (*a == '\0' || - (*a == '=' && optn->arg_name && !(flags & _CLIF_STRICT_NOEQUAL)) - ) { /* looks like end of option... */ - - if (!*o) { /* explicit match found */ - if (*a == '=' && arg_p) *arg_p = a + 1; - return optn; - } - - if ((flags & CLIF_ABBREV) && - (a - arg >= CLIF_MIN_ABBREV) - ) { - if (!abbrev_found) { - abbrev_found = 1; - abbrev = optn; - if (*a == '=') abbrev_arg = a + 1; - } else /* several possibility case... */ - abbrev = NULL; - } - } - } - - if (abbrev) { /* implicit match found */ - if (abbrev_arg && arg_p) *arg_p = abbrev_arg; - return abbrev; - } else /* no match found */ - return NULL; +static CLIF_option *find_long(char *arg, char **arg_p, + unsigned int match, unsigned int nomatch) { + CLIF_option *optn; + CLIF_option *abbrev = NULL; + char *abbrev_arg = NULL; + int abbrev_found = 0; + + for(optn = curr.option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + char *a; + const char *o; + unsigned int flags; + + if(!optn->long_opt) + continue; + + flags = curr.parse_flags | optn->flags; + if(flags & nomatch) + continue; + if(match && !(flags & match)) + continue; /* XXX: optimize it */ + + for(a = arg, o = optn->long_opt; *o && *a == *o; a++, o++) + ; + + if(*a == '\0' || + (*a == '=' && optn->arg_name && !(flags & _CLIF_STRICT_NOEQUAL)) + ) { /* looks like end of option... */ + + if(!*o) { /* explicit match found */ + if(*a == '=' && arg_p) + *arg_p = a + 1; + return optn; + } + + if((flags & CLIF_ABBREV) && + (a - arg >= CLIF_MIN_ABBREV) + ) { + if(!abbrev_found) { + abbrev_found = 1; + abbrev = optn; + if(*a == '=') + abbrev_arg = a + 1; + } else + /* several possibility case... */ + abbrev = NULL; + } + } + } + + if(abbrev) { /* implicit match found */ + if(abbrev_arg && arg_p) + *arg_p = abbrev_arg; + return abbrev; + } else + /* no match found */ + return NULL; } -static int check_sym (const CLIF_option *optn, char sym) { +static int check_sym(const CLIF_option *optn, char sym) { - if (sym == '+') { - if (!optn->function_plus) return -1; - } - else if (sym == '-') { - if (!optn->function && optn->function_plus) - return -1; - } + if(sym == '+') { + if(!optn->function_plus) + return -1; + } + else if(sym == '-') { + if(!optn->function && optn->function_plus) + return -1; + } - return 0; + return 0; } -static int call_function (CLIF_option *optn, char *opt_arg, char sym) { - int (*function) (CLIF_option *, char *); - - function = (sym == '+') ? optn->function_plus : optn->function; - - if (!function) return 0; +static int call_function(CLIF_option *optn, char *opt_arg, char sym) { + int (*function)(CLIF_option *, char *); - if (opt_arg && ((optn->flags | curr.parse_flags) & CLIF_SEVERAL)) { - char tmp[80]; - char *t; - char *endt = tmp + sizeof (tmp); + function = (sym == '+') ? optn->function_plus : optn->function; - while (*opt_arg) { - - t = tmp; - while (t < endt && *opt_arg && - *opt_arg != ' ' && *opt_arg != '\t' && *opt_arg != ',' - ) *t++ = *opt_arg++; + if(!function) + return 0; - if (t >= endt) return -1; - - *t = '\0'; - - if (function (optn, tmp) < 0) return -1; - - while (*opt_arg == ' ' || *opt_arg == '\t' || *opt_arg == ',') - opt_arg++; - } + if(opt_arg && ((optn->flags | curr.parse_flags) & CLIF_SEVERAL)) { + char tmp[80]; + char *t; + char *endt = tmp + sizeof(tmp); - return 0; - } + while(*opt_arg) { - return function (optn, opt_arg); -} + t = tmp; + while(t < endt && *opt_arg && + *opt_arg != ' ' && *opt_arg != '\t' && *opt_arg != ',' + ) + *t++ = *opt_arg++; + if(t >= endt) + return -1; -int CLIF_parse_cmdline (int argc, char *argv[], - CLIF_option *option_list, - CLIF_argument *argument_list, - unsigned int parse_flags) { - int i, j; - CLIF_option *optn; - CLIF_argument *argm; - int num_args = 0; - int num_argm = 0, strict_beg = 0, strict_end = 0; - _CLIF_index arg_n[MAX_ARGC_NUMBER]; - unsigned int dirty_flags = 0; - int dirty_plus = 0; - int exclusive_cnt = 0; - int posix = getenv ("POSIXLY_CORRECT") != NULL || - (parse_flags & CLIF_POSIX); - - curr.argc = argc; - curr.argv = argv; - curr.option_list = option_list; - curr.argument_list = argument_list; - curr.parse_flags = parse_flags; - - if (argc <= 1 && (parse_flags & CLIF_HELP_EMPTY)) { - CLIF_current_help (); - exit (0); - } - - /* Scan argument_list for check and some info. */ - - if (argument_list) { - enum stages { STRICT_BEG, OPTIONAL, STRICT_END }; - int stage = STRICT_BEG; - - for (argm = argument_list; argm->name; argm++) { - - if (argm->flags & CLIF_STRICT) { - - if (stage == STRICT_BEG) strict_beg++; - else if (stage == OPTIONAL) { - stage = STRICT_END; - strict_end++; - } - else if (stage == STRICT_END) - strict_end++; - } else { - if (stage == STRICT_BEG) stage = OPTIONAL; - else if (stage == STRICT_END) { - err_report ("Incorrect argument list set in program " - "source: more than one optional area."); - return -1; - } - } - - num_argm++; - } - } - - /* Scan option_list for some info. */ - if (option_list) { - - dirty_flags = parse_flags; - - for (optn = option_list; - optn->short_opt || optn->long_opt; - optn++ - ) { - dirty_flags |= optn->flags; - if (optn->function_plus) dirty_plus = 1; - } - } - - if (dirty_flags & CLIF_EXCL) - exclusive_cnt = 1; /* only one is allowed... */ - - - /* Go ! Store arguments, parse options. */ - - for (i = 1; i < argc; i++) { - char *arg = argv[i]; - char *opt_arg = NULL; - char sym = '-'; - - if (!option_list) - goto handle_arg; - - if (*arg == '+' && dirty_plus) - sym = '+'; - - if (*arg != sym) { /* argument or keyword */ - - if (dirty_flags & CLIF_MAY_KEYWORD) { - optn = find_long (arg, &opt_arg, CLIF_MAY_KEYWORD, 0); - if (optn) goto long_found; - } - - if (num_args == 0 && (parse_flags & CLIF_FIRST_GROUP)) { - /* ugly... */ - parse_flags &= ~CLIF_FIRST_GROUP; - dirty_flags &= ~CLIF_FIRST_GROUP; /* to be correct */ - - goto handle_short; - } - - /* else it is an argument */ - goto handle_arg; - - } - else if (*++arg == sym) { /* `--' - long option */ - arg++; - - if (*arg == sym || /* `---' - let it be not option... */ - (parse_flags & (_CLIF_STRICT_KEYWORD|_CLIF_STRICT_ONEDASH)) - ) { - arg -= 2; - goto handle_arg; /* not option anyway */ - } - - optn = find_long (arg, &opt_arg, 0, - _CLIF_STRICT_KEYWORD | _CLIF_STRICT_ONEDASH); - if (optn) goto long_found; - - /* XXX: May be allow only for `--', not `++' too... */ - if (!*arg && sym == '-') { /* `--' and no empty longoption */ - option_list = NULL; /* POSIX way... */ - continue; - } - - /* XXX: or treat as an argument sometimes??? */ - err_bad_opt (argv[i], 0, i); - return -1; - } - else { /* short option, or several short options... */ - - if (dirty_flags & CLIF_MAY_ONEDASH) { - optn = find_long (arg, &opt_arg, CLIF_MAY_ONEDASH, 0); - if (optn) goto long_found; - } - - if (!*arg) { /* POSIX say: only "stdout specification"... */ - arg--; - goto handle_arg; - } - - goto handle_short; - } - - - long_found: - if (check_sym (optn, sym) < 0) { /* Oops... */ - err_bad_opt (argv[i], 0, i); - return -1; - } - - if (optn->flags & CLIF_EXCL) { - if (!exclusive_cnt) { - err_bad_excl (optn, 0, i); - return -1; - } - exclusive_cnt--; - } - - if (optn->arg_name && !opt_arg) { - unsigned int flags = optn->flags | parse_flags; - - if (++i >= argc || - !(flags & CLIF_MAY_NOEQUAL) - ) { /* missing opt arg */ - i--; - - if (!(flags & CLIF_OPTARG)) { - err_bad_arg (optn, 0, i); - return -1; - } - - opt_arg = NULL; - } else - opt_arg = argv[i]; - - } - - - if (call_function (optn, opt_arg, sym) < 0) { - err_bad_res (optn, 0, opt_arg, i); - return -1; - } - - if (optn->flags & CLIF_EXIT) - exit (0); - - continue; + *t = '\0'; + if(function(optn, tmp) < 0) + return -1; - handle_arg: - if (argument_list) { - if (i < MAX_ARGC_NUMBER) /* XXX: ugly, better report */ - arg_n[num_args++] = i; - } else { - err_report ("`%s' (argc %d): arguments are not allowed", - argv[i], i); - return -1; - } + while(*opt_arg == ' ' || *opt_arg == '\t' || *opt_arg == ',') + opt_arg++; + } - /* POSIX say: No more options after args... */ - if (posix) option_list = NULL; /* geniously... */ - - continue; + return 0; + } + return function(optn, opt_arg); +} - handle_short: +int CLIF_parse_cmdline (int argc, char *argv[], + CLIF_option *option_list, + CLIF_argument *argument_list, + unsigned int parse_flags){ +int i, j; +CLIF_option *optn; +CLIF_argument *argm; +int num_args = 0; +int num_argm = 0, strict_beg = 0, strict_end = 0; +_CLIF_index arg_n[MAX_ARGC_NUMBER]; +unsigned int dirty_flags = 0; +int dirty_plus = 0; +int exclusive_cnt = 0; +int posix = getenv ("POSIXLY_CORRECT") != NULL || +(parse_flags & CLIF_POSIX); + +curr.argc = argc; +curr.argv = argv; +curr.option_list = option_list; +curr.argument_list = argument_list; +curr.parse_flags = parse_flags; + +if (argc <= 1 && (parse_flags & CLIF_HELP_EMPTY)) { + CLIF_current_help (); + exit (0); +} - opt_arg = NULL; - - do { - - for (optn = option_list; - optn->short_opt || optn->long_opt; - optn++ - ) { - if (optn->short_opt && optn->short_opt[0] == *arg) - break; - } - if (!optn->short_opt || - check_sym (optn, sym) < 0 - ) { - err_bad_opt (argv[i], *arg, i); - return -1; - } - - if (optn->flags & CLIF_EXCL) { - if (!exclusive_cnt) { - err_bad_excl (optn, *arg, i); - return -1; - } - exclusive_cnt--; - } - - - if (optn->arg_name) { - unsigned int flags = parse_flags | optn->flags; - - if (arg[1] == '\0') { /* a last one */ - - /* POSIX say: an option with arg cannot be grouped. */ - if (posix && arg != argv[i] && arg[-1] != sym) { - err_bad_arg (optn, *arg, i); /* good way? */ - return -1; - } - - if (++i >= argc || - (flags & _CLIF_STRICT_JOIN_ARG) - ) { - i--; - - if (!(flags & CLIF_OPTARG)) { - err_bad_arg (optn, *arg, i); - return -1; - } - - opt_arg = NULL; - } else - opt_arg = argv[i]; - } - else if ((arg == argv[i] || arg[-1] == sym) && - (flags & CLIF_MAY_JOIN_ARG) - ) { - opt_arg = ++arg; - } - else { /* inside a group... */ - if (!(flags & CLIF_OPTARG) || - (flags & CLIF_MAY_JOIN_ARG) - ) { - err_bad_arg (optn, *arg, i); - return -1; - } - - opt_arg = NULL; - } - } - - if (call_function (optn, opt_arg, sym) < 0) { - err_bad_res (optn, optn->short_opt[0], opt_arg, i); - return -1; - } - - if (optn->flags & CLIF_EXIT) - exit (0); - - } while (!opt_arg && *++arg); - - } /* for ( ... ) */ - - - if ((parse_flags & CLIF_STRICT_EXCL) && exclusive_cnt != 0) { - err_report ("One of these must be specified:\n %s\n", - show_excl (option_list, 0)); - return -1; - } - - - /* Now, after *ALL* options, handle arguments, if any. */ - - if (num_args < strict_beg + strict_end) { - /* Missing some needed arguments. */ - - if (num_args < strict_beg) argm = argument_list + num_args; - else - argm = argument_list + - ((num_args - strict_beg) + (num_argm - strict_end)); - - if (num_args == strict_beg + strict_end - 1) - err_report ("Specify \"%s\" missing argument.", argm->name); - else - err_report ("Specify \"%s\" and other missing arguments.", - argm->name); - return -1; - } - - if (num_args > 0) { - _CLIF_index argm_index[MAX_ARGC_NUMBER]; - - /* assing argm (by index) for each arg... */ - - for (i = 0, j = 0; i < strict_beg; i++, j++) - argm_index[i] = j; - for (i = num_args - strict_end, j = num_argm - strict_end; - i < num_args; i++, j++ - ) argm_index[i] = j; - for (i = strict_beg, j = strict_beg; - i < num_args - strict_end && j < num_argm - strict_end; - i++ - ) { - argm_index[i] = j; - if (!(argument_list[j].flags & CLIF_MORE)) - j++; - } - - if (i < num_args - strict_end) { /* there are extra args... */ - err_report ("Extra arg `%s' (position %d, argc %d)", - argv[arg_n[i]], i + 1, arg_n[i]); - return -1; - } - - if (j < num_argm - strict_end && - !(argument_list[j].flags & CLIF_MORE) && - /* ...i.e, there are some missing optional args... */ - (argument_list[j].flags & CLIF_ACC_PREV) - ) { - if (j == 0) - err_report ("Incorrect argument list set: first arg " - "cannot be `accompanied with previous'."); - else - err_report ("Arg \"%s\" must be specified because " - "\"%s\" `%s' is used.", argument_list[j].name, - argument_list[j - 1].name, argv[arg_n[i - 1]]); - return -1; - } - - if (argm_index[--i] == j && - /* above is true only after OPTIONAL area scan - and when `j' is stopped on CLIF_MORE */ - ++j < num_argm - strict_end - /* i.e: there is a *last* one (after CLIF_MORE) - in the OPTIONAL area */ - ) argm_index[i] = j; /* *last* is better than *more* */ - - - /* ...and work now */ - - for (i = 0; i < num_args; i++) { - argm = argument_list + argm_index[i]; - - if (argm->function && - argm->function (argm, argv[arg_n[i]], i) < 0 - ) { - err_report ("Cannot handle \"%s\" cmdline arg `%s' " - "on position %d (argc %d)", - argm->name, argv[arg_n[i]], i + 1, arg_n[i]); - return -1; - } - } - - /* That`s all. */ - } - - return 0; +/* Scan argument_list for check and some info. */ + +if (argument_list) { + enum stages {STRICT_BEG, OPTIONAL, STRICT_END}; + int stage = STRICT_BEG; + + for (argm = argument_list; argm->name; argm++) { + + if (argm->flags & CLIF_STRICT) { + + if (stage == STRICT_BEG) strict_beg++; + else if (stage == OPTIONAL) { + stage = STRICT_END; + strict_end++; + } + else if (stage == STRICT_END) + strict_end++; + } else { + if (stage == STRICT_BEG) stage = OPTIONAL; + else if (stage == STRICT_END) { + err_report ("Incorrect argument list set in program " + "source: more than one optional area."); + return -1; + } + } + + num_argm++; + } } +/* Scan option_list for some info. */ +if (option_list) { + + dirty_flags = parse_flags; -static void box_output (int start, int left, int width, const char *str, - const char *arg_name) { - char *p, *endp, *s; - int l; - char buf[1024]; - char spacer[128]; /* assume it is enough */ - - if (left > sizeof (spacer) - 2) left = sizeof (spacer) - 2; - if (width > sizeof (buf) - 1) width = sizeof (buf) - 1; - - spacer[0] = '\n'; - memset (spacer + 1, ' ', left); - spacer[left + 1] = '\0'; - - - l = left - start; - if (l > 0) { - memset (buf, ' ', l); - buf[l] = '\0'; - fprintf (stderr, "%s", buf); - } else - fprintf (stderr, "%s", spacer); - - - endp = buf + width; - - p = buf; - - while (*str) { - - while (*str && p < endp) { - - if (*str == '%' && arg_name) { - if (str[1] == '%') { - *p++ = '%'; - str += 2; - continue; - } - else if (str[1] == 's') { - const char *a = arg_name; - - while (*a && p < endp) *p++ = *a++; - str += 2; - continue; - } - } - - *p++ = *str++; - } - - *p = '\0'; - - if (p < endp) break; - - - while (p > buf && *p != ' ' && *p != '\t') p--; - if (p <= buf) return; /* foo on you */ - - *p = '\0'; - fprintf (stderr, "%s", buf); - fprintf (stderr, "%s", spacer); - - p++; - for (s = buf; *p; *s++ = *p++) ; - *s = '\0'; - p = s; - } - - - fprintf (stderr, "%s", buf); - - return; + for (optn = option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + dirty_flags |= optn->flags; + if (optn->function_plus) dirty_plus = 1; + } } +if (dirty_flags & CLIF_EXCL) +exclusive_cnt = 1; /* only one is allowed... */ + +/* Go ! Store arguments, parse options. */ + +for (i = 1; i < argc; i++) { + char *arg = argv[i]; + char *opt_arg = NULL; + char sym = '-'; + + if (!option_list) + goto handle_arg; + + if (*arg == '+' && dirty_plus) + sym = '+'; + + if (*arg != sym) { /* argument or keyword */ -#define SHORT_LONG_DLM " " -#define OPT_START_DLM " " -#define OPT_FIELD_WIDTH 30 + if (dirty_flags & CLIF_MAY_KEYWORD) { + optn = find_long (arg, &opt_arg, CLIF_MAY_KEYWORD, 0); + if (optn) goto long_found; + } -#define ARG_MARK_STRICT "+ " -#define ARG_MARK_GROUP0 " . " -#define ARG_MARK_GROUP " ' " -#define ARG_MARK_OPT " " -#define ARG_FIELD_WIDTH 20 + if (num_args == 0 && (parse_flags & CLIF_FIRST_GROUP)) { + /* ugly... */ + parse_flags &= ~CLIF_FIRST_GROUP; + dirty_flags &= ~CLIF_FIRST_GROUP; /* to be correct */ -#define SCREEN_WIDTH 80 + goto handle_short; + } + /* else it is an argument */ + goto handle_arg; -void CLIF_print_options (const char *header, - const CLIF_option *option_list) { - const CLIF_option *optn; - char *excl; - int excl_cnt = 0; + } + else if (*++arg == sym) { /* `--' - long option */ + arg++; - /* Print a header string, if present... */ - if (header) fprintf (stderr, "%s\n", header); + if (*arg == sym || /* `---' - let it be not option... */ + (parse_flags & (_CLIF_STRICT_KEYWORD|_CLIF_STRICT_ONEDASH)) + ) { + arg -= 2; + goto handle_arg; /* not option anyway */ + } - if (!option_list) return; + optn = find_long (arg, &opt_arg, 0, + _CLIF_STRICT_KEYWORD | _CLIF_STRICT_ONEDASH); + if (optn) goto long_found; + /* XXX: May be allow only for `--', not `++' too... */ + if (!*arg && sym == '-') { /* `--' and no empty longoption */ + option_list = NULL; /* POSIX way... */ + continue; + } - for (optn = option_list; optn->short_opt || optn->long_opt; optn++) { - int len; + /* XXX: or treat as an argument sometimes??? */ + err_bad_opt (argv[i], 0, i); + return -1; + } + else { /* short option, or several short options... */ - /* generate and print an option usage */ + if (dirty_flags & CLIF_MAY_ONEDASH) { + optn = find_long (arg, &opt_arg, CLIF_MAY_ONEDASH, 0); + if (optn) goto long_found; + } - if (optn->short_opt) { - if (optn->long_opt) - len = fprintf (stderr, OPT_START_DLM "%s" - SHORT_LONG_DLM "%s", - show_short (optn), show_long (optn)); - else - len = fprintf (stderr, OPT_START_DLM "%s", - show_short (optn)); - } else - len = fprintf (stderr, OPT_START_DLM "%s", show_long (optn)); + if (!*arg) { /* POSIX say: only "stdout specification"... */ + arg--; + goto handle_arg; + } + goto handle_short; + } - /* print a help string, if present */ - - if (optn->help_string) - box_output (len, OPT_FIELD_WIDTH, - SCREEN_WIDTH - OPT_FIELD_WIDTH, - optn->help_string, optn->arg_name); + long_found: + if (check_sym (optn, sym) < 0) { /* Oops... */ + err_bad_opt (argv[i], 0, i); + return -1; + } - fprintf (stderr, "\n"); /* a last one */ - } + if (optn->flags & CLIF_EXCL) { + if (!exclusive_cnt) { + err_bad_excl (optn, 0, i); + return -1; + } + exclusive_cnt--; + } - excl = show_excl (option_list, &excl_cnt); - if (excl_cnt > 0) { + if (optn->arg_name && !opt_arg) { + unsigned int flags = optn->flags | parse_flags; - if (excl_cnt == 1) { - if ((curr.parse_flags & CLIF_STRICT_EXCL) && - curr.option_list == option_list - ) fprintf (stderr, "Anyway `%s' must be specified.\n", excl); - else /* simple ordinary option, because excl_cnt == 1 ... */; - } else - fprintf (stderr, "Only one of these may be specified:\n" - " %s\n", excl); - } + if (++i >= argc || + !(flags & CLIF_MAY_NOEQUAL) + ) { /* missing opt arg */ + i--; - return; -} - + if (!(flags & CLIF_OPTARG)) { + err_bad_arg (optn, 0, i); + return -1; + } + + opt_arg = NULL; + } else + opt_arg = argv[i]; + + } + + if (call_function (optn, opt_arg, sym) < 0) { + err_bad_res (optn, 0, opt_arg, i); + return -1; + } + + if (optn->flags & CLIF_EXIT) + exit (0); + + continue; -void CLIF_print_arguments (const char *header, - const CLIF_argument *argument_list) { - const CLIF_argument *argm; + handle_arg: + if (argument_list) { + if (i < MAX_ARGC_NUMBER) /* XXX: ugly, better report */ + arg_n[num_args++] = i; + } else { + err_report ("`%s' (argc %d): arguments are not allowed", + argv[i], i); + return -1; + } + /* POSIX say: No more options after args... */ + if (posix) option_list = NULL; /* geniously... */ - if (!argument_list) return; + continue; - /* Print a header string, if present... */ - if (header) fprintf (stderr, "%s\n", header); + handle_short: + opt_arg = NULL; + + do { + + for (optn = option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + if (optn->short_opt && optn->short_opt[0] == *arg) + break; + } + if (!optn->short_opt || + check_sym (optn, sym) < 0 + ) { + err_bad_opt (argv[i], *arg, i); + return -1; + } + + if (optn->flags & CLIF_EXCL) { + if (!exclusive_cnt) { + err_bad_excl (optn, *arg, i); + return -1; + } + exclusive_cnt--; + } + + if (optn->arg_name) { + unsigned int flags = parse_flags | optn->flags; + + if (arg[1] == '\0') { /* a last one */ + + /* POSIX say: an option with arg cannot be grouped. */ + if (posix && arg != argv[i] && arg[-1] != sym) { + err_bad_arg (optn, *arg, i); /* good way? */ + return -1; + } + + if (++i >= argc || + (flags & _CLIF_STRICT_JOIN_ARG) + ) { + i--; + + if (!(flags & CLIF_OPTARG)) { + err_bad_arg (optn, *arg, i); + return -1; + } + + opt_arg = NULL; + } else + opt_arg = argv[i]; + } + else if ((arg == argv[i] || arg[-1] == sym) && + (flags & CLIF_MAY_JOIN_ARG) + ) { + opt_arg = ++arg; + } + else { /* inside a group... */ + if (!(flags & CLIF_OPTARG) || + (flags & CLIF_MAY_JOIN_ARG) + ) { + err_bad_arg (optn, *arg, i); + return -1; + } + + opt_arg = NULL; + } + } + + if (call_function (optn, opt_arg, sym) < 0) { + err_bad_res (optn, optn->short_opt[0], opt_arg, i); + return -1; + } + + if (optn->flags & CLIF_EXIT) + exit (0); + + }while (!opt_arg && *++arg); + +} /* for ( ... ) */ + +if ((parse_flags & CLIF_STRICT_EXCL) && exclusive_cnt != 0) { + err_report ("One of these must be specified:\n %s\n", + show_excl (option_list, 0)); + return -1; +} - for (argm = argument_list; argm->name; argm++) { - int len; +/* Now, after *ALL* options, handle arguments, if any. */ - if (argm->flags & CLIF_STRICT) - len = fprintf (stderr, ARG_MARK_STRICT "%s", argm->name); - else if (argm->flags & CLIF_MORE) - len = fprintf (stderr, ARG_MARK_OPT "%s ...", argm->name); - else if (argm->flags & CLIF_ACC_PREV) - len = fprintf (stderr, ARG_MARK_GROUP "%s", argm->name); - else if ((argm + 1)->name && ((argm + 1)->flags & CLIF_ACC_PREV)) - len = fprintf (stderr, ARG_MARK_GROUP0 "%s", argm->name); - else - len = fprintf (stderr, ARG_MARK_OPT "%s", argm->name); +if (num_args < strict_beg + strict_end) { + /* Missing some needed arguments. */ - if (argm->help_string) - box_output (len, ARG_FIELD_WIDTH, - SCREEN_WIDTH - ARG_FIELD_WIDTH, - argm->help_string, argm->name); + if (num_args < strict_beg) argm = argument_list + num_args; + else + argm = argument_list + + ((num_args - strict_beg) + (num_argm - strict_end)); - fprintf (stderr, "\n"); - } + if (num_args == strict_beg + strict_end - 1) + err_report ("Specify \"%s\" missing argument.", argm->name); + else + err_report ("Specify \"%s\" and other missing arguments.", + argm->name); + return -1; +} - return; +if (num_args > 0) { + _CLIF_index argm_index[MAX_ARGC_NUMBER]; + + /* assing argm (by index) for each arg... */ + + for (i = 0, j = 0; i < strict_beg; i++, j++) + argm_index[i] = j; + for (i = num_args - strict_end, j = num_argm - strict_end; + i < num_args; i++, j++ + ) argm_index[i] = j; + for (i = strict_beg, j = strict_beg; + i < num_args - strict_end && j < num_argm - strict_end; + i++ + ) { + argm_index[i] = j; + if (!(argument_list[j].flags & CLIF_MORE)) + j++; + } + + if (i < num_args - strict_end) { /* there are extra args... */ + err_report ("Extra arg `%s' (position %d, argc %d)", + argv[arg_n[i]], i + 1, arg_n[i]); + return -1; + } + + if (j < num_argm - strict_end && + !(argument_list[j].flags & CLIF_MORE) && + /* ...i.e, there are some missing optional args... */ + (argument_list[j].flags & CLIF_ACC_PREV) + ) { + if (j == 0) + err_report ("Incorrect argument list set: first arg " + "cannot be `accompanied with previous'."); + else + err_report ("Arg \"%s\" must be specified because " + "\"%s\" `%s' is used.", argument_list[j].name, + argument_list[j - 1].name, argv[arg_n[i - 1]]); + return -1; + } + + if (argm_index[--i] == j && + /* above is true only after OPTIONAL area scan + and when `j' is stopped on CLIF_MORE */ + ++j < num_argm - strict_end + /* i.e: there is a *last* one (after CLIF_MORE) + in the OPTIONAL area */ + ) argm_index[i] = j; /* *last* is better than *more* */ + + /* ...and work now */ + + for (i = 0; i < num_args; i++) { + argm = argument_list + argm_index[i]; + + if (argm->function && + argm->function (argm, argv[arg_n[i]], i) < 0 + ) { + err_report ("Cannot handle \"%s\" cmdline arg `%s' " + "on position %d (argc %d)", + argm->name, argv[arg_n[i]], i + 1, arg_n[i]); + return -1; + } + } + + /* That`s all. */ } +return 0; +} -void CLIF_print_usage (const char *header, const char *progname, - const CLIF_option *option_list, - const CLIF_argument *argument_list) { - - if (!progname && curr.argv) - progname = curr.argv[0]; - - if (!header) { - if (progname) - fprintf (stderr, "Usage: %s", progname); - else - fprintf (stderr, "Command line options:"); - } else { - if (progname) - fprintf (stderr, "%s\n" OPT_START_DLM "%s", header, progname); - else - fprintf (stderr, "%s", header); - } - - - if (option_list) { - const CLIF_option *optn; - char m_buf[256], p_buf[256], mp_buf[256]; - char *m = m_buf, *p = p_buf, *mp = mp_buf; - char *end_m = m_buf + sizeof (m_buf) - 1; - char *end_p = p_buf + sizeof (p_buf) - 1; - char *end_mp = mp_buf + sizeof (mp_buf) - 1; - char *excl; - int excl_cnt = 0; - - - /* first, show exclusive option list, if any... */ - - excl = show_excl (option_list, &excl_cnt); - if (excl_cnt > 0) { - if ((curr.parse_flags & CLIF_STRICT_EXCL) && - curr.option_list == option_list - ) { - if (excl_cnt == 1) - fprintf (stderr, " %s", excl); - else - fprintf (stderr, " { %s }", excl); - } else - fprintf (stderr, " [ %s ]", excl); - } - - - /* second, find short options without arguments... */ - - for (optn = option_list; - optn->short_opt || optn->long_opt; - optn++ - ) { - /* We don`t exclude CLIF_EXTRA hear: - simple one char don`t eat a lot of space... - */ - - if (!optn->short_opt || - optn->arg_name || - (optn->flags & CLIF_EXCL) - ) continue; - - if (optn->function_plus) { - if (optn->function) { - if (mp < end_mp) *mp++ = optn->short_opt[0]; - } else { - if (p < end_p) *p++ = optn->short_opt[0]; - } - } else { - if (m < end_m) *m++ = optn->short_opt[0]; - } - } - - if (m > (char *) m_buf) { - *m = '\0'; - fprintf (stderr, " [ -%s ]", m_buf); - } - if (p > (char *) p_buf) { - *p = '\0'; - fprintf (stderr, " [ +%s ]", p_buf); - } - if (mp > (char *) mp_buf) { - *mp = '\0'; - fprintf (stderr, " [ " SHORT_PLUS_MINUS "%s ]", mp_buf); - } - - - /* third, print all another... */ - - for (optn = option_list; - optn->short_opt || optn->long_opt; - optn++ - ) { - if (optn->flags & CLIF_EXTRA) continue; - - if (optn->flags & CLIF_EXCL) - continue; /* already handled */ - - if (optn->short_opt) { - if (optn->arg_name) - fprintf (stderr, " [ %s ]", show_short (optn)); - else - /* already handled */; - } else - fprintf (stderr, " [ %s ]", show_long (optn)); - } - } - - - if (argument_list) { - const CLIF_argument *argm; - int deep = 0; - - for (argm = argument_list; argm->name; argm++) { - - if (argm->flags & CLIF_STRICT) { - if (deep > 0) { - fputc (' ', stderr); - while (deep--) fputc (']', stderr); - deep = 0; - } - - fprintf (stderr, " %s", argm->name); - } else { - if (argm->flags & CLIF_MORE) - fprintf (stderr, " [ %s ...", argm->name); - else if (argm->flags & CLIF_ACC_PREV) { - fprintf (stderr, " %s", argm->name); - --deep; /* ugly, but easy */ - } else - fprintf (stderr, " [ %s", argm->name); - - deep++; - } - } - - if (deep > 0) { - fputc (' ', stderr); - while (deep--) fputc (']', stderr); - } - } - - - fprintf (stderr, "\n"); +static void box_output(int start, int left, int width, const char *str, + const char *arg_name) { + char *p, *endp, *s; + int l; + char buf[1024]; + char spacer[128]; /* assume it is enough */ + + if(left > (int) sizeof(spacer) - 2) + left = (int) sizeof(spacer) - 2; + if(width > (int) sizeof(buf) - 1) + width = (int) sizeof(buf) - 1; + + spacer[0] = '\n'; + memset(spacer + 1, ' ', left); + spacer[left + 1] = '\0'; + + l = left - start; + if(l > 0) { + memset(buf, ' ', l); + buf[l] = '\0'; + fprintf(stderr, "%s", buf); + } else + fprintf(stderr, "%s", spacer); + + endp = buf + width; + + p = buf; + + while(*str) { + + while(*str && p < endp) { + + if(*str == '%' && arg_name) { + if(str[1] == '%') { + *p++ = '%'; + str += 2; + continue; + } + else if(str[1] == 's') { + const char *a = arg_name; + + while(*a && p < endp) + *p++ = *a++; + str += 2; + continue; + } + } + + *p++ = *str++; + } + + *p = '\0'; + + if(p < endp) + break; + + while(p > buf && *p != ' ' && *p != '\t') + p--; + if(p <= buf) + return; /* foo on you */ + + *p = '\0'; + fprintf(stderr, "%s", buf); + fprintf(stderr, "%s", spacer); + + p++; + for(s = buf; *p; *s++ = *p++) + ; + *s = '\0'; + p = s; + } + + fprintf(stderr, "%s", buf); + + return; } +#define SHORT_LONG_DLM " " +#define OPT_START_DLM " " +#define OPT_FIELD_WIDTH 30 -int CLIF_current_help (void) { +#define ARG_MARK_STRICT "+ " +#define ARG_MARK_GROUP0 " . " +#define ARG_MARK_GROUP " ' " +#define ARG_MARK_OPT " " +#define ARG_FIELD_WIDTH 20 - if (!curr.argc) return -1; /* i.e., not inited... */ +#define SCREEN_WIDTH 80 - CLIF_print_usage ("Usage:", curr.argv[0], curr.option_list, - curr.argument_list); +void CLIF_print_options(const char *header, + const CLIF_option *option_list) { + const CLIF_option *optn; + char *excl; + int excl_cnt = 0; + + /* Print a header string, if present... */ + if(header) + fprintf(stderr, "%s\n", header); + + if(!option_list) + return; + + for(optn = option_list; optn->short_opt || optn->long_opt; optn++) { + int len; + + /* generate and print an option usage */ + + if(optn->short_opt) { + if(optn->long_opt) + len = fprintf(stderr, OPT_START_DLM "%s" + SHORT_LONG_DLM "%s", + show_short(optn), show_long(optn)); + else + len = fprintf(stderr, OPT_START_DLM "%s", + show_short(optn)); + } else + len = fprintf(stderr, OPT_START_DLM "%s", show_long(optn)); + + /* print a help string, if present */ + + if(optn->help_string) + box_output(len, OPT_FIELD_WIDTH, + SCREEN_WIDTH - OPT_FIELD_WIDTH, + optn->help_string, optn->arg_name); + + fprintf(stderr, "\n"); /* a last one */ + } + + excl = show_excl(option_list, &excl_cnt); + if(excl_cnt > 0) { + + if(excl_cnt == 1) { + if((curr.parse_flags & CLIF_STRICT_EXCL) && + curr.option_list == option_list + ) + fprintf(stderr, "Anyway `%s' must be specified.\n", excl); + //else /* simple ordinary option, because excl_cnt == 1 ... */ + } else + fprintf(stderr, "Only one of these may be specified:\n" + " %s\n", excl); + } + + return; +} - if (curr.option_list) - CLIF_print_options ("Options:", curr.option_list); - - if (curr.argument_list) - CLIF_print_arguments ("\nArguments:", curr.argument_list); +void CLIF_print_arguments(const char *header, + const CLIF_argument *argument_list) { + const CLIF_argument *argm; - return 0; -} + if(!argument_list) + return; + /* Print a header string, if present... */ + if(header) + fprintf(stderr, "%s\n", header); -/* Common useful option handlers. */ + for(argm = argument_list; argm->name; argm++) { + int len; -int CLIF_version_handler (CLIF_option *optn, char *arg) { + if(argm->flags & CLIF_STRICT) + len = fprintf(stderr, ARG_MARK_STRICT "%s", argm->name); + else if(argm->flags & CLIF_MORE) + len = fprintf(stderr, ARG_MARK_OPT "%s ...", argm->name); + else if(argm->flags & CLIF_ACC_PREV) + len = fprintf(stderr, ARG_MARK_GROUP "%s", argm->name); + else if((argm + 1)->name && ((argm + 1)->flags & CLIF_ACC_PREV)) + len = fprintf(stderr, ARG_MARK_GROUP0 "%s", argm->name); + else + len = fprintf(stderr, ARG_MARK_OPT "%s", argm->name); - if (!optn->data) return -1; + if(argm->help_string) + box_output(len, ARG_FIELD_WIDTH, + SCREEN_WIDTH - ARG_FIELD_WIDTH, + argm->help_string, argm->name); - fprintf (stderr, "%s\n", ((char *) optn->data)); + fprintf(stderr, "\n"); + } - return 0; /* be happy */ + return; } - -int CLIF_set_flag (CLIF_option *optn, char *arg) { +void CLIF_print_usage(const char *header, const char *progname, + const CLIF_option *option_list, + const CLIF_argument *argument_list) { + + if(!progname && curr.argv) + progname = curr.argv[0]; + + if(!header) { + if(progname) + fprintf(stderr, "Usage: %s", progname); + else + fprintf(stderr, "Command line options:"); + } else { + if(progname) + fprintf(stderr, "%s\n" OPT_START_DLM "%s", header, progname); + else + fprintf(stderr, "%s", header); + } + + if(option_list) { + const CLIF_option *optn; + char m_buf[256], p_buf[256], mp_buf[256]; + char *m = m_buf, *p = p_buf, *mp = mp_buf; + char *end_m = m_buf + sizeof(m_buf) - 1; + char *end_p = p_buf + sizeof(p_buf) - 1; + char *end_mp = mp_buf + sizeof(mp_buf) - 1; + char *excl; + int excl_cnt = 0; + + /* first, show exclusive option list, if any... */ + + excl = show_excl(option_list, &excl_cnt); + if(excl_cnt > 0) { + if((curr.parse_flags & CLIF_STRICT_EXCL) && + curr.option_list == option_list + ) { + if(excl_cnt == 1) + fprintf(stderr, " %s", excl); + else + fprintf(stderr, " { %s }", excl); + } else + fprintf(stderr, " [ %s ]", excl); + } + + /* second, find short options without arguments... */ + + for(optn = option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + /* We don`t exclude CLIF_EXTRA hear: + simple one char don`t eat a lot of space... + */ + + if(!optn->short_opt || + optn->arg_name || + (optn->flags & CLIF_EXCL) + ) + continue; + + if(optn->function_plus) { + if(optn->function) { + if(mp < end_mp) + *mp++ = optn->short_opt[0]; + } else { + if(p < end_p) + *p++ = optn->short_opt[0]; + } + } else { + if(m < end_m) + *m++ = optn->short_opt[0]; + } + } + + if(m > (char *) m_buf) { + *m = '\0'; + fprintf(stderr, " [ -%s ]", m_buf); + } + if(p > (char *) p_buf) { + *p = '\0'; + fprintf(stderr, " [ +%s ]", p_buf); + } + if(mp > (char *) mp_buf) { + *mp = '\0'; + fprintf(stderr, " [ " SHORT_PLUS_MINUS "%s ]", mp_buf); + } + + /* third, print all another... */ + + for(optn = option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + if(optn->flags & CLIF_EXTRA) + continue; + + if(optn->flags & CLIF_EXCL) + continue; /* already handled */ + + if(optn->short_opt) { + if(optn->arg_name) + fprintf(stderr, " [ %s ]", show_short(optn)); + //else + /* already handled */ + } else + fprintf(stderr, " [ %s ]", show_long(optn)); + } + } + + if(argument_list) { + const CLIF_argument *argm; + int deep = 0; + + for(argm = argument_list; argm->name; argm++) { + + if(argm->flags & CLIF_STRICT) { + if(deep > 0) { + fputc(' ', stderr); + while(deep--) + fputc(']', stderr); + deep = 0; + } + + fprintf(stderr, " %s", argm->name); + } else { + if(argm->flags & CLIF_MORE) + fprintf(stderr, " [ %s ...", argm->name); + else if(argm->flags & CLIF_ACC_PREV) { + fprintf(stderr, " %s", argm->name); + --deep; /* ugly, but easy */ + } else + fprintf(stderr, " [ %s", argm->name); + + deep++; + } + } + + if(deep > 0) { + fputc(' ', stderr); + while(deep--) + fputc(']', stderr); + } + } + + fprintf(stderr, "\n"); +} - if (!optn->data) return -1; +int CLIF_current_help(void) { - *((int *) optn->data) = 1; + if(!curr.argc) + return -1; /* i.e., not inited... */ - return 0; -} + CLIF_print_usage("Usage:", curr.argv[0], curr.option_list, + curr.argument_list); + if(curr.option_list) + CLIF_print_options("Options:", curr.option_list); -int CLIF_unset_flag (CLIF_option *optn, char *arg) { + if(curr.argument_list) + CLIF_print_arguments("\nArguments:", curr.argument_list); - if (!optn->data) return -1; + return 0; +} - *((int *) optn->data) = 0; +/* Common useful option handlers. */ - return 0; -} +int CLIF_version_handler(CLIF_option *optn, char *arg) { + UNUSED(arg); + if(!optn->data) + return -1; + fprintf(stderr, "%s\n", ((char *) optn->data)); -static int set_string (char **data, char *arg) { + return 0; /* be happy */ +} - if (!data) return -1; +int CLIF_set_flag(CLIF_option *optn, char *arg) { + UNUSED(arg); + if(!optn->data) + return -1; - *data = arg; + *((int *) optn->data) = 1; - return 0; + return 0; } -int CLIF_set_string (CLIF_option *optn, char *arg) { +int CLIF_unset_flag(CLIF_option *optn, char *arg) { + UNUSED(arg); + if(!optn->data) + return -1; + + *((int *) optn->data) = 0; - return set_string (optn->data, arg); + return 0; } -int CLIF_arg_string (CLIF_argument *argm, char *arg, int index) { +static int set_string(char **data, char *arg) { - return set_string (argm->data, arg); -} + if(!data) + return -1; + *data = arg; -static int set_int (int *data, char *arg) { - char *q; + return 0; +} - if (!data) return -1; +int CLIF_set_string(CLIF_option *optn, char *arg) { - *data = (int) strtol (arg, &q, 0); + return set_string(optn->data, arg); +} - return (q == arg || *q) ? -1 : 0; +int CLIF_arg_string(CLIF_argument *argm, char *arg, int index) { + UNUSED(index); + return set_string(argm->data, arg); } -static int set_uint (unsigned int *data, char *arg) { - char *q; +static int set_int(int *data, char *arg) { + char *q; - if (!data) return -1; + if(!data) + return -1; - *data = (unsigned int) strtoul (arg, &q, 0); + *data = (int) strtol(arg, &q, 0); - return (q == arg || *q) ? -1 : 0; + return (q == arg || *q) ? -1 : 0; } -static int set_double (double *data, char *arg) { - char *q; +static int set_uint(unsigned int *data, char *arg) { + char *q; - if (!data) return -1; + if(!data) + return -1; - *data = strtod (arg, &q); + *data = (unsigned int) strtoul(arg, &q, 0); - return (q == arg || *q) ? -1 : 0; + return (q == arg || *q) ? -1 : 0; } +static int set_double(double *data, char *arg) { + char *q; -int CLIF_set_int (CLIF_option *optn, char *arg) { + if(!data) + return -1; - return set_int (optn->data, arg); -} + *data = strtod(arg, &q); -int CLIF_set_uint (CLIF_option *optn, char *arg) { - - return set_uint (optn->data, arg); + return (q == arg || *q) ? -1 : 0; } -int CLIF_set_double (CLIF_option *optn, char *arg) { +int CLIF_set_int(CLIF_option *optn, char *arg) { - return set_double (optn->data, arg); + return set_int(optn->data, arg); } -int CLIF_arg_int (CLIF_argument *argm, char *arg, int index) { +int CLIF_set_uint(CLIF_option *optn, char *arg) { - return set_int (argm->data, arg); + return set_uint(optn->data, arg); } -int CLIF_arg_uint (CLIF_argument *argm, char *arg, int index) { +int CLIF_set_double(CLIF_option *optn, char *arg) { - return set_uint (argm->data, arg); + return set_double(optn->data, arg); } -int CLIF_arg_double (CLIF_argument *argm, char *arg, int index) { +int CLIF_arg_int(CLIF_argument *argm, char *arg, int index) { + UNUSED(index); + return set_int(argm->data, arg); +} - return set_double (argm->data, arg); +int CLIF_arg_uint(CLIF_argument *argm, char *arg, int index) { + UNUSED(index); + return set_uint(argm->data, arg); } +int CLIF_arg_double(CLIF_argument *argm, char *arg, int index) { + UNUSED(index); + return set_double(argm->data, arg); +} -int CLIF_call_func (CLIF_option *optn, char *arg) { +int CLIF_call_func(CLIF_option *optn, char *arg) { - if (!optn->data) return -1; + if(!optn->data) + return -1; - if (optn->arg_name) { - int (*func) (char *) = optn->data; + if(optn->arg_name) { + int (*func)(char *) = optn->data; - return func (arg); - } else { - int (*func) (void) = optn->data; + return func(arg); + } else { + int (*func)(void) = optn->data; - return func (); - } + return func(); + } } -int CLIF_arg_func (CLIF_argument *argm, char *arg, int index) { - int (*func) (char *, int); +int CLIF_arg_func(CLIF_argument *argm, char *arg, int index) { + int (*func)(char *, int); - if (!argm->data) return -1; + if(!argm->data) + return -1; - func = (int (*) (char *, int)) argm->data; + func = (int (*)(char *, int)) argm->data; - return func (arg, index); + return func(arg, index); } diff --git a/iputils/traceroute/mod-dccp.c b/iputils/traceroute/mod-dccp.c index 077c20cef995f935df6b5b1a9613b449c40ada3d..26f2c653bf0fd3af1faeb911cd943e493edd93e9 100755 --- a/iputils/traceroute/mod-dccp.c +++ b/iputils/traceroute/mod-dccp.c @@ -230,6 +230,7 @@ static void dccp_send_probe (probe *pb, int ttl) { static probe *dccp_check_reply (int sk, int err, sockaddr_any *from, char *buf, size_t len) { + UNUSED(sk); probe *pb; struct dccp_hdr *ndh = (struct dccp_hdr *) buf; uint16_t sport, dport; diff --git a/iputils/traceroute/mod-icmp.c b/iputils/traceroute/mod-icmp.c index ed13b5096e422c03edc65a3ce4825370b4f8acf2..e2194d9aa4563b22b48d66f324de9f8cedf61b00 100755 --- a/iputils/traceroute/mod-icmp.c +++ b/iputils/traceroute/mod-icmp.c @@ -1,10 +1,10 @@ /* - Copyright (c) 2006, 2007 Dmitry Butskoy - <buc@citadel.stu.neva.ru> - License: GPL v2 or any later + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later - See COPYING for the status of this software. -*/ + See COPYING for the status of this software. + */ #include <stdlib.h> #include <unistd.h> @@ -18,8 +18,7 @@ #include "traceroute.h" - -static sockaddr_any dest_addr = {{ 0, }, }; +static sockaddr_any dest_addr = { { 0, }, }; static uint16_t seq = 1; static uint16_t ident = 0; @@ -32,219 +31,207 @@ static int last_ttl = 0; static int raw = 0; static int dgram = 0; - static CLIF_option icmp_options[] = { - { 0, "raw", 0, "Use raw sockets way only. Default is try this way " - "first (probably not allowed for unprivileged users), " - "then try dgram", - CLIF_set_flag, &raw, 0, CLIF_EXCL }, - { 0, "dgram", 0, "Use dgram sockets way only. May be not implemented " - "by old kernels or restricted by sysadmins", - CLIF_set_flag, &dgram, 0, CLIF_EXCL }, - CLIF_END_OPTION -}; - - -static int icmp_init (const sockaddr_any *dest, - unsigned int port_seq, size_t *packet_len_p) { - int i; - int af = dest->sa.sa_family; - int protocol; - - dest_addr = *dest; - dest_addr.sin.sin_port = 0; - - if (port_seq) seq = port_seq; - - length_p = packet_len_p; - if (*length_p < sizeof (struct icmphdr)) - *length_p = sizeof (struct icmphdr); - - data = malloc (*length_p); - if (!data) error ("malloc"); - - for (i = sizeof (struct icmphdr); i < *length_p; i++) - data[i] = 0x40 + (i & 0x3f); - - - protocol = (af == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6; - - if (!raw) { - icmp_sk = socket (af, SOCK_DGRAM, protocol); - if (icmp_sk < 0 && dgram) - error ("socket"); - } - - if (!dgram) { - int raw_sk = socket (af, SOCK_RAW, protocol); - if (raw_sk < 0) { - if (raw || icmp_sk < 0) - error_or_perm ("socket"); - dgram = 1; - } else { - /* prefer the traditional "raw" way when possible */ - close (icmp_sk); - icmp_sk = raw_sk; - } - } - - - tune_socket (icmp_sk); - - /* Don't want to catch packets from another hosts */ - if (raw_can_connect () && - connect (icmp_sk, &dest_addr.sa, sizeof (dest_addr)) < 0 - ) error ("connect"); - - use_recverr (icmp_sk); - - - if (dgram) { - sockaddr_any addr; - socklen_t len = sizeof (addr); - - if (getsockname (icmp_sk, &addr.sa, &len) < 0) - error ("getsockname"); - ident = ntohs (addr.sin.sin_port); /* both IPv4 and IPv6 */ - - } else - ident = getpid () & 0xffff; - - - add_poll (icmp_sk, POLLIN | POLLERR); - - return 0; + { 0, "raw", 0, "Use raw sockets way only. Default is try this way " + "first (probably not allowed for unprivileged users), " + "then try dgram", + CLIF_set_flag, &raw, 0, CLIF_EXCL }, + { 0, "dgram", 0, "Use dgram sockets way only. May be not implemented " + "by old kernels or restricted by sysadmins", + CLIF_set_flag, &dgram, 0, CLIF_EXCL }, + CLIF_END_OPTION + }; + +static int icmp_init(const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + int i; + int af = dest->sa.sa_family; + int protocol; + + dest_addr = *dest; + dest_addr.sin.sin_port = 0; + + if(port_seq) + seq = port_seq; + + length_p = packet_len_p; + if(*length_p < sizeof(struct icmphdr)) + *length_p = sizeof(struct icmphdr); + + data = malloc(*length_p); + if(!data) + error("malloc"); + + for(i = (int) sizeof(struct icmphdr); i < (int)*length_p; i++) + data[i] = 0x40 + (i & 0x3f); + + protocol = (af == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6; + + if(!raw) { + icmp_sk = socket(af, SOCK_DGRAM, protocol); + if(icmp_sk < 0 && dgram) + error("socket"); + } + + if(!dgram) { + int raw_sk = socket(af, SOCK_RAW, protocol); + if(raw_sk < 0) { + if(raw || icmp_sk < 0) + error_or_perm("socket"); + dgram = 1; + } else { + /* prefer the traditional "raw" way when possible */ + close(icmp_sk); + icmp_sk = raw_sk; + } + } + + tune_socket(icmp_sk); + + /* Don't want to catch packets from another hosts */ + if(raw_can_connect() && + connect(icmp_sk, &dest_addr.sa, sizeof(dest_addr)) < 0 + ) + error("connect"); + + use_recverr(icmp_sk); + + if(dgram) { + sockaddr_any addr; + socklen_t len = sizeof(addr); + + if(getsockname(icmp_sk, &addr.sa, &len) < 0) + error("getsockname"); + ident = ntohs(addr.sin.sin_port); /* both IPv4 and IPv6 */ + + } else + ident = getpid() & 0xffff; + + add_poll(icmp_sk, POLLIN | POLLERR); + + return 0; } +static void icmp_send_probe(probe *pb, int ttl) { + int af = dest_addr.sa.sa_family; -static void icmp_send_probe (probe *pb, int ttl) { - int af = dest_addr.sa.sa_family; - - - if (ttl != last_ttl) { - - set_ttl (icmp_sk, ttl); - - last_ttl = ttl; - } + if(ttl != last_ttl) { + set_ttl(icmp_sk, ttl); - if (af == AF_INET) { - struct icmp *icmp = (struct icmp *) data; + last_ttl = ttl; + } - icmp->icmp_type = ICMP_ECHO; - icmp->icmp_code = 0; - icmp->icmp_cksum = 0; - icmp->icmp_id = htons (ident); - icmp->icmp_seq = htons (seq); + if(af == AF_INET) { + struct icmp *icmp = (struct icmp *) data; - icmp->icmp_cksum = in_csum (data, *length_p); - } - else if (af == AF_INET6) { - struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) data; + icmp->icmp_type = ICMP_ECHO; + icmp->icmp_code = 0; + icmp->icmp_cksum = 0; + icmp->icmp_id = htons(ident); + icmp->icmp_seq = htons(seq); - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = 0; - icmp6->icmp6_id = htons (ident); - icmp6->icmp6_seq = htons(seq); + icmp->icmp_cksum = in_csum(data, *length_p); + } + else if(af == AF_INET6) { + struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) data; - /* icmp6->icmp6_cksum always computed by kernel internally */ - } + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = 0; + icmp6->icmp6_id= htons (ident); + icmp6->icmp6_seq= htons(seq); + /* icmp6->icmp6_cksum always computed by kernel internally */ + } - pb->send_time = get_time (); + pb->send_time = get_time(); - if (do_send (icmp_sk, data, *length_p, &dest_addr) < 0) { - pb->send_time = 0; - return; - } + if(do_send(icmp_sk, data, *length_p, &dest_addr) < 0) { + pb->send_time = 0; + return; + } + pb->seq = seq; - pb->seq = seq; + seq++; - seq++; - - return; + return; } +static probe *icmp_check_reply(int sk, int err, sockaddr_any *from, + char *buf, size_t len) { + UNUSED(sk); + UNUSED(from); + int af = dest_addr.sa.sa_family; + int type; + uint16_t recv_id, recv_seq; + probe *pb; -static probe *icmp_check_reply (int sk, int err, sockaddr_any *from, - char *buf, size_t len) { - int af = dest_addr.sa.sa_family; - int type; - uint16_t recv_id, recv_seq; - probe *pb; - - - if (len < sizeof (struct icmphdr)) - return NULL; - - - if (af == AF_INET) { - struct icmp *icmp = (struct icmp *) buf; + if(len < sizeof(struct icmphdr)) + return NULL; - type = icmp->icmp_type; + if(af == AF_INET) { + struct icmp *icmp = (struct icmp *) buf; - recv_id = ntohs (icmp->icmp_id); - recv_seq = ntohs (icmp->icmp_seq); + type = icmp->icmp_type; - } - else { /* AF_INET6 */ - struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) buf; + recv_id = ntohs(icmp->icmp_id); + recv_seq = ntohs(icmp->icmp_seq); - type = icmp6->icmp6_type; + } + else { /* AF_INET6 */ + struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) buf; - recv_id = ntohs (icmp6->icmp6_id); - recv_seq = ntohs (icmp6->icmp6_seq); - } + type = icmp6->icmp6_type; + recv_id = ntohs(icmp6->icmp6_id); + recv_seq = ntohs(icmp6->icmp6_seq); + } - if (recv_id != ident) - return NULL; + if(recv_id != ident) + return NULL; - pb = probe_by_seq (recv_seq); - if (!pb) return NULL; + pb = probe_by_seq(recv_seq); + if(!pb) + return NULL; + if(!err) { - if (!err) { + if(!(af == AF_INET && type == ICMP_ECHOREPLY) && + !(af == AF_INET6 && type == ICMP6_ECHO_REPLY) + ) + return NULL; - if (!(af == AF_INET && type == ICMP_ECHOREPLY) && - !(af == AF_INET6 && type == ICMP6_ECHO_REPLY) - ) return NULL; + pb->final = 1; + } - pb->final = 1; - } - - return pb; + return pb; } +static void icmp_recv_probe(int sk, int revents) { -static void icmp_recv_probe (int sk, int revents) { - - if (!(revents & (POLLIN | POLLERR))) - return; + if(!(revents & (POLLIN | POLLERR))) + return; - recv_reply (sk, !!(revents & POLLERR), icmp_check_reply); + recv_reply(sk, !!(revents & POLLERR), icmp_check_reply); } +static void icmp_expire_probe(probe *pb) { -static void icmp_expire_probe (probe *pb) { - - probe_done (pb); + probe_done(pb); } - static tr_module icmp_ops = { - .name = "icmp", - .init = icmp_init, - .send_probe = icmp_send_probe, - .recv_probe = icmp_recv_probe, - .expire_probe = icmp_expire_probe, - .options = icmp_options, + .name = "icmp", + .init = icmp_init, + .send_probe = icmp_send_probe, + .recv_probe = icmp_recv_probe, + .expire_probe = icmp_expire_probe, + .options = icmp_options, }; -TR_MODULE (icmp_ops); +TR_MODULE(icmp_ops); void tr_module_icmp_insert() { diff --git a/iputils/traceroute/mod-raw.c b/iputils/traceroute/mod-raw.c index 6a05516ce288db54098e3a49761268bcef4ab8ec..bd9f05ba612569e5fbfdb1a3aec01990a55dd8a0 100755 --- a/iputils/traceroute/mod-raw.c +++ b/iputils/traceroute/mod-raw.c @@ -32,7 +32,8 @@ static int seq = 0; static int set_protocol (CLIF_option *optn, char *arg) { - char *q; + UNUSED(optn); + char *q; protocol = strtoul (arg, &q, 0); if (q == arg) { @@ -71,7 +72,7 @@ static int raw_init (const sockaddr_any *dest, !(data = malloc (*length_p)) ) error ("malloc"); - for (i = 0; i < *length_p; i++) + for (i = 0; i < (int)*length_p; i++) data[i] = 0x40 + (i & 0x3f); @@ -121,7 +122,10 @@ static void raw_send_probe (probe *pb, int ttl) { static probe *raw_check_reply (int sk, int err, sockaddr_any *from, char *buf, size_t len) { - probe *pb; + UNUSED(sk); + UNUSED(len); + UNUSED(buf); + probe *pb; if (!equal_addr (&dest_addr, from)) return NULL; diff --git a/iputils/traceroute/mod-tcp.c b/iputils/traceroute/mod-tcp.c index b5b0ca2d520cd41c0a8a9b81fd1ce2ea644bfb9f..32d2f1027e88db3ff623150cfcca5b7aad7ccf8d 100755 --- a/iputils/traceroute/mod-tcp.c +++ b/iputils/traceroute/mod-tcp.c @@ -81,7 +81,7 @@ static char *names_by_flags (unsigned int flags) { char *curr = str; char *end = str + sizeof (str) / sizeof (*str); - for (i = 0; i < sizeof (tcp_flags) / sizeof (*tcp_flags); i++) { + for (i = 0; i < (int)(sizeof (tcp_flags) / sizeof (*tcp_flags)); i++) { const char *p; if (!(flags & tcp_flags[i].flag)) continue; @@ -96,9 +96,10 @@ static char *names_by_flags (unsigned int flags) { } static int set_tcp_flag (CLIF_option *optn, char *arg) { - int i; + UNUSED(arg); + int i; - for (i = 0; i < sizeof (tcp_flags) / sizeof (*tcp_flags); i++) { + for (i = 0; i < (int)(sizeof (tcp_flags) / sizeof (*tcp_flags)); i++) { if (!strcmp (optn->long_opt, tcp_flags[i].name)) { flags |= tcp_flags[i].flag; return 0; @@ -109,7 +110,8 @@ static int set_tcp_flag (CLIF_option *optn, char *arg) { } static int set_tcp_flags (CLIF_option *optn, char *arg) { - char *q; + UNUSED(optn); + char *q; unsigned long value; value = strtoul (arg, &q, 0); @@ -120,7 +122,7 @@ static int set_tcp_flags (CLIF_option *optn, char *arg) { } static int set_flag (CLIF_option *optn, char *arg) { - + UNUSED(arg); flags |= (unsigned long) optn->data; return 0; @@ -318,7 +320,7 @@ static int tcp_init (const sockaddr_any *dest, if (flags & TH_SYN) { *ptr++ = TCPOPT_MAXSEG; /* 2 */ *ptr++ = TCPOLEN_MAXSEG; /* 4 */ - *((uint16_t *) ptr) = htons (mss ? mss : mtu); + *((uint16_t *) ptr) = htons (mss ? mss : (unsigned int)mtu); ptr += sizeof (uint16_t); } @@ -441,6 +443,7 @@ static void tcp_send_probe (probe *pb, int ttl) { static probe *tcp_check_reply (int sk, int err, sockaddr_any *from, char *buf, size_t len) { + UNUSED(sk); probe *pb; struct tcphdr *tcp = (struct tcphdr *) buf; uint16_t sport, dport; diff --git a/iputils/traceroute/mod-tcpconn.c b/iputils/traceroute/mod-tcpconn.c index df37bb556b80d1a78f5f10e19aae056a334289d9..13e239864756de3639330189389933df570e8bf6 100755 --- a/iputils/traceroute/mod-tcpconn.c +++ b/iputils/traceroute/mod-tcpconn.c @@ -28,6 +28,7 @@ static int icmp_sk = -1; static int tcp_init (const sockaddr_any *dest, unsigned int port_seq, size_t *packet_len_p) { + UNUSED(packet_len_p); int af = dest->sa.sa_family; dest_addr = *dest; @@ -94,6 +95,9 @@ static void tcp_send_probe (probe *pb, int ttl) { static probe *tcp_check_reply (int sk, int err, sockaddr_any *from, char *buf, size_t len) { + UNUSED(sk); + UNUSED(err); + UNUSED(from); int af = dest_addr.sa.sa_family; int type, code, info; probe *pb; diff --git a/iputils/traceroute/mod-udp.c b/iputils/traceroute/mod-udp.c index b2d319d7f8fe791baba3741fad056ee9a73939a6..e24d0271c8c6e60f40592f0be18e3e7c7b482379 100755 --- a/iputils/traceroute/mod-udp.c +++ b/iputils/traceroute/mod-udp.c @@ -44,7 +44,7 @@ static void fill_data (size_t *packet_len_p) { !(data = malloc (*length_p)) ) error ("malloc"); - for (i = 0; i < *length_p; i++) + for (i = 0; i < (int)*length_p; i++) data[i] = 0x40 + (i & 0x3f); return; @@ -166,7 +166,9 @@ static void udp_send_probe (probe *pb, int ttl) { static probe *udp_check_reply (int sk, int err, sockaddr_any *from, char *buf, size_t len) { - probe *pb; + UNUSED(buf); + UNUSED(len); + probe *pb; pb = probe_by_sk (sk); if (!pb) return NULL; diff --git a/iputils/traceroute/poll.c b/iputils/traceroute/poll.c index 988c456030091f09c3d713dee5994bd04d6e10ef..232a83395bc600ab54bddb1d8ea7c98e3ceb8526 100755 --- a/iputils/traceroute/poll.c +++ b/iputils/traceroute/poll.c @@ -22,9 +22,9 @@ static unsigned int num_polls = 0; void add_poll (int fd, int events) { int i; - for (i = 0; i < num_polls && pfd[i].fd > 0; i++) ; + for (i = 0; i < (int)num_polls && pfd[i].fd > 0; i++) ; - if (i == num_polls) { + if (i == (int)num_polls) { pfd = realloc (pfd, ++num_polls * sizeof (*pfd)); if (!pfd) error ("realloc"); } @@ -37,21 +37,21 @@ void add_poll (int fd, int events) { void del_poll (int fd) { int i; - for (i = 0; i < num_polls && pfd[i].fd != fd; i++) ; + for (i = 0; i < (int)num_polls && pfd[i].fd != fd; i++) ; - if (i < num_polls) pfd[i].fd = -1; /* or just zero it... */ + if (i < (int)num_polls) pfd[i].fd = -1; /* or just zero it... */ } static int cleanup_polls (void) { int i; - for (i = 0; i < num_polls && pfd[i].fd > 0; i++) ; + for (i = 0; i < (int)num_polls && pfd[i].fd > 0; i++) ; - if (i < num_polls) { /* a hole have found */ + if (i < (int)num_polls) { /* a hole have found */ int j; - for (j = i + 1; j < num_polls; j++) { + for (j = i + 1; j < (int)num_polls; j++) { if (pfd[j].fd > 0) { pfd[i++] = pfd[j]; pfd[j].fd = -1; @@ -78,7 +78,7 @@ void do_poll (double timeout, void (*callback) (int fd, int revents)) { error ("poll"); } - for (i = 0; n && i < num_polls; i++) { + for (i = 0; n && i < (int)num_polls; i++) { if (pfd[i].revents) { callback (pfd[i].fd, pfd[i].revents); n--; diff --git a/iputils/traceroute/traceroute.c b/iputils/traceroute/traceroute.c index b0e92bc0eb9c3b13db9a4d055f336b2352d31474..0142e70948b7c7ffb9645ed39decf915ee7346ae 100755 --- a/iputils/traceroute/traceroute.c +++ b/iputils/traceroute/traceroute.c @@ -32,9 +32,7 @@ #include <stdbool.h> #include <glib.h> #include "traceroute.h" -#include "../iputils.h" -#define UNUSED(x) (void)(x) #ifndef ICMP6_DST_UNREACH_BEYONDSCOPE #ifdef ICMP6_DST_UNREACH_NOTNEIGHBOR @@ -753,8 +751,7 @@ static bool print_addr(sockaddr_any *res) { if(noresolve) { log_printf("%s", str); - //ret_str = g_strdup_printf("%s", str); - if(!strcmp(dst_name, str)) + if(str && !strcmp(dst_name, str)) is_final = true; } else { @@ -764,9 +761,11 @@ static bool print_addr(sockaddr_any *res) { getnameinfo(&res->sa, sizeof(*res), buf, sizeof(buf), 0, 0, NI_IDN); log_printf(" %s (%s)", buf[0] ? buf : str, str); - //ret_str = g_strdup_printf("%s", buf[0] ? buf : str); if(buf[0] && !strcmp(dst_name, buf)) is_final = true; + else + if(str && !strcmp(dst_name, str)) + is_final = true; } if(as_lookups) @@ -1070,12 +1069,24 @@ static void do_it(void) { if(pb->done) { if(n == start) { /* can print it now */ - if(print_probe(pb)) + if(print_probe(pb)) { pb->final = 1; + } //log_printf("(host=%s,%s recv_ttl=%d)", dst_name, (host) ? host : "-", pb->recv_ttl); start++; } + /* { + char buf[1024]; + buf[0] = '\0'; + getnameinfo(&(pb->res.sa), sizeof((pb->res)), buf, sizeof(buf),0, 0, NI_IDN); + if(buf[0] && !strcmp(dst_name, buf)) + pb->real_final = true; + //else + //if(str && !strcmp(dst_name, str)) + // pb->real_final = true; + }*/ + if(pb->final) end = (n / probes_per_hop + 1) * probes_per_hop; @@ -1694,22 +1705,30 @@ int raw_can_connect(void) { return can_connect; } +/** + * Traceroute host + * + * @addr[in] host name or IP address + * @hops[out] hops count + * @time_usec[out] latency in microseconds + * @return 0 Ok, -1 error + */ int traceroute_util(const char *addr, int *hops, int *time_usec) { UNUSED(hops); - int type = 6; // 4 or 6 - //int total_hops = 0; - long int total_time_usec = 0; // latency in microseconds + int type = 6; // ipv4 or ipv6 int argc = 3; const char *argv[argc]; if(type != 4) argv[0] = "traceroute6"; else argv[0] = "traceroute4"; - //argv[1] = "-A"; - argv[1] = "-4"; // -n -m 16 + argv[1] = "-4"; // ipv4 argv[2] = addr; + *hops = 0; + *time_usec = 0; + int ret = traceroute_main(argc, (char**) argv); if(!ret) for(int i = 0; i < (int) num_probes; i++) { @@ -1717,13 +1736,17 @@ int traceroute_util(const char *addr, int *hops, int *time_usec) if(one_probe->done && one_probe->final && one_probe->recv_ttl) { *hops = i / DEF_NUM_PROBES + 1; *time_usec = (int) ((one_probe->recv_time - one_probe->send_time) * 1000000); - ret = 1; + // if error -> not found host + if(!strlen(one_probe->err_str)) + ret = 1; break; } /*if(one_probe->done) - printf("%d(%d) dseq=%d sk=%d done=%d final=%d recv_ttl=%d dt=%lf\n", i + 1, i / DEF_NUM_PROBES + 1, + printf("%d(%d) dseq=%d sk=%d done=%d final=%d recv_ttl=%d dt=%lf err='%s'\n", i + 1, + i / DEF_NUM_PROBES + 1, one_probe->seq, one_probe->sk, one_probe->done, - one_probe->final, one_probe->recv_ttl, one_probe->recv_time - one_probe->send_time);*/ + one_probe->final, one_probe->recv_ttl, one_probe->recv_time - one_probe->send_time, + one_probe->err_str);*/ } free(probes); diff --git a/iputils/traceroute/traceroute.h b/iputils/traceroute/traceroute.h index 53dc7933554534c857947bf694a7f83823c2236e..532b7b6f0912d67fb71e2bcac901d7f9da99bb37 100755 --- a/iputils/traceroute/traceroute.h +++ b/iputils/traceroute/traceroute.h @@ -9,7 +9,7 @@ #include <netinet/in.h> #include <clif.h> - +#include "../iputils.h" union common_sockaddr { struct sockaddr sa; diff --git a/iputils/traceroute6.c b/iputils/traceroute6.c deleted file mode 100755 index ffe1d8dfb67be708613cb535eb1a74905f6baa82..0000000000000000000000000000000000000000 --- a/iputils/traceroute6.c +++ /dev/null @@ -1,981 +0,0 @@ -/* - * Modified for NRL 4.4BSD IPv6 release. - * 07/31/96 bgp - * - * Search for "#ifdef NRL" to find the changes. - */ - -/* - * Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt> - * 31/07/1996 - * - * As ICMP error messages for IPv6 now include more than 8 bytes - * UDP datagrams are now sent via an UDP socket instead of magic - * RAW socket tricks. - * - * Original copyright and comments left intact. They might not - * match the code anymore. - */ - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * traceroute host - trace the route ip packets follow going to "host". - * - * Attempt to trace the route an ip packet would follow to some - * internet host. We find out intermediate hops by launching probe - * packets with a small ttl (time to live) then listening for an - * icmp "time exceeded" reply from a gateway. We start our probes - * with a ttl of one and increase by one until we get an icmp "port - * unreachable" (which means we got to "host") or hit a max (which - * defaults to 30 hops & can be changed with the -m flag). Three - * probes (change with -q flag) are sent at each ttl setting and a - * line is printed showing the ttl, address of the gateway and - * round trip time of each probe. If the probe answers come from - * different gateways, the address of each responding system will - * be printed. If there is no response within a 5 sec. timeout - * interval (changed with the -w flag), a "*" is printed for that - * probe. - * - * Probe packets are UDP format. We don't want the destination - * host to process them so the destination port is set to an - * unlikely value (if some clod on the destination is using that - * value, it can be changed with the -p flag). - * - * A sample use might be: - * - * [yak 71]% traceroute nis.nsf.net. - * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet - * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms - * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms - * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms - * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms - * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms - * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms - * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms - * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms - * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms - * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms - * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms - * - * Note that lines 2 & 3 are the same. This is due to a buggy - * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards - * packets with a zero ttl. - * - * A more interesting example is: - * - * [yak 72]% traceroute allspice.lcs.mit.edu. - * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max - * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms - * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms - * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms - * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms - * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms - * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms - * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms - * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms - * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms - * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms - * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms - * 12 * * * - * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms - * 14 * * * - * 15 * * * - * 16 * * * - * 17 * * * - * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms - * - * (I start to see why I'm having so much trouble with mail to - * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away - * either don't send ICMP "time exceeded" messages or send them - * with a ttl too small to reach us. 14 - 17 are running the - * MIT C Gateway code that doesn't send "time exceeded"s. God - * only knows what's going on with 12. - * - * The silent gateway 12 in the above may be the result of a bug in - * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) - * sends an unreachable message using whatever ttl remains in the - * original datagram. Since, for gateways, the remaining ttl is - * zero, the icmp "time exceeded" is guaranteed to not make it back - * to us. The behavior of this bug is slightly more interesting - * when it appears on the destination system: - * - * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms - * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms - * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms - * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms - * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms - * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms - * 7 * * * - * 8 * * * - * 9 * * * - * 10 * * * - * 11 * * * - * 12 * * * - * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! - * - * Notice that there are 12 "gateways" (13 is the final - * destination) and exactly the last half of them are "missing". - * What's really happening is that rip (a Sun-3 running Sun OS3.5) - * is using the ttl from our arriving datagram as the ttl in its - * icmp reply. So, the reply will time out on the return path - * (with no notice sent to anyone since icmp's aren't sent for - * icmp's) until we probe with a ttl that's at least twice the path - * length. I.e., rip is really only 7 hops away. A reply that - * returns with a ttl of 1 is a clue this problem exists. - * Traceroute prints a "!" after the time if the ttl is <= 1. - * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or - * non-standard (HPUX) software, expect to see this problem - * frequently and/or take care picking the target host of your - * probes. - * - * Other possible annotations after the time are !H, !N, !P (got a host, - * network or protocol unreachable, respectively), !S or !F (source - * route failed or fragmentation needed -- neither of these should - * ever occur and the associated gateway is busted if you see one), - * !X (communication administratively prohibited). If - * almost all the probes result in some kind of unreachable, traceroute - * will give up and exit. - * - * Notes - * ----- - * This program must be run by root or be setuid. (I suggest that - * you *don't* make it setuid -- casual use could result in a lot - * of unnecessary traffic on our poor, congested nets.) - * - * This program requires a kernel mod that does not appear in any - * system available from Berkeley: A raw ip socket using proto - * IPPROTO_RAW must interpret the data sent as an ip datagram (as - * opposed to data to be wrapped in a ip datagram). See the README - * file that came with the source to this program for a description - * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may - * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE - * MODIFIED TO RUN THIS PROGRAM. - * - * The udp port usage may appear bizarre (well, ok, it is bizarre). - * The problem is that an icmp message only contains 8 bytes of - * data from the original datagram. 8 bytes is the size of a udp - * header so, if we want to associate replies with the original - * datagram, the necessary information must be encoded into the - * udp header (the ip id could be used but there's no way to - * interlock with the kernel's assignment of ip id's and, anyway, - * it would have taken a lot more kernel hacking to allow this - * code to set the ip id). So, to allow two or more users to - * use traceroute simultaneously, we use this task's pid as the - * source port (the high bit is set to move the port number out - * of the "likely" range). To keep track of which probe is being - * replied to (so times and/or hop counts don't get confused by a - * reply that was delayed in transit), we increment the destination - * port number before each probe. - * - * Don't use this as a coding example. I was trying to find a - * routing problem and this code sort-of popped out after 48 hours - * without sleep. I was amazed it ever compiled, much less ran. - * - * I stole the idea for this program from Steve Deering. Since - * the first release, I've learned that had I attended the right - * IETF working group meetings, I also could have stolen it from Guy - * Almes or Matt Mathis. I don't know (or care) who came up with - * the idea first. I envy the originators' perspicacity and I'm - * glad they didn't keep the idea a secret. - * - * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or - * enhancements to the original distribution. - * - * I've hacked up a round-trip-route version of this that works by - * sending a loose-source-routed udp datagram through the destination - * back to yourself. Unfortunately, SO many gateways botch source - * routing, the thing is almost worthless. Maybe one day... - * - * -- Van Jacobson (van@helios.ee.lbl.gov) - * Tue Dec 20 03:50:13 PST 1988 - */ - -#include <arpa/inet.h> -#include <errno.h> -#include <linux/types.h> -#include <netdb.h> -#include <net/if.h> -#include <netinet/icmp6.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip6.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/udp.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/file.h> -#include <sys/ioctl.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <time.h> -#include <unistd.h> -#include <glib.h> - -#include "iputils.h" - -#if __linux__ -# include <endian.h> -#endif - -#ifdef HAVE_LIBCAP -# include <sys/capability.h> -#endif - -#ifdef USE_IDN -# include <locale.h> -# ifndef NI_IDN -# define NI_IDN 32 -# endif -# define ADDRINFO_IDN_FLAGS AI_IDN -# define getnameinfo_flags NI_IDN -#else -# define getnameinfo_flags 0 -# define ADDRINFO_IDN_FLAGS 0 -#endif - -#ifndef SOL_IPV6 -# define SOL_IPV6 IPPROTO_IPV6 -#endif - -enum { - DEFAULT_PROBES = 3, - DEFAULT_HOPS = 30, - DEFAULT_PORT = 32768 + 666, - DEFAULT_WAIT = 5, - PACKET_SIZE = 512, - MAXPACKET = 65535, - - /* - * The following are copy from linux/icmpv6.h that cannot be - * included because icmp6_filter prototype is redefined in - * netinet/icmp6.h header. - */ - ICMPV6_DEST_UNREACH = 1, - ICMPV6_PKT_TOOBIG = 2, - ICMPV6_TIME_EXCEED = 3, - ICMPV6_PARAMPROB = 4, - ICMPV6_ECHO_REQUEST = 128, - ICMPV6_ECHO_REPLY = 129, - ICMPV6_MGM_QUERY = 130, - ICMPV6_MGM_REPORT = 131, - ICMPV6_MGM_REDUCTION = 132, - ICMPV6_NI_QUERY = 139, - ICMPV6_NI_REPLY = 140, - ICMPV6_MLD2_REPORT = 143, - ICMPV6_DHAAD_REQUEST = 144, - ICMPV6_DHAAD_REPLY = 145, - ICMPV6_MOBILE_PREFIX_SOL = 146, - ICMPV6_MOBILE_PREFIX_ADV = 147, - - /* - * ICMP codes for neighbour discovery messages. These are from - * linux kernel source include/net/ndisc.h file. The user api - * includes does not have these values. - */ - NDISC_ROUTER_SOLICITATION = 133, - NDISC_ROUTER_ADVERTISEMENT = 134, - NDISC_NEIGHBOUR_SOLICITATION = 135, - NDISC_NEIGHBOUR_ADVERTISEMENT = 136, - NDISC_REDIRECT = 137, -}; - -#ifndef FD_SET -# define NFDBITS (8 * sizeof(fd_set)) -# define FD_SETSIZE NFDBITS -# define FD_SET(n, p) ((p)->fds_bits[(n) / NFDBITS] |= (1 << ((n) % NFDBITS))) -# define FD_CLR(n, p) ((p)->fds_bits[(n) / NFDBITS] &= ~(1 << ((n) % NFDBITS))) -# define FD_ISSET(n, p) ((p)->fds_bits[(n) / NFDBITS] & (1 << ((n) % NFDBITS))) -# define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p))) -#endif - -struct run_state { - unsigned char packet[PACKET_SIZE]; /* last inbound (icmp) packet */ - int icmp_sock; /* receive (icmp) socket file descriptor */ - int sndsock; /* send (udp) socket file descriptor */ - char *sendbuff; - int datalen; - struct sockaddr_in6 whereto; /* Who to try to reach */ - struct sockaddr_in6 saddr; - struct sockaddr_in6 firsthop; - char *source; - char *device; - char *hostname; - int nprobes; - int max_ttl; - pid_t ident; - unsigned short port; /* start udp dest port # for probe packets */ - int options; /* socket options */ - int waittime; /* time to wait for response (in seconds) */ - unsigned int - nflag:1, /* print addresses numerically */ - verbose:1; -}; - -struct pkt_format { - uint32_t ident; - uint32_t seq; - struct timespec ts; -}; - -/* - * All includes, definitions, struct declarations, and global variables are - * above. After this comment all you can find is functions. - */ - -static int wait_for_reply(struct run_state *ctl, struct sockaddr_in6 *from, - struct in6_addr *to, const uint8_t reset_timer) -{ - fd_set fds; - static struct timeval wait; - ssize_t cc = 0; - char cbuf[PACKET_SIZE]; - - FD_ZERO(&fds); - FD_SET(ctl->icmp_sock, &fds); - if (reset_timer) { - /* - * traceroute could hang if someone else has a ping - * running and our ICMP reply gets dropped but we don't - * realize it because we keep waking up to handle those - * other ICMP packets that keep coming in. To fix this, - * "reset_timer" will only be true if the last packet that - * came in was for us or if this is the first time we're - * waiting for a reply since sending out a probe. Note - * that this takes advantage of the select() feature on - * Linux where the remaining timeout is written to the - * struct timeval area. - */ - wait.tv_sec = ctl->waittime; - wait.tv_usec = 0; - } - - if (select(ctl->icmp_sock + 1, &fds, NULL, NULL, &wait) > 0) { - struct iovec iov = { - .iov_base = ctl->packet, - .iov_len = sizeof(ctl->packet) - }; - struct msghdr msg = { - .msg_name = (void *)from, - .msg_namelen = sizeof(*from), - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cbuf, - .msg_controllen = sizeof(cbuf), - 0 - }; - - cc = recvmsg(ctl->icmp_sock, &msg, 0); - if (cc >= 0) { - struct cmsghdr *cmsg; - struct in6_pktinfo *ipi; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level != SOL_IPV6) - continue; - switch (cmsg->cmsg_type) { - case IPV6_PKTINFO: -#ifdef IPV6_2292PKTINFO - case IPV6_2292PKTINFO: -#endif - ipi = (struct in6_pktinfo *) - CMSG_DATA(cmsg); - memcpy(to, ipi, sizeof(*to)); - } - } - } - } - - return (cc); -} - -static void send_probe(struct run_state *ctl, uint32_t seq, int ttl) -{ - struct pkt_format *pkt = (struct pkt_format *)ctl->sendbuff; - int i; - - pkt->ident = htonl(ctl->ident); - pkt->seq = htonl(seq); - clock_gettime(CLOCK_MONOTONIC_RAW, &pkt->ts); - - i = setsockopt(ctl->sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); - if (i < 0) { - perror("setsockopt"); - exit(1); - } - - do { - i = sendto(ctl->sndsock, ctl->sendbuff, ctl->datalen, 0, - (struct sockaddr *)&ctl->whereto, sizeof(ctl->whereto)); - } while (i < 0 && errno == ECONNREFUSED); - - if (i < 0 || i != ctl->datalen) { - if (i < 0) - perror("sendto"); - printf("traceroute: wrote %s %d chars, ret=%d\n", ctl->hostname, ctl->datalen, i); - fflush(stdout); - } -} - -static double deltaT(struct timespec *a, struct timespec *b) -{ - struct timespec c; - double dt; - - if ((b->tv_nsec - a->tv_nsec) < 0) { - c.tv_sec = b->tv_sec - a->tv_sec - 1UL; - c.tv_nsec = b->tv_nsec - a->tv_nsec + 1000000000UL; - } else { - c.tv_sec = b->tv_sec - a->tv_sec; - c.tv_nsec = b->tv_nsec - a->tv_nsec; - } - dt = (double)(c.tv_sec * 1000.0L) + (double)(c.tv_nsec / 1000000.0L); - return (dt); -} - -/* - * Convert an ICMP "type" field to a printable string. - */ -static char const *pr_type(const uint8_t t) -{ - switch (t) { - /* Unknown */ - case 0: - return "Error"; - case ICMPV6_DEST_UNREACH: - return "Destination Unreachable"; - case ICMPV6_PKT_TOOBIG: - return "Packet Too Big"; - case ICMPV6_TIME_EXCEED: - return "Time Exceeded in Transit"; - case ICMPV6_PARAMPROB: - return "Parameter Problem"; - case ICMPV6_ECHO_REQUEST: - return "Echo Request"; - case ICMPV6_ECHO_REPLY: - return "Echo Reply"; - case ICMPV6_MGM_QUERY: - return "Membership Query"; - case ICMPV6_MGM_REPORT: - return "Membership Report"; - case ICMPV6_MGM_REDUCTION: - return "Membership Reduction"; - case NDISC_ROUTER_SOLICITATION: - return "Router Solicitation"; - case NDISC_ROUTER_ADVERTISEMENT: - return "Router Advertisement"; - case NDISC_NEIGHBOUR_SOLICITATION: - return "Neighbor Solicitation"; - case NDISC_NEIGHBOUR_ADVERTISEMENT: - return "Neighbor Advertisement"; - case NDISC_REDIRECT: - return "Redirect"; - case ICMPV6_NI_QUERY: - return "Neighbor Query"; - case ICMPV6_NI_REPLY: - return "Neighbor Reply"; - case ICMPV6_MLD2_REPORT: - return "Multicast Listener Report packet"; - case ICMPV6_DHAAD_REQUEST: - return "Home Agent Address Discovery Request Message"; - case ICMPV6_DHAAD_REPLY: - return "Home Agent Address Discovery Reply message"; - case ICMPV6_MOBILE_PREFIX_SOL: - return "Mobile Prefix Solicitation Message"; - case ICMPV6_MOBILE_PREFIX_ADV: - return "Mobile Prefix Solicitation Advertisement"; - default: - return "OUT-OF-RANGE"; - } - abort(); -} - -static int packet_ok(struct run_state *ctl, int cc, struct sockaddr_in6 *from, - struct in6_addr *to, uint32_t seq, struct timespec *ts) -{ - struct icmp6_hdr *icp = (struct icmp6_hdr *)ctl->packet; - uint8_t type, code; - - type = icp->icmp6_type; - code = icp->icmp6_code; - - if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) - || type == ICMP6_DST_UNREACH) { - struct ip6_hdr *hip; - struct udphdr *up; - int nexthdr; - - hip = (struct ip6_hdr *)(icp + 1); - up = (struct udphdr *)(hip + 1); - nexthdr = hip->ip6_nxt; - - if (nexthdr == 44) { - nexthdr = *(unsigned char *)up; - up++; - } - if (nexthdr == IPPROTO_UDP) { - struct pkt_format *pkt; - - pkt = (struct pkt_format *)(up + 1); - - if (ntohl(pkt->ident) == (uint32_t) ctl->ident && ntohl(pkt->seq) == seq) { - *ts = pkt->ts; - return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); - } - } - - } - - if (ctl->verbose) { - unsigned char *p; - char pa1[NI_MAXHOST]; - char pa2[NI_MAXHOST]; - int i; - - p = (unsigned char *)(icp + 1); - - printf("\n%d bytes from %s to %s", cc, - inet_ntop(AF_INET6, &from->sin6_addr, pa1, sizeof(pa1)), - inet_ntop(AF_INET6, to, pa2, sizeof(pa2))); - - printf(": icmp type %d (%s) code %d\n", type, pr_type(type), icp->icmp6_code); - - cc -= sizeof(struct icmp6_hdr); - for (i = 0; i < cc; i++) { - if (i % 16 == 0) - printf("%04x:", i); - if (i % 4 == 0) - printf(" "); - printf("%02x", 0xff & (unsigned)p[i]); - if (i % 16 == 15 && i + 1 < cc) - printf("\n"); - } - printf("\n"); - } - - return (0); -} - -static void print(struct run_state *ctl, struct sockaddr_in6 *from) -{ - char pa[NI_MAXHOST] = ""; - char hnamebuf[NI_MAXHOST] = ""; - - if (ctl->nflag) - printf(" %s", inet_ntop(AF_INET6, &from->sin6_addr, pa, sizeof(pa))); - else { - inet_ntop(AF_INET6, &from->sin6_addr, pa, sizeof(pa)); - getnameinfo((struct sockaddr *)from, sizeof *from, hnamebuf, - sizeof hnamebuf, NULL, 0, getnameinfo_flags); - - printf(" %s (%s)", hnamebuf[0] ? hnamebuf : pa, pa); - } -} - -static __attribute__((noreturn)) void usage(void) -{ - fprintf(stderr, - "\nUsage:\n" - " traceroute6 [options] <destination>\n" - "\nOptions:\n" - " -d use SO_DEBUG socket option\n" - " -i <device> bind to <device>\n" - " -m <hops> use maximum <hops>\n" - " -n no dns name resolution\n" - " -p <port> use destination <port>\n" - " -q <nprobes> number of probes\n" - " -r use SO_DONTROUTE socket option\n" - " -s <address> use source <address>\n" - " -v verbose output\n" - " -w <timeout> time to wait for response\n" - "\nFor more details see traceroute6(8).\n"); - exit(1); -} - -static uint16_t get_ip_unprivileged_port_start(const uint16_t fallback) -{ - FILE *f; - uint16_t nr = fallback; - - f = fopen("/proc/sys/net/ipv4/ip_unprivileged_port_start", "r"); - if (f) { - if (fscanf(f, "%" SCNu16, &nr) != 1) - nr = fallback; - fclose(f); - } - return nr; -} - -int traceroute6_main(int argc, char **argv) -{ - struct run_state ctl = { - .nprobes = DEFAULT_PROBES, - .max_ttl = DEFAULT_HOPS, - .port = DEFAULT_PORT, - .waittime = DEFAULT_WAIT, - 0 - }; - char pa[NI_MAXHOST]; - extern char *optarg; - extern int optind; - struct addrinfo hints6 = { - .ai_family = AF_INET6, - .ai_socktype = SOCK_RAW, - .ai_flags = AI_CANONNAME | ADDRINFO_IDN_FLAGS - }; - struct addrinfo *result; - int status; - struct sockaddr_in6 from; - struct sockaddr_in6 *to = (struct sockaddr_in6 *)&ctl.whereto; - int ch, i, probe, ttl, on = 1; - uint32_t seq = 0; - int socket_errno; - char *resolved_hostname = NULL; - - ctl.datalen = sizeof(struct pkt_format); - ctl.icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - socket_errno = errno; - - if (setuid(getuid())) { - perror("traceroute6: setuid"); - exit(-1); - } -#ifdef HAVE_LIBCAP - { - cap_t caps = cap_init(); - - if (cap_set_proc(caps)) { - perror("traceroute6: cap_set_proc"); - exit(-1); - } - cap_free(caps); - } -#endif - -#ifdef USE_IDN - setlocale(LC_ALL, ""); -#endif - while ((ch = getopt(argc, argv, "dm:np:q:rs:w:vi:V")) != EOF) { - switch (ch) { - case 'd': - ctl.options |= SO_DEBUG; - break; - case 'm': - ctl.max_ttl = atoi(optarg); - if (ctl.max_ttl <= 1) { - fprintf(stderr, "traceroute: max ttl must be >1.\n"); - exit(1); - } - break; - case 'n': - ctl.nflag = 1; - break; - case 'p': - ctl.port = atoi(optarg); - if (ctl.port < 1) { - fprintf(stderr, "traceroute: port must be >0.\n"); - exit(1); - } - break; - case 'q': - ctl.nprobes = atoi(optarg); - if (ctl.nprobes < 1) { - fprintf(stderr, "traceroute: nprobes must be >0.\n"); - exit(1); - } - break; - case 'r': - ctl.options |= SO_DONTROUTE; - break; - case 's': - /* - * set the ip source address of the outbound probe - * (e.g., on a multi-homed host). - */ - ctl.source = optarg; - break; - case 'i': - ctl.device = optarg; - break; - case 'v': - ctl.verbose = 1; - break; - case 'w': - ctl.waittime = atoi(optarg); - if (ctl.waittime <= 1) { - fprintf(stderr, "traceroute: wait must be >1 sec.\n"); - exit(1); - } - break; - case 'V': - printf(IPUTILS_VERSION("traceroute6")); - exit(0); - default: - usage(); - } - } - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) - usage(); - - setlinebuf(stdout); - - memset((char *)&ctl.whereto, 0, sizeof(ctl.whereto)); - - to->sin6_family = AF_INET6; - - if (inet_pton(AF_INET6, *argv, &to->sin6_addr) > 0) { - ctl.hostname = *argv; - } else { - status = getaddrinfo(*argv, NULL, &hints6, &result); - if (status) { - fprintf(stderr, "traceroute: %s: %s\n", *argv, gai_strerror(status)); - exit(1); - } - - memcpy(to, result->ai_addr, sizeof *to); - resolved_hostname = strdup(result->ai_canonname); - if (resolved_hostname == NULL) { - fprintf(stderr, "traceroute: cannot allocate memory\n"); - exit(1); - } - ctl.hostname = resolved_hostname; - freeaddrinfo(result); - } - - to->sin6_port = htons(ctl.port); - - ctl.firsthop = *to; - if (*++argv) { - ctl.datalen = atoi(*argv); - /* - * Message for rpm maintainers: have _shame_. If you want - * to fix something send the patch to me for sanity - * checking. "datalen" patch is a shit. - */ - if (ctl.datalen == 0) - ctl.datalen = sizeof(struct pkt_format); - else if (ctl.datalen < (int)sizeof(struct pkt_format) || ctl.datalen >= MAXPACKET) { - fprintf(stderr, - "traceroute: packet size must be %d <= s < %d.\n", - (int)sizeof(struct pkt_format), MAXPACKET); - exit(1); - } - } - - ctl.ident = getpid(); - - ctl.sendbuff = malloc(ctl.datalen); - if (ctl.sendbuff == NULL) { - fprintf(stderr, "malloc failed\n"); - exit(1); - } - - if (ctl.icmp_sock < 0) { - errno = socket_errno; - perror("traceroute6: icmp socket"); - exit(1); - } -#ifdef IPV6_RECVPKTINFO - setsockopt(ctl.icmp_sock, SOL_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); - setsockopt(ctl.icmp_sock, SOL_IPV6, IPV6_2292PKTINFO, &on, sizeof(on)); -#else - setsockopt(ctl.icmp_sock, SOL_IPV6, IPV6_PKTINFO, &on, sizeof(on)); -#endif - - if (ctl.options & SO_DEBUG) - setsockopt(ctl.icmp_sock, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); - if (ctl.options & SO_DONTROUTE) - setsockopt(ctl.icmp_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); - -#ifdef __linux__ - on = 2; - if (setsockopt(ctl.icmp_sock, SOL_RAW, IPV6_CHECKSUM, &on, sizeof(on)) < 0) { - /* - * checksum should be enabled by default and setting this - * option might fail anyway. - */ - fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed - try to continue."); - } -#endif - - if ((ctl.sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - perror("traceroute: UDP socket"); - exit(5); - } -#ifdef SO_SNDBUF - if (setsockopt(ctl.sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&ctl.datalen, - sizeof(ctl.datalen)) < 0) { - perror("traceroute: SO_SNDBUF"); - exit(6); - } -#endif /* SO_SNDBUF */ - - if (ctl.options & SO_DEBUG) - setsockopt(ctl.sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); - if (ctl.options & SO_DONTROUTE) - setsockopt(ctl.sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); - - if (ctl.source == NULL) { - socklen_t alen; - int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0); - - if (probe_fd < 0) { - perror("socket"); - exit(1); - } - if (ctl.device) { - if (setsockopt - (probe_fd, SOL_SOCKET, SO_BINDTODEVICE, ctl.device, - strlen(ctl.device) + 1) == -1) - perror("WARNING: interface is ignored"); - } - ctl.firsthop.sin6_port = htons(get_ip_unprivileged_port_start(1025)); - if (connect(probe_fd, (struct sockaddr *)&ctl.firsthop, - sizeof(ctl.firsthop)) == -1) { - perror("connect"); - exit(1); - } - alen = sizeof(ctl.saddr); - if (getsockname(probe_fd, (struct sockaddr *)&ctl.saddr, &alen) == -1) { - perror("getsockname"); - exit(1); - } - ctl.saddr.sin6_port = 0; - close(probe_fd); - } else { - memset((char *)&ctl.saddr, 0, sizeof(ctl.saddr)); - ctl.saddr.sin6_family = AF_INET6; - if (inet_pton(AF_INET6, ctl.source, &ctl.saddr.sin6_addr) <= 0) { - printf("traceroute: unknown addr %s\n", ctl.source); - exit(1); - } - } - - if (bind(ctl.sndsock, (struct sockaddr *)&ctl.saddr, sizeof(ctl.saddr)) < 0) { - perror("traceroute: bind sending socket"); - exit(1); - } - if (bind(ctl.icmp_sock, (struct sockaddr *)&ctl.saddr, sizeof(ctl.saddr)) < 0) { - perror("traceroute: bind icmp6 socket"); - exit(1); - } - - fprintf(stderr, "traceroute to %s (%s)", ctl.hostname, - inet_ntop(AF_INET6, &to->sin6_addr, pa, sizeof(pa))); - - fprintf(stderr, " from %s", inet_ntop(AF_INET6, &ctl.saddr.sin6_addr, pa, sizeof(pa))); - fprintf(stderr, ", %d hops max, %d byte packets\n", ctl.max_ttl, ctl.datalen); - fflush(stderr); - - for (ttl = 1; ttl <= ctl.max_ttl; ++ttl) { - struct in6_addr lastaddr = { {{0,}} }; - uint8_t got_there = 0; - int unreachable = 0; - - printf("%2d ", ttl); - for (probe = 0; probe < ctl.nprobes; ++probe) { - ssize_t cc; - uint8_t reset_timer = 1; - struct timespec t1, t2; - struct in6_addr to_addr; - - clock_gettime(CLOCK_MONOTONIC_RAW, &t1); - send_probe(&ctl, ++seq, ttl); - while ((cc = wait_for_reply(&ctl, &from, &to_addr, reset_timer)) != 0) { - clock_gettime(CLOCK_MONOTONIC_RAW, &t2); - if ((i = packet_ok(&ctl, cc, &from, &to_addr, seq, &t1))) { - if (memcmp(&from.sin6_addr, &lastaddr, - sizeof(from.sin6_addr))) { - print(&ctl, &from); - memcpy(&lastaddr, - &from.sin6_addr, sizeof(lastaddr)); - } - printf(" %.4f ms", deltaT(&t1, &t2)); - switch (i - 1) { - case ICMP6_DST_UNREACH_NOPORT: - got_there = 1; - break; - - case ICMP6_DST_UNREACH_NOROUTE: - ++unreachable; - printf(" !N"); - break; - case ICMP6_DST_UNREACH_ADDR: - ++unreachable; - printf(" !H"); - break; - - case ICMP6_DST_UNREACH_ADMIN: - ++unreachable; - printf(" !X"); - break; - } - break; - } else - reset_timer = 0; - } - if (cc <= 0) - printf(" *"); - fflush(stdout); - } - putchar('\n'); - if (got_there || (unreachable > 0 && unreachable >= ctl.nprobes - 1)) - break; - } - free(resolved_hostname); - return 0; -} - -int traceroute6_util(const char *addr, int *hops, int *time_usec) -{ - int type = 4; // 4 or 6 - int total_hops = 0; - long int total_time_usec = 0; // latency in microseconds - int argc = 4; - const char *argv[argc]; - if(type != 4) - argv[0] = "raceroute6"; - else - argv[0] = "raceroute4"; - argv[1] = "-v"; // print both name and ip - argv[2] = "-v"; // -n -m 16 - argv[3] = addr; - int ret = traceroute6_main(argc, (char**) argv); - return ret; -}