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-socket.c < prev    next >
C/C++ Source or Header  |  2007-01-24  |  5KB  |  222 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. /* XXX Yes this is WAY too complicated */
  35.  
  36. #ifndef lint
  37. static const char rcsid[] =
  38.     "@(#) $Id: findsaddr-socket.c,v 1.2 2007/01/25 03:39:08 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.  
  50. #if __STDC__
  51. struct mbuf;
  52. struct rtentry;
  53. #endif
  54.  
  55. #include <net/if.h>
  56. #include <net/if_dl.h>
  57. #include <net/route.h>
  58. #include <netinet/in.h>
  59.  
  60. #include <errno.h>
  61. #include <stdio.h>
  62. #include <stdlib.h>
  63. #include <string.h>
  64. #include <unistd.h>
  65.  
  66. #include "gnuc.h"
  67. #ifdef HAVE_OS_PROTO_H
  68. #include "os-proto.h"
  69. #endif
  70.  
  71. #include "findsaddr.h"
  72.  
  73. #ifdef HAVE_SOCKADDR_SA_LEN
  74. #define SALEN(sa) ((sa)->sa_len)
  75. #else
  76. #define SALEN(sa) salen(sa)
  77. #endif
  78.  
  79. #ifndef roundup
  80. #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))  /* to any y */
  81. #endif
  82.  
  83. struct rtmsg {
  84.         struct rt_msghdr rtmsg;
  85.         u_char data[512];
  86. };
  87.  
  88. static struct rtmsg rtmsg = {
  89.     { 0, RTM_VERSION, RTM_GET, 0,
  90.     RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC,
  91.     RTA_DST | RTA_IFA, 0, 0, 0, 0, 0, { 0 } },
  92.     { 0 }
  93. };
  94.  
  95. #ifndef HAVE_SOCKADDR_SA_LEN
  96. static int salen(struct sockaddr *);
  97. #endif
  98.  
  99. /*
  100.  * Return the source address for the given destination address
  101.  */
  102. const char *
  103. findsaddr(register const struct sockaddr_in *to,
  104.     register struct sockaddr_in *from)
  105. {
  106.     register struct rt_msghdr *rp;
  107.     register u_char *cp;
  108.  
  109.     register struct sockaddr_in *sp, *ifa;
  110.     register struct sockaddr *sa;
  111.     register int s, size, cc, seq, i;
  112.     register pid_t pid;
  113.     static char errbuf[512];
  114.  
  115.     s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
  116.     if (s < 0) {
  117.         sprintf(errbuf, "socket: %.128s", strerror(errno));
  118.         return (errbuf);
  119.     }
  120.  
  121.     seq = 0;
  122.     pid = getpid();
  123.  
  124.     rp = &rtmsg.rtmsg;
  125.     rp->rtm_seq = ++seq;
  126.     cp = (u_char *)(rp + 1);
  127.  
  128.     sp = (struct sockaddr_in *)cp;
  129.     *sp = *to;
  130.     cp += roundup(SALEN((struct sockaddr *)sp), sizeof(u_int32_t));
  131.  
  132.     size = cp - (u_char *)rp;
  133.     rp->rtm_msglen = size;
  134.  
  135.     cc = write(s, (char *)rp, size);
  136.     if (cc < 0) {
  137.         sprintf(errbuf, "write: %.128s", strerror(errno));
  138.         close(s);
  139.         return (errbuf);
  140.     }
  141.     if (cc != size) {
  142.         sprintf(errbuf, "short write (%d != %d)", cc, size);
  143.         close(s);
  144.         return (errbuf);
  145.     }
  146.  
  147.     size = sizeof(rtmsg);
  148.     do {
  149.         memset(rp, 0, size);
  150.         cc = read(s, (char *)rp, size);
  151.         if (cc < 0) {
  152.             sprintf(errbuf, "read: %.128s", strerror(errno));
  153.             close(s);
  154.             return (errbuf);
  155.         }
  156.  
  157.     } while (rp->rtm_seq != seq || rp->rtm_pid != pid);
  158.     close(s);
  159.  
  160.  
  161.     if (rp->rtm_version != RTM_VERSION) {
  162.         sprintf(errbuf, "bad version %d", rp->rtm_version);
  163.         return (errbuf);
  164.     }
  165.     if (rp->rtm_msglen > cc) {
  166.         sprintf(errbuf, "bad msglen %d > %d", rp->rtm_msglen, cc);
  167.         return (errbuf);
  168.     }
  169.     if (rp->rtm_errno != 0) {
  170.         sprintf(errbuf, "rtm_errno: %.128s", strerror(rp->rtm_errno));
  171.         return (errbuf);
  172.     }
  173.  
  174.     /* Find the interface sockaddr */
  175.     cp = (u_char *)(rp + 1);
  176.     for (i = 1; i != 0; i <<= 1)
  177.         if ((i & rp->rtm_addrs) != 0) {
  178.             sa = (struct sockaddr *)cp;
  179.             switch (i) {
  180.  
  181.             case RTA_IFA:
  182.                 if (sa->sa_family == AF_INET) {
  183.                     ifa = (struct sockaddr_in *)cp;
  184.                     if (ifa->sin_addr.s_addr != 0) {
  185.                         *from = *ifa;
  186.                         return (NULL);
  187.                     }
  188.                 }
  189.                 break;
  190.  
  191.             default:
  192.                 /* empty */
  193.                 break;
  194.             }
  195.  
  196.             if (SALEN(sa) == 0)
  197.                 cp += sizeof(u_int32_t);
  198.             else
  199.                 cp += roundup(SALEN(sa), sizeof(u_int32_t));
  200.         }
  201.  
  202.     return ("failed!");
  203. }
  204.  
  205. #ifndef HAVE_SOCKADDR_SA_LEN
  206. static int
  207. salen(struct sockaddr *sa)
  208. {
  209.     switch (sa->sa_family) {
  210.  
  211.     case AF_INET:
  212.         return (sizeof(struct sockaddr_in));
  213.  
  214.     case AF_LINK:
  215.         return (sizeof(struct sockaddr_dl));
  216.  
  217.     default:
  218.         return (sizeof(struct sockaddr));
  219.     }
  220. }
  221. #endif
  222.