home *** CD-ROM | disk | FTP | other *** search
/ ftp.shrubbery.net / 2015-02-07.ftp.shrubbery.net.tar / ftp.shrubbery.net / pub / astraceroute / astraceroute-1.4.a12.2.tar.gz / astraceroute-1.4.a12.2.tar / astraceroute-1.4.a12.2 / findsaddr-mib.c < prev    next >
C/C++ Source or Header  |  2007-01-24  |  9KB  |  379 lines

  1. /*
  2.  * Copyright (c) 2000
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the Computer Systems
  16.  *    Engineering Group at Lawrence Berkeley Laboratory.
  17.  * 4. Neither the name of the University nor of the Laboratory may be used
  18.  *    to endorse or promote products derived from this software without
  19.  *    specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. /* Seriously complex Solaris mib2 code */
  35.  
  36. #ifndef lint
  37. static const char rcsid[] =
  38.     "@(#) $Id: findsaddr-mib.c,v 1.1.1.1 2007/01/25 03:32:19 heas Exp $ (LBL)";
  39. #endif
  40.  
  41. #include <sys/param.h>
  42. #include <sys/file.h>
  43. #include <sys/ioctl.h>
  44. #include <sys/socket.h>
  45. #ifdef HAVE_SYS_SOCKIO_H
  46. #include <sys/sockio.h>
  47. #endif
  48. #include <sys/time.h>                /* concession to AIX */
  49. #include <sys/stream.h>
  50. #include <sys/tihdr.h>
  51. #include <sys/tiuser.h>
  52.  
  53. #if __STDC__
  54. struct mbuf;
  55. struct rtentry;
  56. #endif
  57.  
  58. #include <net/if.h>
  59. #include <net/route.h>
  60.  
  61. #include <netinet/in.h>
  62.  
  63. #include <inet/common.h>
  64. #include <inet/mib2.h>
  65. #include <inet/ip.h>
  66. #include <inet/arp.h>
  67.  
  68. #include <arpa/inet.h>
  69.  
  70. #include <errno.h>
  71. #include <fcntl.h>
  72. #ifdef HAVE_MALLOC_H
  73. #include <malloc.h>
  74. #endif
  75. #include <stdio.h>
  76. #include <stdlib.h>
  77. #include <string.h>
  78. #include <stropts.h>
  79. #include <unistd.h>
  80.  
  81. #include "gnuc.h"
  82. #ifdef HAVE_OS_PROTO_H
  83. #include "os-proto.h"
  84. #endif
  85.  
  86. #include "findsaddr.h"
  87.  
  88. /* Compatibility with older versions of Solaris */
  89. #ifndef IRE_CACHE
  90. #define IRE_CACHE IRE_ROUTE
  91. #endif
  92.  
  93. #ifndef T_CURRENT
  94. #define T_CURRENT MI_T_CURRENT
  95. #endif
  96.  
  97. struct routelist {
  98.     struct routelist *next;
  99.     u_int32_t dest;
  100.     u_int32_t mask;
  101.     u_int32_t gate;
  102.     char ifname[64];
  103. };
  104.  
  105. /* Forwards */
  106. static struct routelist *getroutelist(char *);
  107. static void freeroutelist(struct routelist *);
  108.  
  109. /*
  110.  * Return the source address for the given destination address
  111.  *
  112.  * Since solaris doesn't report the interface associated with every
  113.  * route, we have to make two passes over the routing table.  The
  114.  * first pass should yield a host, net, default or interface route.
  115.  * If we find an interface route we're done. If not, we need to
  116.  * make a second pass to find the interface route for the gateway
  117.  * in the host, net, default route we found in the first pass.
  118.  *
  119.  * So instead of making a single pass through the tables as they
  120.  * are retrieved from the kernel, we must build a linked list...
  121.  */
  122. const char *
  123. findsaddr(register const struct sockaddr_in *to,
  124.     register struct sockaddr_in *from)
  125. {
  126.     register struct routelist *rl, *rl2, *routelist;
  127.     static char errbuf[512];
  128.     u_int32_t mask, gate;
  129.  
  130.     /* Get the routing table */
  131.     routelist = getroutelist(errbuf);
  132.     if (routelist == NULL)
  133.         return (errbuf);
  134.  
  135.     /* First pass; look for a route that matches */
  136.     mask = 0;
  137.     rl2 = NULL;
  138.     for (rl = routelist; rl != NULL; rl = rl->next) {
  139.         if ((to->sin_addr.s_addr & rl->mask) == rl->dest &&
  140.             (rl->mask > mask || mask == 0) &&
  141.             rl->gate != 0) {
  142.             mask = rl->mask;
  143.             rl2 = rl;
  144.         }
  145.     }
  146.     if (rl2 == NULL) {
  147.         freeroutelist(routelist);
  148.         sprintf(errbuf, "%s: %.128s",
  149.             inet_ntoa(to->sin_addr), strerror(EHOSTUNREACH));
  150.         return (errbuf);
  151.     }
  152.  
  153.     /* We're done if we got one with an interface */
  154.     if (rl2->ifname[0] != '\0') {
  155.         freeroutelist(routelist);
  156.         from->sin_addr.s_addr = rl2->gate;
  157.         return (NULL);
  158.     }
  159.  
  160.     /* First pass; look for a route that matches the gateway we found */
  161.     mask = 0;
  162.     gate = rl2->gate;
  163.     rl2 = NULL;
  164.     for (rl = routelist; rl != NULL; rl = rl->next) {
  165.         if ((gate & rl->mask) == rl->dest &&
  166.             (rl->mask > mask || mask == 0) &&
  167.             rl->gate != 0 &&
  168.             rl->ifname[0] != '\0') {
  169.             mask = rl->mask;
  170.             rl2 = rl;
  171.         }
  172.     }
  173.     if (rl2 == NULL) {
  174.         freeroutelist(routelist);
  175.         sprintf(errbuf, "%s: %.128s (second pass)",
  176.             inet_ntoa(to->sin_addr), strerror(EHOSTUNREACH));
  177.         return (errbuf);
  178.     }
  179.  
  180.     from->sin_addr.s_addr = rl2->gate;
  181.     freeroutelist(routelist);
  182.     return (NULL);
  183. }
  184.  
  185. /* Request mib */
  186. struct mibrq {
  187.     struct T_optmgmt_req req;
  188.     struct opthdr hdr;
  189. };
  190.  
  191. /* Reply mib */
  192. struct mibrep {
  193.     struct T_optmgmt_ack ack;
  194.     struct opthdr hdr;
  195.     char buf[512];
  196. };
  197.  
  198. static struct mibrq mibrq = {
  199.     { T_OPTMGMT_REQ, sizeof(mibrq.hdr), sizeof(mibrq.req), T_CURRENT },
  200.     { MIB2_IP }
  201. };
  202.  
  203. static struct mibrep mibrep = {
  204.     { 0, 0, 0 },
  205.     { 0 },
  206.     { 0 }
  207. };
  208.  
  209. static struct strbuf rqbuf = {
  210.     0, sizeof(mibrq), (char *)&mibrq
  211. };
  212.  
  213. static struct strbuf repbuf = {
  214.     sizeof(mibrep.buf), sizeof(mibrep.ack) + sizeof(mibrep.hdr),
  215.         (char *)&mibrep
  216. };
  217.  
  218. static const char devip[] = "/dev/ip";
  219.  
  220. /*
  221.  * Construct the list of routes
  222.  */
  223. static struct routelist *
  224. getroutelist(char *errbuf)
  225. {
  226.     register int s, stat, i;
  227.     register char *cp;
  228.     register struct T_optmgmt_ack *ackp;
  229.     register struct T_error_ack *eackp;
  230.     register struct opthdr *hp;
  231.     register mib2_ipRouteEntry_t *rp, *rp2;
  232.     register struct routelist *rl, *rl2, *routelist;
  233.     int flags;
  234.     struct strbuf repbuf2;
  235.  
  236.     s = open(devip, O_RDWR, 0);
  237.     if (s < 0) {
  238.         sprintf(errbuf, "open %s: %.128s", devip, strerror(errno));
  239.         return (NULL);
  240.     }
  241.  
  242.     if ((cp = "arp", ioctl(s, I_PUSH, cp) < 0) ||
  243.         (cp = "tcp", ioctl(s, I_PUSH, cp) < 0) ||
  244.         (cp = "udp", ioctl(s, I_PUSH, cp) < 0)) {
  245.         sprintf(errbuf, "I_PUSH %s: %.128s", cp, strerror(errno));
  246.         close(s);
  247.         return (NULL);
  248.     }
  249.  
  250.     flags = 0;
  251.     if (putmsg(s, &rqbuf, NULL, flags) < 0) {
  252.         sprintf(errbuf, "putmsg: %.128s", strerror(errno));
  253.         close(s);
  254.         return (NULL);
  255.     }
  256.  
  257.     routelist= NULL;
  258.     rl2 = NULL;
  259.  
  260.     rp = NULL;
  261.  
  262.     ackp = &mibrep.ack;
  263.     hp = &mibrep.hdr;
  264.     eackp = (struct T_error_ack *)ackp;
  265.     for (;;) {
  266.         flags = 0;
  267.         memset(repbuf.buf, 0, repbuf.len);
  268.         stat = getmsg(s, &repbuf, NULL, &flags);
  269.         if (stat < 0) {
  270.             sprintf(errbuf, "getmsg: %.128s", strerror(errno));
  271.             goto bail;
  272.         }
  273.         if (stat == 0 && repbuf.len >= sizeof(*ackp) &&
  274.             ackp->PRIM_type == T_OPTMGMT_ACK &&
  275.             ackp->MGMT_flags == T_SUCCESS &&
  276.             hp->len == 0) {
  277.             /* All done! */
  278.             goto done;
  279.         }
  280.         if (repbuf.len >= sizeof(*eackp) &&
  281.             eackp->PRIM_type == T_ERROR_ACK) {
  282.             sprintf(errbuf, "getmsg err: %.128s",
  283.                 strerror((eackp->TLI_error == TSYSERR) ?
  284.                 eackp->UNIX_error : EPROTO));
  285.             goto bail;
  286.         }
  287.         if (stat != MOREDATA ||
  288.             repbuf.len < sizeof(*ackp) ||
  289.             ackp->PRIM_type != T_OPTMGMT_ACK ||
  290.             ackp->MGMT_flags != T_SUCCESS) {
  291.             strcpy(errbuf, "unknown getmsg err");
  292.             goto bail;
  293.         }
  294.  
  295.         memset(&repbuf2, 0, sizeof(repbuf2));
  296.         repbuf2.maxlen = hp->len;
  297.         rp = malloc(hp->len);
  298.         if (rp == NULL) {
  299.             sprintf(errbuf, "malloc: %.128s", strerror(errno));
  300.             goto bail;
  301.         }
  302.         repbuf2.buf = (char *)rp;
  303.  
  304.         flags = 0;
  305.         memset(repbuf2.buf, 0, repbuf2.len);
  306.         stat = getmsg(s, NULL, &repbuf2, &flags);
  307.         if (stat < 0) {
  308.             sprintf(errbuf, "getmsg2: %.128s", strerror(errno));
  309.             goto bail;
  310.         }
  311.  
  312.         /* Spin through the routes */
  313.         rp2 = rp;
  314.         for (rp2 = rp; (char *)rp2 < (char *)rp + repbuf2.len; ++rp2) {
  315.             if (hp->level != MIB2_IP || hp->name != MIB2_IP_21)
  316.                 continue;
  317.  
  318.             if (rp2->ipRouteInfo.re_ire_type == IRE_CACHE ||
  319.                 rp2->ipRouteInfo.re_ire_type == IRE_BROADCAST)
  320.                 continue;
  321.  
  322.             /* Got one we want to keep */
  323.             rl = malloc(sizeof(*rl));
  324.             if (rl == NULL) {
  325.                 sprintf(errbuf,
  326.                     "malloc 2: %.128s", strerror(errno));
  327.                 goto bail;
  328.             }
  329.             memset(rl, 0, sizeof(*rl));
  330.  
  331.             rl->mask = rp2->ipRouteMask;
  332.             rl->dest = rp2->ipRouteDest;
  333.             rl->gate = rp2->ipRouteNextHop;
  334.             if (rp2->ipRouteIfIndex.o_length > 0) {
  335.                 i = rp2->ipRouteIfIndex.o_length;
  336.                 if (i > sizeof(rl->ifname) - 1)
  337.                     i = sizeof(rl->ifname) - 1;
  338.                 strncpy(rl->ifname,
  339.                     rp2->ipRouteIfIndex.o_bytes, i);
  340.                 rl->ifname[i] = '\0';
  341.             }
  342.  
  343.             /* Keep in order (just for fun) */
  344.             if (routelist == NULL)
  345.                 routelist = rl;
  346.             if (rl2 != NULL)
  347.                 rl2->next = rl;
  348.             rl2 = rl;
  349.         }
  350.         free(rp);
  351.         rp = NULL;
  352.     }
  353.  
  354.     strcpy(errbuf, "failed!");
  355.  
  356. bail:
  357.     if (routelist != NULL) {
  358.         freeroutelist(routelist);
  359.         routelist = NULL;
  360.     }
  361. done:
  362.     if (rp != NULL)
  363.         free(rp);
  364.     close(s);
  365.     return (routelist);
  366. }
  367.  
  368. static void
  369. freeroutelist(register struct routelist *rl)
  370. {
  371.     register struct routelist *rl2;
  372.  
  373.     while (rl != NULL) {
  374.         rl2 = rl->next;
  375.         free(rl);
  376.         rl = rl2;
  377.     }
  378. }
  379.