Annotation of embedaddon/mtr/mtr.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:     mtr  --  a network diagnostic tool
                      3:     Copyright (C) 1997,1998  Matt Kimball
                      4: 
                      5:     This program is free software; you can redistribute it and/or modify
                      6:     it under the terms of the GNU General Public License version 2 as
                      7:     published by the Free Software Foundation.
                      8: 
                      9:     This program is distributed in the hope that it will be useful,
                     10:     but WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     12:     GNU General Public License for more details.
                     13: 
                     14:     You should have received a copy of the GNU General Public License
                     15:     along with this program; if not, write to the Free Software
                     16:     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17: */
                     18: 
1.1.1.2   misho      19: #include "config.h"
                     20: 
1.1       misho      21: #include <sys/types.h>
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
                     25: #include <unistd.h>
                     26: #include <errno.h>
                     27: #include <string.h>
1.1.1.2   misho      28: #include <strings.h>
                     29: 
                     30: #include <netdb.h>
                     31: #include <netinet/in.h>
                     32: #include <sys/socket.h>
                     33: #include <time.h>
1.1       misho      34: #include <ctype.h>
                     35: #include <assert.h>
                     36: #include <fcntl.h>
                     37: #include <sys/stat.h>
                     38: 
                     39: #include "mtr.h"
                     40: #include "mtr-curses.h"
1.1.1.3 ! misho      41: #include <getopt.h>
1.1       misho      42: #include "display.h"
                     43: #include "dns.h"
                     44: #include "report.h"
                     45: #include "net.h"
                     46: #include "asn.h"
                     47: #include "version.h"
                     48: 
                     49: 
                     50: #ifdef ENABLE_IPV6
                     51: #define DEFAULT_AF AF_UNSPEC
                     52: #else
                     53: #define DEFAULT_AF AF_INET
                     54: #endif
                     55: 
                     56: 
                     57: #ifdef NO_HERROR
                     58: #define herror(str) fprintf(stderr, str ": error looking up \"%s\"\n", Hostname);
                     59: #endif
                     60: 
                     61: 
                     62: int   DisplayMode;
                     63: int   display_mode;
                     64: int   Interactive = 1;
                     65: int   PrintVersion = 0;
                     66: int   PrintHelp = 0;
                     67: int   MaxPing = 10;
                     68: int   ForceMaxPing = 0;
                     69: float WaitTime = 1.0;
                     70: char *Hostname = NULL;
                     71: char *InterfaceAddress = NULL;
                     72: char  LocalHostname[128];
                     73: int   dns = 1;
                     74: int   show_ips = 0;
                     75: int   enablempls = 0;
                     76: int   cpacketsize = 64;          /* default packet size */
                     77: int   bitpattern = 0;
                     78: int   tos = 0;
1.1.1.2   misho      79: #ifdef SO_MARK
                     80: int   mark = -1;
                     81: #endif
