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

route-bsd.c

Go to the documentation of this file.
00001 /*
00002  * route-bsd.c
00003  *
00004  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
00005  * Copyright (c) 1999 Masaki Hirabaru <masaki@merit.edu>
00006  * 
00007  * $Id: route-bsd.c,v 1.22 2005/02/10 05:18:38 dugsong Exp $
00008  */
00009 
00010 #include "config.h"
00011 
00012 #include <sys/param.h>
00013 #include <sys/types.h>
00014 #include <sys/socket.h>
00015 #ifdef HAVE_SYS_SYSCTL_H
00016 #include <sys/sysctl.h>
00017 #endif
00018 #ifdef HAVE_STREAMS_MIB2
00019 #include <sys/stream.h>
00020 #include <sys/tihdr.h>
00021 #include <sys/tiuser.h>
00022 #include <inet/common.h>
00023 #include <inet/mib2.h>
00024 #include <inet/ip.h>
00025 #undef IP_ADDR_LEN
00026 #include <stropts.h>
00027 #elif defined(HAVE_STREAMS_ROUTE)
00028 #include <sys/stream.h>
00029 #include <sys/stropts.h>
00030 #endif
00031 
00032 #define route_t oroute_t        /* XXX - unixware */
00033 #include <net/route.h>
00034 #undef route_t
00035 #include <netinet/in.h>
00036 
00037 #include <errno.h>
00038 #include <fcntl.h>
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 #include <unistd.h>
00043 
00044 #include "dnet.h"
00045 
00046 #define ROUNDUP(a) \
00047         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
00048 
00049 #ifdef HAVE_SOCKADDR_SA_LEN
00050 #define NEXTSA(s) \
00051         ((struct sockaddr *)((u_char *)(s) + ROUNDUP((s)->sa_len)))
00052 #else
00053 #define NEXTSA(s) \
00054         ((struct sockaddr *)((u_char *)(s) + ROUNDUP(sizeof(*(s)))))
00055 #endif
00056 
00057 struct route_handle {
00058         int     fd;
00059         int     seq;
00060 #ifdef HAVE_STREAMS_MIB2
00061         int     ip_fd;
00062 #endif
00063 };
00064 
00065 #ifdef DEBUG
00066 static void
00067 route_msg_print(struct rt_msghdr *rtm)
00068 {
00069         printf("v: %d type: 0x%x flags: 0x%x addrs: 0x%x pid: %d seq: %d\n",
00070             rtm->rtm_version, rtm->rtm_type, rtm->rtm_flags,
00071             rtm->rtm_addrs, rtm->rtm_pid, rtm->rtm_seq);
00072 }
00073 #endif
00074 
00075 static int
00076 route_msg(route_t *r, int type, struct addr *dst, struct addr *gw)
00077 {
00078         struct addr net;
00079         struct rt_msghdr *rtm;
00080         struct sockaddr *sa;
00081         u_char buf[BUFSIZ];
00082         pid_t pid;
00083         int len;
00084 
00085         memset(buf, 0, sizeof(buf));
00086 
00087         rtm = (struct rt_msghdr *)buf;
00088         rtm->rtm_version = RTM_VERSION;
00089         if ((rtm->rtm_type = type) != RTM_DELETE)
00090                 rtm->rtm_flags = RTF_UP;
00091         rtm->rtm_addrs = RTA_DST;
00092         rtm->rtm_seq = ++r->seq;
00093 
00094         /* Destination */
00095         sa = (struct sockaddr *)(rtm + 1);
00096         if (addr_net(dst, &net) < 0 || addr_ntos(&net, sa) < 0)
00097                 return (-1);
00098         sa = NEXTSA(sa);
00099 
00100         /* Gateway */
00101         if (gw != NULL && type != RTM_GET) {
00102                 rtm->rtm_flags |= RTF_GATEWAY;
00103                 rtm->rtm_addrs |= RTA_GATEWAY;
00104                 if (addr_ntos(gw, sa) < 0)
00105                         return (-1);
00106                 sa = NEXTSA(sa);
00107         }
00108         /* Netmask */
00109         if (dst->addr_ip == IP_ADDR_ANY || dst->addr_bits < IP_ADDR_BITS) {
00110                 rtm->rtm_addrs |= RTA_NETMASK;
00111                 if (addr_btos(dst->addr_bits, sa) < 0)
00112                         return (-1);
00113                 sa = NEXTSA(sa);
00114         } else
00115                 rtm->rtm_flags |= RTF_HOST;
00116         
00117         rtm->rtm_msglen = (u_char *)sa - buf;
00118 #ifdef DEBUG
00119         route_msg_print(rtm);
00120 #endif
00121 #ifdef HAVE_STREAMS_ROUTE
00122         if (ioctl(r->fd, RTSTR_SEND, rtm) < 0)
00123                 return (-1);
00124 #else
00125         if (write(r->fd, buf, rtm->rtm_msglen) < 0)
00126                 return (-1);
00127 
00128         pid = getpid();
00129         
00130         while (type == RTM_GET && (len = read(r->fd, buf, sizeof(buf))) > 0) {
00131                 if (len < (int)sizeof(*rtm)) {
00132                         return (-1);
00133                 }
00134                 if (rtm->rtm_type == type && rtm->rtm_pid == pid &&
00135                     rtm->rtm_seq == r->seq) {
00136                         if (rtm->rtm_errno) {
00137                                 errno = rtm->rtm_errno;
00138                                 return (-1);
00139                         }
00140                         break;
00141                 }
00142         }
00143 #endif
00144         if (type == RTM_GET && (rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) ==
00145             (RTA_DST|RTA_GATEWAY)) {
00146                 sa = (struct sockaddr *)(rtm + 1);
00147                 sa = NEXTSA(sa);
00148                 
00149                 if (addr_ston(sa, gw) < 0 || gw->addr_type != ADDR_TYPE_IP) {
00150                         errno = ESRCH;
00151                         return (-1);
00152                 }
00153         }
00154         return (0);
00155 }
00156 
00157 route_t *
00158 route_open(void)
00159 {
00160         route_t *r;
00161         
00162         if ((r = calloc(1, sizeof(*r))) != NULL) {
00163                 r->fd = -1;
00164 #ifdef HAVE_STREAMS_MIB2
00165                 if ((r->ip_fd = open(IP_DEV_NAME, O_RDWR)) < 0)
00166                         return (route_close(r));
00167 #endif
00168 #ifdef HAVE_STREAMS_ROUTE
00169                 if ((r->fd = open("/dev/route", O_RDWR, 0)) < 0)
00170 #else
00171                 if ((r->fd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0)
00172 #endif
00173                         return (route_close(r));
00174         }
00175         return (r);
00176 }
00177 
00178 int
00179 route_add(route_t *r, const struct route_entry *entry)
00180 {
00181         struct route_entry rtent;
00182         
00183         memcpy(&rtent, entry, sizeof(rtent));
00184         
00185         if (route_msg(r, RTM_ADD, &rtent.route_dst, &rtent.route_gw) < 0)
00186                 return (-1);
00187         
00188         return (0);
00189 }
00190 
00191 int
00192 route_delete(route_t *r, const struct route_entry *entry)
00193 {
00194         struct route_entry rtent;
00195         
00196         memcpy(&rtent, entry, sizeof(rtent));
00197         
00198         if (route_get(r, &rtent) < 0)
00199                 return (-1);
00200         
00201         if (route_msg(r, RTM_DELETE, &rtent.route_dst, &rtent.route_gw) < 0)
00202                 return (-1);
00203         
00204         return (0);
00205 }
00206 
00207 int
00208 route_get(route_t *r, struct route_entry *entry)
00209 {
00210         if (route_msg(r, RTM_GET, &entry->route_dst, &entry->route_gw) < 0)
00211                 return (-1);
00212         
00213         return (0);
00214 }
00215 
00216 #if defined(HAVE_SYS_SYSCTL_H) || defined(HAVE_STREAMS_ROUTE)
00217 int
00218 route_loop(route_t *r, route_handler callback, void *arg)
00219 {
00220         struct rt_msghdr *rtm;
00221         struct route_entry entry;
00222         struct sockaddr *sa;
00223         char *buf, *lim, *next;
00224         int ret;
00225 #ifdef HAVE_SYS_SYSCTL_H
00226         int mib[6] = { CTL_NET, PF_ROUTE, 0, 0 /* XXX */, NET_RT_DUMP, 0 };
00227         size_t len;
00228         
00229         if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
00230                 return (-1);
00231 
00232         if (len == 0)
00233                 return (0);
00234         
00235         if ((buf = malloc(len)) == NULL)
00236                 return (-1);
00237         
00238         if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
00239                 free(buf);
00240                 return (-1);
00241         }
00242         lim = buf + len;
00243         next = buf;
00244 #else /* HAVE_STREAMS_ROUTE */
00245         struct rt_giarg giarg, *gp;
00246 
00247         memset(&giarg, 0, sizeof(giarg));
00248         giarg.gi_op = KINFO_RT_DUMP;
00249 
00250         if (ioctl(r->fd, RTSTR_GETROUTE, &giarg) < 0)
00251                 return (-1);
00252 
00253         if ((buf = malloc(giarg.gi_size)) == NULL)
00254                 return (-1);
00255 
00256         gp = (struct rt_giarg *)buf;
00257         gp->gi_size = giarg.gi_size;
00258         gp->gi_op = KINFO_RT_DUMP;
00259         gp->gi_where = buf;
00260         gp->gi_arg = RTF_UP | RTF_GATEWAY;
00261 
00262         if (ioctl(r->fd, RTSTR_GETROUTE, buf) < 0) {
00263                 free(buf);
00264                 return (-1);
00265         }
00266         lim = buf + gp->gi_size;
00267         next = buf + sizeof(giarg);
00268 #endif
00269         for (ret = 0; next < lim; next += rtm->rtm_msglen) {
00270                 rtm = (struct rt_msghdr *)next;
00271                 sa = (struct sockaddr *)(rtm + 1);
00272 
00273                 if (addr_ston(sa, &entry.route_dst) < 0 ||
00274                     (rtm->rtm_addrs & RTA_GATEWAY) == 0)
00275                         continue;
00276 
00277                 sa = NEXTSA(sa);
00278                 
00279                 if (addr_ston(sa, &entry.route_gw) < 0)
00280                         continue;
00281                 
00282                 if (entry.route_dst.addr_type != entry.route_gw.addr_type ||
00283                     (entry.route_dst.addr_type != ADDR_TYPE_IP &&
00284                         entry.route_dst.addr_type != ADDR_TYPE_IP6))
00285                         continue;
00286 
00287                 if (rtm->rtm_addrs & RTA_NETMASK) {
00288                         sa = NEXTSA(sa);
00289                         if (addr_stob(sa, &entry.route_dst.addr_bits) < 0)
00290                                 continue;
00291                 }
00292                 if ((ret = callback(&entry, arg)) != 0)
00293                         break;
00294         }
00295         free(buf);
00296         
00297         return (ret);
00298 }
00299 #elif defined(HAVE_STREAMS_MIB2)
00300 
00301 #ifdef IRE_DEFAULT              /* This means Solaris 5.6 */
00302 /* I'm not sure if they are compatible, though -- masaki */
00303 #define IRE_ROUTE IRE_CACHE
00304 #define IRE_ROUTE_REDIRECT IRE_HOST_REDIRECT
00305 #endif /* IRE_DEFAULT */
00306 
00307 int
00308 route_loop(route_t *r, route_handler callback, void *arg)
00309 {
00310         struct route_entry entry;
00311         struct sockaddr_in sin;
00312         struct strbuf msg;
00313         struct T_optmgmt_req *tor;
00314         struct T_optmgmt_ack *toa;
00315         struct T_error_ack *tea;
00316         struct opthdr *opt;
00317         mib2_ipRouteEntry_t *rt, *rtend;
00318         u_char buf[8192];
00319         int flags, rc, rtable, ret;
00320 
00321         tor = (struct T_optmgmt_req *)buf;
00322         toa = (struct T_optmgmt_ack *)buf;
00323         tea = (struct T_error_ack *)buf;
00324 
00325         tor->PRIM_type = T_OPTMGMT_REQ;
00326         tor->OPT_offset = sizeof(*tor);
00327         tor->OPT_length = sizeof(*opt);
00328         tor->MGMT_flags = T_CURRENT;
00329         
00330         opt = (struct opthdr *)(tor + 1);
00331         opt->level = MIB2_IP;
00332         opt->name = opt->len = 0;
00333         
00334         msg.maxlen = sizeof(buf);
00335         msg.len = sizeof(*tor) + sizeof(*opt);
00336         msg.buf = buf;
00337         
00338         if (putmsg(r->ip_fd, &msg, NULL, 0) < 0)
00339                 return (-1);
00340         
00341         opt = (struct opthdr *)(toa + 1);
00342         msg.maxlen = sizeof(buf);
00343         
00344         for (;;) {
00345                 flags = 0;
00346                 if ((rc = getmsg(r->ip_fd, &msg, NULL, &flags)) < 0)
00347                         return (-1);
00348 
00349                 /* See if we're finished. */
00350                 if (rc == 0 &&
00351                     msg.len >= sizeof(*toa) &&
00352                     toa->PRIM_type == T_OPTMGMT_ACK &&
00353                     toa->MGMT_flags == T_SUCCESS && opt->len == 0)
00354                         break;
00355 
00356                 if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK)
00357                         return (-1);
00358                 
00359                 if (rc != MOREDATA || msg.len < (int)sizeof(*toa) ||
00360                     toa->PRIM_type != T_OPTMGMT_ACK ||
00361                     toa->MGMT_flags != T_SUCCESS)
00362                         return (-1);
00363                 
00364                 rtable = (opt->level == MIB2_IP && opt->name == MIB2_IP_21);
00365                 
00366                 msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*rt));
00367                 msg.len = 0;
00368                 flags = 0;
00369                 
00370                 do {
00371                         rc = getmsg(r->ip_fd, NULL, &msg, &flags);
00372                         
00373                         if (rc != 0 && rc != MOREDATA)
00374                                 return (-1);
00375                         
00376                         if (!rtable)
00377                                 continue;
00378                         
00379                         rt = (mib2_ipRouteEntry_t *)msg.buf;
00380                         rtend = (mib2_ipRouteEntry_t *)(msg.buf + msg.len);
00381 
00382                         sin.sin_family = AF_INET;
00383 
00384                         for ( ; rt < rtend; rt++) {
00385                                 if ((rt->ipRouteInfo.re_ire_type &
00386                                     (IRE_BROADCAST|IRE_ROUTE_REDIRECT|
00387                                         IRE_LOCAL|IRE_ROUTE)) != 0 ||
00388                                     rt->ipRouteNextHop == IP_ADDR_ANY)
00389                                         continue;
00390                                 
00391                                 sin.sin_addr.s_addr = rt->ipRouteNextHop;
00392                                 addr_ston((struct sockaddr *)&sin,
00393                                     &entry.route_gw);
00394                                 
00395                                 sin.sin_addr.s_addr = rt->ipRouteDest;
00396                                 addr_ston((struct sockaddr *)&sin,
00397                                     &entry.route_dst);
00398                                 
00399                                 sin.sin_addr.s_addr = rt->ipRouteMask;
00400                                 addr_stob((struct sockaddr *)&sin,
00401                                     &entry.route_dst.addr_bits);
00402                                 
00403                                 if ((ret = callback(&entry, arg)) != 0)
00404                                         return (ret);
00405                         }
00406                 } while (rc == MOREDATA);
00407         }
00408         return (0);
00409 }
00410 #elif defined(HAVE_NET_RADIX_H)
00411 /* XXX - Tru64, others? */
00412 #include <nlist.h>
00413 
00414 static int
00415 _kread(int fd, void *addr, void *buf, int len)
00416 {
00417         if (lseek(fd, (off_t)addr, SEEK_SET) == (off_t)-1L)
00418                 return (-1);
00419         return (read(fd, buf, len) == len ? 0 : -1);
00420 }
00421 
00422 static int
00423 _radix_walk(int fd, struct radix_node *rn, route_handler callback, void *arg)
00424 {
00425         struct radix_node rnode;
00426         struct rtentry rt;
00427         struct sockaddr_in sin;
00428         struct route_entry entry;
00429         int ret = 0;
00430  again:
00431         _kread(fd, rn, &rnode, sizeof(rnode));
00432         if (rnode.rn_b < 0) {
00433                 if (!(rnode.rn_flags & RNF_ROOT)) {
00434                         _kread(fd, rn, &rt, sizeof(rt));
00435                         _kread(fd, rt_key(&rt), &sin, sizeof(sin));
00436                         addr_ston((struct sockaddr *)&sin, &entry.route_dst);
00437                         if (!(rt.rt_flags & RTF_HOST)) {
00438                                 _kread(fd, rt_mask(&rt), &sin, sizeof(sin));
00439                                 addr_stob((struct sockaddr *)&sin,
00440                                     &entry.route_dst.addr_bits);
00441                         }
00442                         _kread(fd, rt.rt_gateway, &sin, sizeof(sin));
00443                         addr_ston((struct sockaddr *)&sin, &entry.route_gw);
00444                         if ((ret = callback(&entry, arg)) != 0)
00445                                 return (ret);
00446                 }
00447                 if ((rn = rnode.rn_dupedkey))
00448                         goto again;
00449         } else {
00450                 rn = rnode.rn_r;
00451                 if ((ret = _radix_walk(fd, rnode.rn_l, callback, arg)) != 0)
00452                         return (ret);
00453                 if ((ret = _radix_walk(fd, rn, callback, arg)) != 0)
00454                         return (ret);
00455         }
00456         return (ret);
00457 }
00458 
00459 int
00460 route_loop(route_t *r, route_handler callback, void *arg)
00461 {
00462         struct radix_node_head *rnh, head;
00463         struct nlist nl[2];
00464         int fd, ret = 0;
00465 
00466         memset(nl, 0, sizeof(nl));
00467         nl[0].n_name = "radix_node_head";
00468         
00469         if (knlist(nl) < 0 || nl[0].n_type == 0 ||
00470             (fd = open("/dev/kmem", O_RDONLY, 0)) < 0)
00471                 return (-1);
00472         
00473         for (_kread(fd, (void *)nl[0].n_value, &rnh, sizeof(rnh));
00474             rnh != NULL; rnh = head.rnh_next) {
00475                 _kread(fd, rnh, &head, sizeof(head));
00476                 /* XXX - only IPv4 for now... */
00477                 if (head.rnh_af == AF_INET) {
00478                         if ((ret = _radix_walk(fd, head.rnh_treetop,
00479                                  callback, arg)) != 0)
00480                                 break;
00481                 }
00482         }
00483         close(fd);
00484         return (ret);
00485 }
00486 #else
00487 int
00488 route_loop(route_t *r, route_handler callback, void *arg)
00489 {
00490         errno = ENOSYS;
00491         return (-1);
00492 }
00493 #endif
00494 
00495 route_t *
00496 route_close(route_t *r)
00497 {
00498         if (r != NULL) {
00499 #ifdef HAVE_STREAMS_MIB2
00500                 if (r->ip_fd >= 0)
00501                         close(r->ip_fd);
00502 #endif
00503                 if (r->fd >= 0)
00504                         close(r->fd);
00505                 free(r);
00506         }
00507         return (NULL);
00508 }

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