Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

intf.c

Go to the documentation of this file.
00001 /*
00002  * intf.c
00003  *
00004  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
00005  *
00006  * $Id: intf.c,v 1.56 2006/01/09 07:09:49 dugsong Exp $
00007  */
00008 
00009 #include "config.h"
00010 
00011 #include <sys/param.h>
00012 #include <sys/types.h>
00013 #include <sys/ioctl.h>
00014 #include <sys/socket.h>
00015 #ifdef HAVE_SYS_SOCKIO_H
00016 # include <sys/sockio.h>
00017 #endif
00018 /* XXX - AIX */
00019 #ifndef IP_MULTICAST
00020 # define IP_MULTICAST
00021 #endif
00022 #include <net/if.h>
00023 #ifdef HAVE_NET_IF_VAR_H
00024 # include <net/if_var.h>
00025 #endif
00026 #undef IP_MULTICAST
00027 /* XXX - IPv6 ioctls */
00028 #ifdef HAVE_NETINET_IN_VAR_H
00029 # include <netinet/in.h>
00030 # include <netinet/in_var.h>
00031 #endif
00032 
00033 #include <errno.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <unistd.h>
00038 
00039 #include "dnet.h"
00040 
00041 /* XXX - Tru64 */
00042 #if defined(SIOCRIPMTU) && defined(SIOCSIPMTU)
00043 # define SIOCGIFMTU     SIOCRIPMTU
00044 # define SIOCSIFMTU     SIOCSIPMTU
00045 #endif
00046 
00047 /* XXX - HP-UX */
00048 #if defined(SIOCADDIFADDR) && defined(SIOCDELIFADDR)
00049 # define SIOCAIFADDR    SIOCADDIFADDR
00050 # define SIOCDIFADDR    SIOCDELIFADDR
00051 #endif
00052 
00053 /* XXX - HP-UX, Solaris */
00054 #if !defined(ifr_mtu) && defined(ifr_metric)
00055 # define ifr_mtu        ifr_metric
00056 #endif
00057 
00058 #ifdef HAVE_SOCKADDR_SA_LEN
00059 # define NEXTIFR(i)     ((struct ifreq *)((u_char *)&i->ifr_addr + \
00060                                 (i->ifr_addr.sa_len ? i->ifr_addr.sa_len : \
00061                                  sizeof(i->ifr_addr))))
00062 #else
00063 # define NEXTIFR(i)     (i + 1)
00064 #endif
00065 
00066 /* XXX - superset of ifreq, for portable SIOC{A,D}IFADDR */
00067 struct dnet_ifaliasreq {
00068         char            ifra_name[IFNAMSIZ];
00069         struct sockaddr ifra_addr;
00070         struct sockaddr ifra_brdaddr;
00071         struct sockaddr ifra_mask;
00072         int             ifra_cookie;    /* XXX - IRIX!@#$ */
00073 };
00074 
00075 struct intf_handle {
00076         int             fd;
00077         int             fd6;
00078         struct ifconf   ifc;
00079         u_char          ifcbuf[4192];
00080 };
00081 
00082 static int
00083 intf_flags_to_iff(u_short flags, int iff)
00084 {
00085         if (flags & INTF_FLAG_UP)
00086                 iff |= IFF_UP;
00087         else
00088                 iff &= ~IFF_UP;
00089         if (flags & INTF_FLAG_NOARP)
00090                 iff |= IFF_NOARP;
00091         else
00092                 iff &= ~IFF_NOARP;
00093         
00094         return (iff);
00095 }
00096 
00097 static u_int
00098 intf_iff_to_flags(int iff)
00099 {
00100         u_int n = 0;
00101 
00102         if (iff & IFF_UP)
00103                 n |= INTF_FLAG_UP;      
00104         if (iff & IFF_LOOPBACK)
00105                 n |= INTF_FLAG_LOOPBACK;
00106         if (iff & IFF_POINTOPOINT)
00107                 n |= INTF_FLAG_POINTOPOINT;
00108         if (iff & IFF_NOARP)
00109                 n |= INTF_FLAG_NOARP;
00110         if (iff & IFF_BROADCAST)
00111                 n |= INTF_FLAG_BROADCAST;
00112         if (iff & IFF_MULTICAST)
00113                 n |= INTF_FLAG_MULTICAST;
00114 
00115         return (n);
00116 }
00117 
00118 intf_t *
00119 intf_open(void)
00120 {
00121         intf_t *intf;
00122         
00123         if ((intf = calloc(1, sizeof(*intf))) != NULL) {
00124                 intf->fd = intf->fd6 = -1;
00125                 
00126                 if ((intf->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00127                         return (intf_close(intf));
00128 #ifdef SIOCGIFNETMASK_IN6
00129                 if ((intf->fd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
00130 #  ifdef EPROTONOSUPPORT
00131                         if (errno != EPROTONOSUPPORT)
00132 #  endif
00133                                 return (intf_close(intf));
00134                 }
00135 #endif
00136         }
00137         return (intf);
00138 }
00139 
00140 static int
00141 _intf_delete_addrs(intf_t *intf, struct intf_entry *entry)
00142 {
00143 #if defined(SIOCDIFADDR)
00144         struct dnet_ifaliasreq ifra;
00145         
00146         memset(&ifra, 0, sizeof(ifra));
00147         strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name));
00148         if (entry->intf_addr.addr_type == ADDR_TYPE_IP) {
00149                 addr_ntos(&entry->intf_addr, &ifra.ifra_addr);
00150                 ioctl(intf->fd, SIOCDIFADDR, &ifra);
00151         }
00152         if (entry->intf_dst_addr.addr_type == ADDR_TYPE_IP) {
00153                 addr_ntos(&entry->intf_dst_addr, &ifra.ifra_addr);
00154                 ioctl(intf->fd, SIOCDIFADDR, &ifra);
00155         }
00156 #elif defined(SIOCLIFREMOVEIF)
00157         struct ifreq ifr;
00158 
00159         memset(&ifr, 0, sizeof(ifr));
00160         strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name));
00161         /* XXX - overloading Solaris lifreq with ifreq */
00162         ioctl(intf->fd, SIOCLIFREMOVEIF, &ifr);
00163 #endif
00164         return (0);
00165 }
00166 
00167 static int
00168 _intf_delete_aliases(intf_t *intf, struct intf_entry *entry)
00169 {
00170         int i;
00171 #if defined(SIOCDIFADDR) && !defined(__linux__) /* XXX - see Linux below */
00172         struct dnet_ifaliasreq ifra;
00173         
00174         memset(&ifra, 0, sizeof(ifra));
00175         strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name));
00176         
00177         for (i = 0; i < (int)entry->intf_alias_num; i++) {
00178                 addr_ntos(&entry->intf_alias_addrs[i], &ifra.ifra_addr);
00179                 ioctl(intf->fd, SIOCDIFADDR, &ifra);
00180         }
00181 #else
00182         struct ifreq ifr;
00183         
00184         for (i = 0; i < entry->intf_alias_num; i++) {
00185                 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s:%d",
00186                     entry->intf_name, i + 1);
00187 # ifdef SIOCLIFREMOVEIF
00188                 /* XXX - overloading Solaris lifreq with ifreq */
00189                 ioctl(intf->fd, SIOCLIFREMOVEIF, &ifr);
00190 # else
00191                 /* XXX - only need to set interface down on Linux */
00192                 ifr.ifr_flags = 0;
00193                 ioctl(intf->fd, SIOCSIFFLAGS, &ifr);
00194 # endif
00195         }
00196 #endif
00197         return (0);
00198 }
00199 
00200 static int
00201 _intf_add_aliases(intf_t *intf, const struct intf_entry *entry)
00202 {
00203         int i;
00204 #ifdef SIOCAIFADDR
00205         struct dnet_ifaliasreq ifra;
00206         struct addr bcast;
00207         
00208         memset(&ifra, 0, sizeof(ifra));
00209         strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name));
00210         
00211         for (i = 0; i < (int)entry->intf_alias_num; i++) {
00212                 if (entry->intf_alias_addrs[i].addr_type != ADDR_TYPE_IP)
00213                         continue;
00214                 
00215                 if (addr_ntos(&entry->intf_alias_addrs[i],
00216                     &ifra.ifra_addr) < 0)
00217                         return (-1);
00218                 addr_bcast(&entry->intf_alias_addrs[i], &bcast);
00219                 addr_ntos(&bcast, &ifra.ifra_brdaddr);
00220                 addr_btos(entry->intf_alias_addrs[i].addr_bits,
00221                     &ifra.ifra_mask);
00222                 
00223                 if (ioctl(intf->fd, SIOCAIFADDR, &ifra) < 0)
00224                         return (-1);
00225         }
00226 #else
00227         struct ifreq ifr;
00228         int n = 1;
00229         
00230         for (i = 0; i < entry->intf_alias_num; i++) {
00231                 if (entry->intf_alias_addrs[i].addr_type != ADDR_TYPE_IP)
00232                         continue;
00233                 
00234                 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s:%d",
00235                     entry->intf_name, n++);
00236 # ifdef SIOCLIFADDIF
00237                 if (ioctl(intf->fd, SIOCLIFADDIF, &ifr) < 0)
00238                         return (-1);
00239 # endif
00240                 if (addr_ntos(&entry->intf_alias_addrs[i], &ifr.ifr_addr) < 0)
00241                         return (-1);
00242                 if (ioctl(intf->fd, SIOCSIFADDR, &ifr) < 0)
00243                         return (-1);
00244         }
00245         strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name));
00246 #endif
00247         return (0);
00248 }
00249 
00250 int
00251 intf_set(intf_t *intf, const struct intf_entry *entry)
00252 {
00253         struct ifreq ifr;
00254         struct intf_entry *orig;
00255         struct addr bcast;
00256         u_char buf[BUFSIZ];
00257         
00258         orig = (struct intf_entry *)buf;
00259         orig->intf_len = sizeof(buf);
00260         strcpy(orig->intf_name, entry->intf_name);
00261         
00262         if (intf_get(intf, orig) < 0)
00263                 return (-1);
00264         
00265         /* Delete any existing aliases. */
00266         if (_intf_delete_aliases(intf, orig) < 0)
00267                 return (-1);
00268 
00269         /* Delete any existing addrs. */
00270         if (_intf_delete_addrs(intf, orig) < 0)
00271                 return (-1);
00272         
00273         memset(&ifr, 0, sizeof(ifr));
00274         strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name));
00275         
00276         /* Set interface MTU. */
00277         if (entry->intf_mtu != 0) {
00278                 ifr.ifr_mtu = entry->intf_mtu;
00279                 if (ioctl(intf->fd, SIOCSIFMTU, &ifr) < 0)
00280                         return (-1);
00281         }
00282         /* Set interface address. */
00283         if (entry->intf_addr.addr_type == ADDR_TYPE_IP) {
00284 #ifdef BSD
00285                 /* XXX - why must this happen before SIOCSIFADDR? */
00286                 if (addr_btos(entry->intf_addr.addr_bits,
00287                     &ifr.ifr_addr) == 0) {
00288                         if (ioctl(intf->fd, SIOCSIFNETMASK, &ifr) < 0)
00289                                 return (-1);
00290                 }
00291 #endif
00292                 if (addr_ntos(&entry->intf_addr, &ifr.ifr_addr) < 0)
00293                         return (-1);
00294                 if (ioctl(intf->fd, SIOCSIFADDR, &ifr) < 0 && errno != EEXIST)
00295                         return (-1);
00296                 
00297                 if (addr_btos(entry->intf_addr.addr_bits, &ifr.ifr_addr) == 0
00298 #ifdef __linux__
00299                     && entry->intf_addr.addr_ip != 0
00300 #endif
00301                     ) {
00302                         if (ioctl(intf->fd, SIOCSIFNETMASK, &ifr) < 0)
00303                                 return (-1);
00304                 }
00305                 if (addr_bcast(&entry->intf_addr, &bcast) == 0) {
00306                         if (addr_ntos(&bcast, &ifr.ifr_broadaddr) == 0) {
00307                                 /* XXX - ignore error from non-broadcast ifs */
00308                                 ioctl(intf->fd, SIOCSIFBRDADDR, &ifr);
00309                         }
00310                 }
00311         }
00312         /* Set link-level address. */
00313         if (entry->intf_link_addr.addr_type == ADDR_TYPE_ETH &&
00314             addr_cmp(&entry->intf_link_addr, &orig->intf_link_addr) != 0) {
00315 #if defined(SIOCSIFHWADDR)
00316                 if (addr_ntos(&entry->intf_link_addr, &ifr.ifr_hwaddr) < 0)
00317                         return (-1);
00318                 if (ioctl(intf->fd, SIOCSIFHWADDR, &ifr) < 0)
00319                         return (-1);
00320 #elif defined (SIOCSIFLLADDR)
00321                 memcpy(ifr.ifr_addr.sa_data, &entry->intf_link_addr.addr_eth,
00322                     ETH_ADDR_LEN);
00323                 ifr.ifr_addr.sa_len = ETH_ADDR_LEN;
00324                 if (ioctl(intf->fd, SIOCSIFLLADDR, &ifr) < 0)
00325                         return (-1);
00326 #else
00327                 eth_t *eth;
00328 
00329                 if ((eth = eth_open(entry->intf_name)) == NULL)
00330                         return (-1);
00331                 if (eth_set(eth, &entry->intf_link_addr.addr_eth) < 0) {
00332                         eth_close(eth);
00333                         return (-1);
00334                 }
00335                 eth_close(eth);
00336 #endif
00337         }
00338         /* Set point-to-point destination. */
00339         if (entry->intf_dst_addr.addr_type == ADDR_TYPE_IP) {
00340                 if (addr_ntos(&entry->intf_dst_addr, &ifr.ifr_dstaddr) < 0)
00341                         return (-1);
00342                 if (ioctl(intf->fd, SIOCSIFDSTADDR, &ifr) < 0 &&
00343                     errno != EEXIST)
00344                         return (-1);
00345         }
00346         /* Add aliases. */
00347         if (_intf_add_aliases(intf, entry) < 0)
00348                 return (-1);
00349         
00350         /* Set interface flags. */
00351         if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0)
00352                 return (-1);
00353         
00354         ifr.ifr_flags = intf_flags_to_iff(entry->intf_flags, ifr.ifr_flags);
00355         
00356         if (ioctl(intf->fd, SIOCSIFFLAGS, &ifr) < 0)
00357                 return (-1);
00358         
00359         return (0);
00360 }
00361 
00362 /* XXX - this is total crap. how to do this without walking ifnet? */
00363 static void
00364 _intf_set_type(struct intf_entry *entry)
00365 {
00366         if ((entry->intf_flags & INTF_FLAG_BROADCAST) != 0)
00367                 entry->intf_type = INTF_TYPE_ETH;
00368         else if ((entry->intf_flags & INTF_FLAG_POINTOPOINT) != 0)
00369                 entry->intf_type = INTF_TYPE_TUN;
00370         else if ((entry->intf_flags & INTF_FLAG_LOOPBACK) != 0)
00371                 entry->intf_type = INTF_TYPE_LOOPBACK;
00372         else
00373                 entry->intf_type = INTF_TYPE_OTHER;
00374 }
00375 
00376 static int
00377 _intf_get_noalias(intf_t *intf, struct intf_entry *entry)
00378 {
00379         struct ifreq ifr;
00380 
00381         strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name));
00382         
00383         /* Get interface flags. */
00384         if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0)
00385                 return (-1);
00386         
00387         entry->intf_flags = intf_iff_to_flags(ifr.ifr_flags);
00388         _intf_set_type(entry);
00389         
00390         /* Get interface MTU. */
00391         if (ioctl(intf->fd, SIOCGIFMTU, &ifr) < 0)
00392                 return (-1);
00393         entry->intf_mtu = ifr.ifr_mtu;
00394 
00395         entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type =
00396             entry->intf_link_addr.addr_type = ADDR_TYPE_NONE;
00397         
00398         /* Get primary interface address. */
00399         if (ioctl(intf->fd, SIOCGIFADDR, &ifr) == 0) {
00400                 addr_ston(&ifr.ifr_addr, &entry->intf_addr);
00401                 if (ioctl(intf->fd, SIOCGIFNETMASK, &ifr) < 0)
00402                         return (-1);
00403                 addr_stob(&ifr.ifr_addr, &entry->intf_addr.addr_bits);
00404         }
00405         /* Get other addresses. */
00406         if (entry->intf_type == INTF_TYPE_TUN) {
00407                 if (ioctl(intf->fd, SIOCGIFDSTADDR, &ifr) == 0) {
00408                         if (addr_ston(&ifr.ifr_addr,
00409                             &entry->intf_dst_addr) < 0)
00410                                 return (-1);
00411                 }
00412         } else if (entry->intf_type == INTF_TYPE_ETH) {
00413 #if defined(SIOCGIFHWADDR)
00414                 if (ioctl(intf->fd, SIOCGIFHWADDR, &ifr) < 0)
00415                         return (-1);
00416                 if (addr_ston(&ifr.ifr_addr, &entry->intf_link_addr) < 0)
00417                         return (-1);
00418 #elif defined(SIOCRPHYSADDR)
00419                 /* Tru64 */
00420                 struct ifdevea *ifd = (struct ifdevea *)&ifr; /* XXX */
00421                 
00422                 if (ioctl(intf->fd, SIOCRPHYSADDR, ifd) < 0)
00423                         return (-1);
00424                 addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS,
00425                     ifd->current_pa, ETH_ADDR_LEN);
00426 #else
00427                 eth_t *eth;
00428                 
00429                 if ((eth = eth_open(entry->intf_name)) != NULL) {
00430                         if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) {
00431                                 entry->intf_link_addr.addr_type =
00432                                     ADDR_TYPE_ETH;
00433                                 entry->intf_link_addr.addr_bits =
00434                                     ETH_ADDR_BITS;
00435                         }
00436                         eth_close(eth);
00437                 }
00438 #endif
00439         }
00440         return (0);
00441 }
00442 
00443 #ifdef SIOCLIFADDR
00444 /* XXX - aliases on IRIX don't show up in SIOCGIFCONF */
00445 static int
00446 _intf_get_aliases(intf_t *intf, struct intf_entry *entry)
00447 {
00448         struct dnet_ifaliasreq ifra;
00449         struct addr *ap, *lap;
00450         
00451         strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name));
00452         addr_ntos(&entry->intf_addr, &ifra.ifra_addr);
00453         addr_btos(entry->intf_addr.addr_bits, &ifra.ifra_mask);
00454         memset(&ifra.ifra_brdaddr, 0, sizeof(ifra.ifra_brdaddr));
00455         ifra.ifra_cookie = 1;
00456 
00457         ap = entry->intf_alias_addrs;
00458         lap = (struct addr *)((u_char *)entry + entry->intf_len);
00459         
00460         while (ioctl(intf->fd, SIOCLIFADDR, &ifra) == 0 &&
00461             ifra.ifra_cookie > 0 && (ap + 1) < lap) {
00462                 if (addr_ston(&ifra.ifra_addr, ap) < 0)
00463                         break;
00464                 ap++, entry->intf_alias_num++;
00465         }
00466         entry->intf_len = (u_char *)ap - (u_char *)entry;
00467         
00468         return (0);
00469 }
00470 #else
00471 static int
00472 _intf_get_aliases(intf_t *intf, struct intf_entry *entry)
00473 {
00474         struct ifreq *ifr, *lifr;
00475         struct addr *ap, *lap;
00476         char *p;
00477         
00478         if (intf->ifc.ifc_len < (int)sizeof(*ifr)) {
00479                 errno = EINVAL;
00480                 return (-1);
00481         }
00482         entry->intf_alias_num = 0;
00483         ap = entry->intf_alias_addrs;
00484         lifr = (struct ifreq *)intf->ifc.ifc_buf + 
00485             (intf->ifc.ifc_len / sizeof(*lifr));
00486         lap = (struct addr *)((u_char *)entry + entry->intf_len);
00487         
00488         /* Get addresses for this interface. */
00489         for (ifr = intf->ifc.ifc_req; ifr < lifr && (ap + 1) < lap;
00490             ifr = NEXTIFR(ifr)) {
00491                 /* XXX - Linux, Solaris ifaliases */
00492                 if ((p = strchr(ifr->ifr_name, ':')) != NULL)
00493                         *p = '\0';
00494                 
00495                 if (strcmp(ifr->ifr_name, entry->intf_name) != 0)
00496                         continue;
00497                 
00498                 if (addr_ston(&ifr->ifr_addr, ap) < 0)
00499                         continue;
00500                 
00501                 /* XXX */
00502                 if (ap->addr_type == ADDR_TYPE_ETH) {
00503                         memcpy(&entry->intf_link_addr, ap, sizeof(*ap));
00504                         continue;
00505                 } else if (ap->addr_type == ADDR_TYPE_IP) {
00506                         if (ap->addr_ip == entry->intf_addr.addr_ip ||
00507                             ap->addr_ip == entry->intf_dst_addr.addr_ip)
00508                                 continue;
00509                 }
00510 #ifdef SIOCGIFNETMASK_IN6
00511                 else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) {
00512                         struct in6_ifreq ifr6;
00513 
00514                         /* XXX - sizeof(ifr) < sizeof(ifr6) */
00515                         memcpy(&ifr6, ifr, sizeof(ifr6));
00516                         
00517                         if (ioctl(intf->fd6, SIOCGIFNETMASK_IN6, &ifr6) == 0) {
00518                                 addr_stob((struct sockaddr *)&ifr6.ifr_addr,
00519                                     &ap->addr_bits);
00520                         }
00521                         else perror("SIOCGIFNETMASK_IN6");
00522                 }
00523 #endif
00524                 ap++, entry->intf_alias_num++;
00525         }
00526 #ifdef HAVE_LINUX_PROCFS
00527 #define PROC_INET6_FILE "/proc/net/if_inet6"
00528         {
00529                 FILE *f;
00530                 char buf[256], s[8][5], name[INTF_NAME_LEN];
00531                 u_int idx, bits, scope, flags;
00532                 
00533                 if ((f = fopen(PROC_INET6_FILE, "r")) != NULL) {
00534                         while (ap < lap &&
00535                                fgets(buf, sizeof(buf), f) != NULL) {
00536                                 sscanf(buf, "%04s%04s%04s%04s%04s%04s%04s%04s %02x %02x %02x %02x %32s\n",
00537                                     s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],
00538                                     &idx, &bits, &scope, &flags, name);
00539                                 if (strcmp(name, entry->intf_name) == 0) {
00540                                         snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d",
00541                                             s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], bits);
00542                                         addr_aton(buf, ap);
00543                                         ap++, entry->intf_alias_num++;
00544                                 }
00545                         }
00546                         fclose(f);
00547                 }
00548         }
00549 #endif
00550         entry->intf_len = (u_char *)ap - (u_char *)entry;
00551         
00552         return (0);
00553 }
00554 #endif /* SIOCLIFADDR */
00555 
00556 int
00557 intf_get(intf_t *intf, struct intf_entry *entry)
00558 {
00559         if (_intf_get_noalias(intf, entry) < 0)
00560                 return (-1);
00561 #ifndef SIOCLIFADDR
00562         intf->ifc.ifc_buf = (caddr_t)intf->ifcbuf;
00563         intf->ifc.ifc_len = sizeof(intf->ifcbuf);
00564         
00565         if (ioctl(intf->fd, SIOCGIFCONF, &intf->ifc) < 0)
00566                 return (-1);
00567 #endif
00568         return (_intf_get_aliases(intf, entry));
00569 }
00570 
00571 static int
00572 _match_intf_src(const struct intf_entry *entry, void *arg)
00573 {
00574         struct intf_entry *save = (struct intf_entry *)arg;
00575         
00576         if (entry->intf_addr.addr_type == ADDR_TYPE_IP &&
00577             entry->intf_addr.addr_ip == save->intf_addr.addr_ip) {
00578                 /* XXX - truncated result if entry is too small. */
00579                 if (save->intf_len < entry->intf_len)
00580                         memcpy(save, entry, save->intf_len);
00581                 else
00582                         memcpy(save, entry, entry->intf_len);
00583                 return (1);
00584         }
00585         return (0);
00586 }
00587 
00588 int
00589 intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src)
00590 {
00591         memcpy(&entry->intf_addr, src, sizeof(*src));
00592         
00593         if (intf_loop(intf, _match_intf_src, entry) != 1) {
00594                 errno = ENXIO;
00595                 return (-1);
00596         }
00597         return (0);
00598 }
00599 
00600 int
00601 intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst)
00602 {
00603         struct sockaddr_in sin;
00604         int n;
00605         
00606         if (dst->addr_type != ADDR_TYPE_IP) {
00607                 errno = EINVAL;
00608                 return (-1);
00609         }
00610         addr_ntos(dst, (struct sockaddr *)&sin);
00611         sin.sin_port = htons(666);
00612         
00613         if (connect(intf->fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
00614                 return (-1);
00615         
00616         n = sizeof(sin);
00617         if (getsockname(intf->fd, (struct sockaddr *)&sin, &n) < 0)
00618                 return (-1);
00619         
00620         addr_ston((struct sockaddr *)&sin, &entry->intf_addr);
00621         
00622         if (intf_loop(intf, _match_intf_src, entry) != 1)
00623                 return (-1);
00624         
00625         return (0);
00626 }
00627 
00628 #ifdef HAVE_LINUX_PROCFS
00629 #define PROC_DEV_FILE   "/proc/net/dev"
00630 
00631 int
00632 intf_loop(intf_t *intf, intf_handler callback, void *arg)
00633 {
00634         FILE *fp;
00635         struct intf_entry *entry;
00636         char *p, buf[BUFSIZ], ebuf[BUFSIZ];
00637         int ret;
00638 
00639         entry = (struct intf_entry *)ebuf;
00640         
00641         if ((fp = fopen(PROC_DEV_FILE, "r")) == NULL)
00642                 return (-1);
00643         
00644         intf->ifc.ifc_buf = (caddr_t)intf->ifcbuf;
00645         intf->ifc.ifc_len = sizeof(intf->ifcbuf);
00646         
00647         if (ioctl(intf->fd, SIOCGIFCONF, &intf->ifc) < 0)
00648                 return (-1);
00649 
00650         ret = 0;
00651         while (fgets(buf, sizeof(buf), fp) != NULL) {
00652                 if ((p = strchr(buf, ':')) == NULL)
00653                         continue;
00654                 *p = '\0';
00655                 for (p = buf; *p == ' '; p++)
00656                         ;
00657 
00658                 memset(ebuf, 0, sizeof(ebuf));
00659                 strlcpy(entry->intf_name, p, sizeof(entry->intf_name));
00660                 entry->intf_len = sizeof(ebuf);
00661                 
00662                 if (_intf_get_noalias(intf, entry) < 0) {
00663                         ret = -1;
00664                         break;
00665                 }
00666                 if (_intf_get_aliases(intf, entry) < 0) {
00667                         ret = -1;
00668                         break;
00669                 }
00670                 if ((ret = (*callback)(entry, arg)) != 0)
00671                         break;
00672         }
00673         if (ferror(fp))
00674                 ret = -1;
00675         
00676         fclose(fp);
00677         
00678         return (ret);
00679 }
00680 #else
00681 int
00682 intf_loop(intf_t *intf, intf_handler callback, void *arg)
00683 {
00684         struct intf_entry *entry;
00685         struct ifreq *ifr, *lifr, *pifr;
00686         char *p, ebuf[BUFSIZ];
00687         int ret;
00688 
00689         entry = (struct intf_entry *)ebuf;
00690 
00691         intf->ifc.ifc_buf = (caddr_t)intf->ifcbuf;
00692         intf->ifc.ifc_len = sizeof(intf->ifcbuf);
00693         
00694         if (ioctl(intf->fd, SIOCGIFCONF, &intf->ifc) < 0)
00695                 return (-1);
00696 
00697         pifr = NULL;
00698         lifr = (struct ifreq *)&intf->ifc.ifc_buf[intf->ifc.ifc_len];
00699         
00700         for (ifr = intf->ifc.ifc_req; ifr < lifr; ifr = NEXTIFR(ifr)) {
00701                 /* XXX - Linux, Solaris ifaliases */
00702                 if ((p = strchr(ifr->ifr_name, ':')) != NULL)
00703                         *p = '\0';
00704                 
00705                 if (pifr != NULL && strcmp(ifr->ifr_name, pifr->ifr_name) == 0)
00706                         continue;
00707 
00708                 memset(ebuf, 0, sizeof(ebuf));
00709                 strlcpy(entry->intf_name, ifr->ifr_name,
00710                     sizeof(entry->intf_name));
00711                 entry->intf_len = sizeof(ebuf);
00712                 
00713                 if (_intf_get_noalias(intf, entry) < 0)
00714                         return (-1);
00715                 if (_intf_get_aliases(intf, entry) < 0)
00716                         return (-1);
00717                 
00718                 if ((ret = (*callback)(entry, arg)) != 0)
00719                         return (ret);
00720 
00721                 pifr = ifr;
00722         }
00723         return (0);
00724 }
00725 #endif /* !HAVE_LINUX_PROCFS */
00726 
00727 intf_t *
00728 intf_close(intf_t *intf)
00729 {
00730         if (intf != NULL) {
00731                 if (intf->fd >= 0)
00732                         close(intf->fd);
00733                 if (intf->fd6 >= 0)
00734                         close(intf->fd6);
00735                 free(intf);
00736         }
00737         return (NULL);
00738 }

Generated on Sun May 14 14:51:12 2006 by  doxygen 1.4.2