1.1       misho      82: int   reportwide = 0;
                     83: int af = DEFAULT_AF;
                     84: int mtrtype = IPPROTO_ICMP;     /* Use ICMP as default packet type */
                     85: 
                     86:                                 /* begin ttl windows addByMin */
                     87: int  fstTTL = 1;                /* default start at first hop */
                     88: /*int maxTTL = MaxHost-1;  */     /* max you can go is 255 hops */
                     89: int   maxTTL = 30;              /* inline with traceroute */
                     90:                                 /* end ttl window stuff. */
                     91: int remoteport = 80;            /* for TCP tracing */
                     92: int timeout = 10 * 1000000;     /* for TCP tracing */
                     93: 
                     94: 
                     95: /* default display field(defined by key in net.h) and order */
                     96: unsigned char fld_active[2*MAXFLD] = "LS NABWV";
                     97: int           fld_index[256];
                     98: char          available_options[MAXFLD];
                     99: 
                    100: 
                    101: struct fields data_fields[MAXFLD] = {
                    102:   /* key, Remark, Header, Format, Width, CallBackFunc */
                    103:   {' ', "<sp>: Space between fields", " ",  " ",        1, &net_drop  },
                    104:   {'L', "L: Loss Ratio",          "Loss%",  " %4.1f%%", 6, &net_loss  },
                    105:   {'D', "D: Dropped Packets",     "Drop",   " %4d",     5, &net_drop  },
                    106:   {'R', "R: Received Packets",    "Rcv",    " %5d",     6, &net_returned},
                    107:   {'S', "S: Sent Packets",        "Snt",    " %5d",     6, &net_xmit  },
                    108:   {'N', "N: Newest RTT(ms)",      "Last",   " %5.1f",   6, &net_last  },
                    109:   {'B', "B: Min/Best RTT(ms)",    "Best",   " %5.1f",   6, &net_best  },
                    110:   {'A', "A: Average RTT(ms)",     "Avg",    " %5.1f",   6, &net_avg   },
                    111:   {'W', "W: Max/Worst RTT(ms)",   "Wrst",   " %5.1f",   6, &net_worst },
                    112:   {'V', "V: Standard Deviation",  "StDev",  " %5.1f",   6, &net_stdev },
                    113:   {'G', "G: Geometric Mean",      "Gmean",  " %5.1f",   6, &net_gmean },
                    114:   {'J', "J: Current Jitter",      "Jttr",   " %4.1f",   5, &net_jitter},
                    115:   {'M', "M: Jitter Mean/Avg.",    "Javg",   " %4.1f",   5, &net_javg  },
                    116:   {'X', "X: Worst Jitter",        "Jmax",   " %4.1f",   5, &net_jworst},
                    117:   {'I', "I: Interarrival Jitter", "Jint",   " %4.1f",   5, &net_jinta },
                    118:   {'\0', NULL, NULL, NULL, 0, NULL}
                    119: };
                    120: 
                    121: typedef struct names {
                    122:   char*                 name;
                    123:   struct names*         next;
                    124: } names_t;
                    125: static names_t *names = NULL;
                    126: 
                    127: char *
                    128: trim(char * s) {
                    129: 
                    130:   char * p = s;
                    131:   int l = strlen(p);
                    132: 
                    133:   while(isspace(p[l-1]) && l) p[--l] = 0;
                    134:   while(*p && isspace(*p) && l) ++p, --l;
                    135: 
                    136:   return p;
                    137: }
                    138: 
                    139: static void
                    140: append_to_names(const char* progname, const char* item) {
                    141: 
                    142:   names_t* name = calloc(1, sizeof(names_t));
                    143:   if (name == NULL) {
                    144:     fprintf(stderr, "%s: memory allocation failure\n", progname);
                    145:     exit(EXIT_FAILURE);
                    146:   }
                    147:   name->name = strdup(item);
                    148:   name->next = names;
                    149:   names = name;
                    150: }
                    151: 
                    152: static void
                    153: read_from_file(const char* progname, const char *filename) {
                    154: 
                    155:   FILE *in;
                    156:   char line[512];
                    157: 
                    158:   if (! filename || strcmp(filename, "-") == 0) {
                    159:     clearerr(stdin);
                    160:     in = stdin;
                    161:   } else {
                    162:     in = fopen(filename, "r");
                    163:     if (! in) {
                    164:       fprintf(stderr, "%s: fopen: %s\n", progname, strerror(errno));
                    165:       exit(EXIT_FAILURE);
                    166:     }
                    167:   }
                    168: 
                    169:   while (fgets(line, sizeof(line), in)) {
                    170:     char* name = trim(line);
                    171:     append_to_names(progname, name);
                    172:   }
                    173: 
                    174:   if (ferror(in)) {
                    175:     fprintf(stderr, "%s: ferror: %s\n", progname, strerror(errno));
                    176:     exit(EXIT_FAILURE);
                    177:   }
                    178: 
                    179:   if (in != stdin) fclose(in);
                    180: }
                    181: 
                    182: /*
                    183:  * If the file stream is associated with a regular file, lock the file
                    184:  * in order coordinate writes to a common file from multiple mtr
                    185:  * instances. This is useful if, for example, multiple mtr instances
                    186:  * try to append results to a common file.
                    187:  */
                    188: 
                    189: static void
                    190: lock(const char* progname, FILE *f) {
                    191:     int fd;
                    192:     struct stat buf;
                    193:     static struct flock lock;
                    194: 
                    195:     assert(f);
                    196: 
                    197:     lock.l_type = F_WRLCK;
                    198:     lock.l_start = 0;
                    199:     lock.l_whence = SEEK_END;
                    200:     lock.l_len = 0;
                    201:     lock.l_pid = getpid();
                    202: 
                    203:     fd = fileno(f);
                    204:     if ((fstat(fd, &buf) == 0) && S_ISREG(buf.st_mode)) {
                    205:       if (fcntl(fd, F_SETLKW, &lock) == -1) {
                    206:           fprintf(stderr, "%s: fcntl: %s (ignored)\n",
                    207:             progname, strerror(errno));
                    208:       }
                    209:     }
                    210: }
                    211: 
                    212: /*
                    213:  * If the file stream is associated with a regular file, unlock the
                    214:  * file (which presumably has previously been locked).
                    215:  */
                    216: 
                    217: static void
                    218: unlock(const char* progname, FILE *f) {
                    219:     int fd;
                    220:     struct stat buf;
                    221:     static struct flock lock;
                    222: 
                    223:     assert(f);
                    224: 
                    225:     lock.l_type = F_UNLCK;
                    226:     lock.l_start = 0;
                    227:     lock.l_whence = SEEK_END;
                    228:     lock.l_len = 0;
                    229:     lock.l_pid = getpid();
                    230: 
                    231:     fd = fileno(f);
                    232:     if ((fstat(fd, &buf) == 0) && S_ISREG(buf.st_mode)) {
                    233:       if (fcntl(fd, F_SETLKW, &lock) == -1) {
                    234:           fprintf(stderr, "%s: fcntl: %s (ignored)\n",
                    235:             progname, strerror(errno));
                    236:       }
                    237:     }
                    238: }
                    239: 
                    240: 
                    241: void init_fld_options (void)
                    242: {
                    243:   int i;
                    244: 
                    245:   for (i=0;i < 256;i++)
                    246:     fld_index[i] = -1;
                    247: 
                    248:   for (i=0;data_fields[i].key != 0;i++) {
                    249:     available_options[i] = data_fields[i].key;
                    250:     fld_index[data_fields[i].key] = i;
                    251:   }
                    252:   available_options[i] = 0;
                    253: }
                    254: 
                    255: 
                    256: void parse_arg (int argc, char **argv)
                    257: {
                    258:   int opt;
                    259:   int i;
1.1.1.2   misho     260:   /* IMPORTANT: when adding or modifying an option:
                    261:        1/ mind the order of options, there is some logic;
                    262:        2/ update the getopt_long call below;
                    263:        3/ update the man page (use the same order);
                    264:        4/ update the help message showed when using --help.
                    265:    */
1.1       misho     266:   static struct option long_options[] = {
                    267:     { "help", 0, 0, 'h' },
1.1.1.2   misho     268:     { "version", 0, 0, 'v' },
                    269: 
                    270:     { "inet", 0, 0, '4' },     /* IPv4 only */
                    271:     { "inet6", 0, 0, '6' },    /* IPv6 only */
                    272: 
                    273:     { "filename", 1, 0, 'F' },
1.1       misho     274: 
                    275:     { "report", 0, 0, 'r' },
                    276:     { "report-wide", 0, 0, 'w' },
                    277:     { "xml", 0, 0, 'x' },
                    278:     { "curses", 0, 0, 't' },
                    279:     { "gtk", 0, 0, 'g' },
                    280:     { "raw", 0, 0, 'l' },
                    281:     { "csv", 0, 0, 'C' },
                    282:     { "split", 0, 0, 'p' },     /* BL */
                    283:                                /* maybe above should change to -d 'x' */
                    284: 
1.1.1.2   misho     285:     { "no-dns", 0, 0, 'n' },
                    286:     { "show-ips", 0, 0, 'b' },
                    287:     { "order", 1, 0, 'o' },    /* fields to display & their order */
                    288: #ifdef IPINFO
                    289:     { "ipinfo", 1, 0, 'y' },    /* IP info lookup */
                    290:     { "aslookup", 0, 0, 'z' },  /* Do AS lookup (--ipinfo 0) */
                    291: #endif
1.1       misho     292: 
                    293:     { "interval", 1, 0, 'i' },
                    294:     { "report-cycles", 1, 0, 'c' },
                    295:     { "psize", 1, 0, 's' },    /* changed 'p' to 's' to match ping option
                    296:                                   overload psize<0, ->rand(min,max) */
                    297:     { "bitpattern", 1, 0, 'B' },/* overload b>255, ->rand(0,255) */
                    298:     { "tos", 1, 0, 'Q' },      /* typeof service (0,255) */
                    299:     { "mpls", 0, 0, 'e' },
                    300:     { "address", 1, 0, 'a' },
                    301:     { "first-ttl", 1, 0, 'f' },        /* -f & -m are borrowed from traceroute */
                    302:     { "max-ttl", 1, 0, 'm' },
                    303:     { "udp", 0, 0, 'u' },      /* UDP (default is ICMP) */
                    304:     { "tcp", 0, 0, 'T' },      /* TCP (default is ICMP) */
                    305:     { "port", 1, 0, 'P' },      /* target port number for TCP */
                    306:     { "timeout", 1, 0, 'Z' },   /* timeout for TCP sockets */
1.1.1.2   misho     307: #ifdef SO_MARK
                    308:     { "mark", 1, 0, 'M' },      /* use SO_MARK */
1.1       misho     309: #endif
                    310:     { 0, 0, 0, 0 }
                    311:   };
                    312: 
                    313:   opt = 0;
                    314:   while(1) {
                    315:     opt = getopt_long(argc, argv,
1.1.1.2   misho     316:                      "hv46F:rwxtglCpnbo:y:zi:c:s:B:Q:ea:f:m:uTP:Z:M:", long_options, NULL);
1.1       misho     317:     if(opt == -1)
                    318:       break;
                    319: 
                    320:     switch(opt) {
                    321:     case 'v':
                    322:       PrintVersion = 1;
                    323:       break;
                    324:     case 'h':
                    325:       PrintHelp = 1;
                    326:       break;
                    327: 
                    328:     case 'r':
                    329:       DisplayMode = DisplayReport;
                    330:       break;
                    331:     case 'w':
                    332:       reportwide = 1;
                    333:       DisplayMode = DisplayReport;
                    334:       break;
                    335:     case 't':
                    336:       DisplayMode = DisplayCurses;
                    337:       break;
                    338:     case 'g':
                    339:       DisplayMode = DisplayGTK;
                    340:       break;
                    341:     case 'p':                 /* BL */
                    342:       DisplayMode = DisplaySplit;
                    343:       break;
                    344:     case 'l':
                    345:       DisplayMode = DisplayRaw;
                    346:       break;
                    347:     case 'C':
                    348:       DisplayMode = DisplayCSV;
                    349:       break;
                    350:     case 'x':
                    351:       DisplayMode = DisplayXML;
                    352:       break;
                    353: 
                    354:     case 'c':
                    355:       MaxPing = atoi (optarg);
                    356:       ForceMaxPing = 1;
                    357:       break;
                    358:     case 's':
                    359:       cpacketsize = atoi (optarg);
                    360:       break;
                    361:     case 'a':
                    362:       InterfaceAddress = optarg;
                    363:       break;
                    364:     case 'e':
                    365:       enablempls = 1;
                    366:       break;
                    367:     case 'n':
                    368:       dns = 0;
                    369:       break;
                    370:     case 'i':
                    371:       WaitTime = atof (optarg);
                    372:       if (WaitTime <= 0.0) {
                    373:        fprintf (stderr, "mtr: wait time must be positive\n");
                    374:        exit (1);
                    375:       }
                    376:       if (getuid() != 0 && WaitTime < 1.0) {
                    377:         fprintf (stderr, "non-root users cannot request an interval < 1.0 seconds\r\n");
                    378:        exit (1);
                    379:       }
                    380:       break;
                    381:     case 'f':
                    382:       fstTTL = atoi (optarg);
                    383:       if (fstTTL > maxTTL) {
                    384:        fstTTL = maxTTL;
                    385:       }
                    386:       if (fstTTL < 1) {                       /* prevent 0 hop */
                    387:        fstTTL = 1;
                    388:       }
                    389:       break;
                    390:     case 'F':
                    391:       read_from_file(argv[0], optarg);
                    392:       break;
                    393:     case 'm':
                    394:       maxTTL = atoi (optarg);
                    395:       if (maxTTL > (MaxHost - 1)) {
                    396:        maxTTL = MaxHost-1;
                    397:       }
                    398:       if (maxTTL < 1) {                       /* prevent 0 hop */
                    399:        maxTTL = 1;
                    400:       }
                    401:       if (fstTTL > maxTTL) {         /* don't know the pos of -m or -f */
                    402:        fstTTL = maxTTL;
                    403:       }
                    404:       break;
                    405:     case 'o':
                    406:       /* Check option before passing it on to fld_active. */
                    407:       if (strlen (optarg) > MAXFLD) {
                    408:        fprintf (stderr, "Too many fields: %s\n", optarg);
                    409:         exit (1);
                    410:       }
                    411:       for (i=0; optarg[i]; i++) {
                    412:         if(!strchr (available_options, optarg[i])) {
                    413:           fprintf (stderr, "Unknown field identifier: %c\n", optarg[i]);
                    414:           exit (1);
                    415:         }
                    416:       }
                    417:       strcpy ((char*)fld_active, optarg);
                    418:       break;
                    419:     case 'B':
                    420:       bitpattern = atoi (optarg);
                    421:       if (bitpattern > 255)
                    422:        bitpattern = -1;
                    423:       break;
                    424:     case 'Q':
                    425:       tos = atoi (optarg);
                    426:       if (tos > 255 || tos < 0) {
                    427:        /* error message, should do more checking for valid values,
                    428:         * details in rfc2474 */
                    429:        tos = 0;
                    430:       }
                    431:       break;
                    432:     case 'u':
                    433:       if (mtrtype != IPPROTO_ICMP) {
                    434:         fprintf(stderr, "-u and -T are mutually exclusive.\n");
                    435:         exit(EXIT_FAILURE);
                    436:       }
                    437:       mtrtype = IPPROTO_UDP;
                    438:       break;
                    439:     case 'T':
                    440:       if (mtrtype != IPPROTO_ICMP) {
                    441:         fprintf(stderr, "-u and -T are mutually exclusive.\n");
                    442:         exit(EXIT_FAILURE);
                    443:       }
                    444:       mtrtype = IPPROTO_TCP;
                    445:       break;
                    446:     case 'b':
                    447:       show_ips = 1;
                    448:       break;
                    449:     case 'P':
                    450:       remoteport = atoi(optarg);
                    451:       if (remoteport > 65535 || remoteport < 1) {
                    452:         fprintf(stderr, "Illegal port number.\n");
                    453:         exit(EXIT_FAILURE);
                    454:       }
                    455:       break;
                    456:     case 'Z':
                    457:       timeout = atoi(optarg);
                    458:       timeout *= 1000000;
                    459:       break;
                    460:     case '4':
                    461:       af = AF_INET;
                    462:       break;
                    463:     case '6':
                    464: #ifdef ENABLE_IPV6
                    465:       af = AF_INET6;
                    466:       break;
                    467: #else
                    468:       fprintf( stderr, "IPv6 not enabled.\n" );
                    469:       break;
                    470: #endif
1.1.1.2   misho     471: #ifdef IPINFO
1.1       misho     472:     case 'y':
                    473:       ipinfo_no = atoi (optarg);
                    474:       if (ipinfo_no < 0)
                    475:         ipinfo_no = 0;
                    476:       break;
                    477:     case 'z':
                    478:       ipinfo_no = 0;
                    479:       break;
1.1.1.2   misho     480: #else
                    481:     case 'y':
                    482:     case 'z':
                    483:       fprintf( stderr, "IPINFO not enabled.\n" );
                    484:       break;
                    485: #endif
                    486: #ifdef SO_MARK
                    487:     case 'M':
                    488:       mark = atoi (optarg);
                    489:       if (mark < 0) {
                    490:         fprintf( stderr, "SO_MARK must be positive.\n" );
                    491:         exit(EXIT_FAILURE);
                    492:       }
                    493:       break;
                    494: #else
                    495:     case 'M':
                    496:       fprintf( stderr, "SO_MARK not enabled.\n" );
                    497:       break;
1.1       misho     498: #endif
                    499:     }
                    500:   }
                    501: 
                    502:   if (DisplayMode == DisplayReport ||
                    503:       DisplayMode == DisplayTXT ||
                    504:       DisplayMode == DisplayXML ||
                    505:       DisplayMode == DisplayRaw ||
                    506:       DisplayMode == DisplayCSV)
                    507:     Interactive = 0;
                    508: 
                    509:   if (optind > argc - 1)
                    510:     return;
                    511: 
                    512: }
                    513: 
                    514: 
                    515: void parse_mtr_options (char *string)
                    516: {
                    517:   int argc;
                    518:   char *argv[128], *p;
                    519: 
                    520:   if (!string) return;
                    521: 
                    522:   argv[0] = "mtr";
                    523:   argc = 1;
                    524:   p = strtok (string, " \t");
                    525:   while (p != NULL && ((size_t) argc < (sizeof(argv)/sizeof(argv[0])))) {
                    526:     argv[argc++] = p;
                    527:     p = strtok (NULL, " \t");
                    528:   }
                    529:   if (p != NULL) {
                    530:     fprintf (stderr, "Warning: extra arguments ignored: %s", p);
                    531:   }
                    532: 
                    533:   parse_arg (argc, argv);
                    534:   optind = 0;
                    535: }
                    536: 
                    537: 
                    538: int main(int argc, char **argv)
                    539: {
                    540:   struct hostent *  host                = NULL;
                    541:   int               net_preopen_result;
                    542: #ifdef ENABLE_IPV6
                    543:   struct addrinfo       hints, *res;
                    544:   int                   error;
                    545:   struct hostent        trhost;
                    546:   char *                alptr[2];
                    547:   struct sockaddr_in *  sa4;
                    548:   struct sockaddr_in6 * sa6;
                    549: #endif
                    550: 
                    551:   /*  Get the raw sockets first thing, so we can drop to user euid immediately  */
                    552: 
                    553:   if ( ( net_preopen_result = net_preopen () ) ) {
                    554:     fprintf( stderr, "mtr: unable to get raw sockets.\n" );
                    555:     exit( EXIT_FAILURE );
                    556:   }
                    557: 
                    558:   /*  Now drop to user permissions  */
                    559:   if (setgid(getgid()) || setuid(getuid())) {
                    560:     fprintf (stderr, "mtr: Unable to drop permissions.\n");
                    561:     exit(1);
                    562:   }
                    563: 
                    564:   /*  Double check, just in case  */
                    565:   if ((geteuid() != getuid()) || (getegid() != getgid())) {
                    566:     fprintf (stderr, "mtr: Unable to drop permissions.\n");
                    567:     exit(1);
                    568:   }
                    569: 
                    570:   /* reset the random seed */
                    571:   srand (getpid());
                    572: 
                    573:   display_detect(&argc, &argv);
                    574: 
                    575:   /* The field options are now in a static array all together,
                    576:      but that requires a run-time initialization. */
                    577:   init_fld_options ();
                    578: 
                    579:   parse_mtr_options (getenv ("MTR_OPTIONS"));
                    580: 
                    581:   parse_arg (argc, argv);
                    582: 
                    583:   while (optind < argc) {
                    584:     char* name = argv[optind++];
                    585:     append_to_names(argv[0], name);
                    586:   }
                    587: 
                    588:   /* Now that we know mtrtype we can select which socket to use */
                    589:   if (net_selectsocket() != 0) {
                    590:     fprintf( stderr, "mtr: Couldn't determine raw socket type.\n" );
                    591:     exit( EXIT_FAILURE );
                    592:   }
                    593: 
                    594:   if (PrintVersion) {
                    595:     printf ("mtr " MTR_VERSION "\n");
                    596:     exit(0);
                    597:   }
                    598: 
                    599:   if (PrintHelp) {
1.1.1.2   misho     600:        printf("usage: %s [--help] [--version] [-4|-6] [-F FILENAME]\n"
                    601:               "\t\t[--report] [--report-wide]\n"
                    602:               "\t\t[--xml] [--gtk] [--curses] [--raw] [--csv] [--split]\n"
                    603:               "\t\t[--no-dns] [--show-ips] [-o FIELDS] [-y IPINFO] [--aslookup]\n"
                    604:               "\t\t[-i INTERVAL] [-c COUNT] [-s PACKETSIZE] [-B BITPATTERN]\n"
                    605:               "\t\t[-Q TOS] [--mpls]\n"
                    606:               "\t\t[-a ADDRESS] [-f FIRST-TTL] [-m MAX-TTL]\n"
                    607:               "\t\t[--udp] [--tcp] [-P PORT] [-Z TIMEOUT]\n"
                    608:               "\t\t[-M MARK] HOSTNAME\n", argv[0]);
                    609:        printf("See the man page for details.\n");
1.1       misho     610:     exit(0);
                    611:   }
                    612: 
                    613:   time_t now = time(NULL);
1.1.1.2   misho     614: 
                    615:   if (!names) append_to_names (argv[0], "localhost"); // default: localhost. 
                    616: 
1.1       misho     617:   names_t* head = names;
                    618:   while (names != NULL) {
                    619: 
                    620:     Hostname = names->name;
1.1.1.2   misho     621:     //  if (Hostname == NULL) Hostname = "localhost"; // no longer necessary.
1.1       misho     622:     if (gethostname(LocalHostname, sizeof(LocalHostname))) {
1.1.1.2   misho     623:       strcpy(LocalHostname, "UNKNOWNHOST");
1.1       misho     624:     }
                    625: 
                    626:     if (net_preopen_result != 0) {
                    627:       fprintf(stderr, "mtr: Unable to get raw socket.  (Executable not suid?)\n");
                    628:       if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
                    629:       else {
                    630:         names = names->next;
                    631:         continue;
                    632:       }
                    633:     }
                    634: 
                    635: #ifdef ENABLE_IPV6
                    636:     /* gethostbyname2() is deprecated so we'll use getaddrinfo() instead. */
                    637:     bzero( &hints, sizeof hints );
                    638:     hints.ai_family = af;
                    639:     hints.ai_socktype = SOCK_DGRAM;
                    640:     error = getaddrinfo( Hostname, NULL, &hints, &res );
                    641:     if ( error ) {
                    642:       if (error == EAI_SYSTEM)
                    643:          perror ("Failed to resolve host");
                    644:       else
                    645:          fprintf (stderr, "Failed to resolve host: %s\n", gai_strerror(error));
                    646: 
                    647:       if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
                    648:       else {
                    649:         names = names->next;
                    650:         continue;
                    651:       }
                    652:     }
                    653:     /* Convert the first addrinfo into a hostent. */
                    654:     host = &trhost;
                    655:     bzero( host, sizeof trhost );
                    656:     host->h_name = res->ai_canonname;
                    657:     host->h_aliases = NULL;
                    658:     host->h_addrtype = res->ai_family;
                    659:     af = res->ai_family;
                    660:     host->h_length = res->ai_addrlen;
                    661:     host->h_addr_list = alptr;
                    662:     switch ( af ) {
                    663:     case AF_INET:
                    664:       sa4 = (struct sockaddr_in *) res->ai_addr;
                    665:       alptr[0] = (void *) &(sa4->sin_addr);
                    666:       break;
                    667:     case AF_INET6:
                    668:       sa6 = (struct sockaddr_in6 *) res->ai_addr;
                    669:       alptr[0] = (void *) &(sa6->sin6_addr);
                    670:       break;
                    671:     default:
                    672:       fprintf( stderr, "mtr unknown address type\n" );
                    673:       if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
                    674:       else {
                    675:         names = names->next;
                    676:         continue;
                    677:       }
                    678:     }
                    679:     alptr[1] = NULL;
                    680: #else
                    681:       host = gethostbyname(Hostname);
                    682:     if (host == NULL) {
                    683:       herror("mtr gethostbyname");
                    684:       if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
                    685:       else {
                    686:         names = names->next;
                    687:         continue;
                    688:       }
                    689:     }
                    690:     af = host->h_addrtype;
                    691: #endif
                    692: 
                    693:     if (net_open(host) != 0) {
                    694:       fprintf(stderr, "mtr: Unable to start net module.\n");
                    695:       if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
                    696:       else {
                    697:         names = names->next;
                    698:         continue;
                    699:       }
                    700:     }
                    701: 
                    702:     if (net_set_interfaceaddress (InterfaceAddress) != 0) {
                    703:       fprintf( stderr, "mtr: Couldn't set interface address.\n" );
                    704:       if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
                    705:       else {
                    706:         names = names->next;
                    707:         continue;
                    708:       }
                    709:     }
                    710: 
                    711:     lock(argv[0], stdout);
                    712:       display_open();
                    713:       dns_open();
                    714: 
                    715:       display_mode = 0;
                    716:       display_loop();
                    717: 
                    718:       net_end_transit();
                    719:       display_close(now);
                    720:     unlock(argv[0], stdout);
                    721: 
                    722:     if ( DisplayMode != DisplayCSV ) break;
                    723:     else names = names->next;
                    724: 
                    725:   }
                    726: 
                    727:   net_close();
                    728: 
                    729:   while (head != NULL) {
                    730:     names_t* item = head;
                    731:     free(item->name); item->name = NULL;
                    732:     head = head->next;
                    733:     free(item); item = NULL;
                    734:   }
                    735:   head=NULL;
                    736: 
                    737:   return 0;
                    738: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>