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

route-linux.c

Go to the documentation of this file.
00001 /*
00002  * route-linux.c
00003  *
00004  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
00005  *
00006  * $Id: route-linux.c,v 1.18 2006/01/15 07:33:29 dugsong Exp $
00007  */
00008 
00009 #include "config.h"
00010 
00011 #include <sys/types.h>
00012 #include <sys/ioctl.h>
00013 #include <sys/socket.h>
00014 #include <sys/uio.h>
00015 
00016 #include <asm/types.h>
00017 #include <netinet/in.h>
00018 #include <linux/netlink.h>
00019 #include <linux/rtnetlink.h>
00020 
00021 #include <net/route.h>
00022 
00023 #include <ctype.h>
00024 #include <errno.h>
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 
00030 #include "dnet.h"
00031 
00032 #define ADDR_ISHOST(a)  (((a)->addr_type == ADDR_TYPE_IP &&     \
00033                           (a)->addr_bits == IP_ADDR_BITS) ||    \
00034                          ((a)->addr_type == ADDR_TYPE_IP6 &&    \
00035                           (a)->addr_bits == IP6_ADDR_BITS))
00036 
00037 #define PROC_ROUTE_FILE         "/proc/net/route"
00038 #define PROC_IPV6_ROUTE_FILE    "/proc/net/ipv6_route"
00039 
00040 struct route_handle {
00041         int      fd;
00042         int      nlfd;
00043 };
00044 
00045 route_t *
00046 route_open(void)
00047 {
00048         struct sockaddr_nl snl;
00049         route_t *r;
00050 
00051         if ((r = calloc(1, sizeof(*r))) != NULL) {
00052                 r->fd = r->nlfd = -1;
00053                 
00054                 if ((r->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00055                         return (route_close(r));
00056                 
00057                 if ((r->nlfd = socket(AF_NETLINK, SOCK_RAW,
00058                          NETLINK_ROUTE)) < 0)
00059                         return (route_close(r));
00060                 
00061                 memset(&snl, 0, sizeof(snl));
00062                 snl.nl_family = AF_NETLINK;
00063                 
00064                 if (bind(r->nlfd, (struct sockaddr *)&snl, sizeof(snl)) < 0)
00065                         return (route_close(r));
00066         }
00067         return (r);
00068 }
00069 
00070 int
00071 route_add(route_t *r, const struct route_entry *entry)
00072 {
00073         struct rtentry rt;
00074         struct addr dst;
00075 
00076         memset(&rt, 0, sizeof(rt));
00077         rt.rt_flags = RTF_UP | RTF_GATEWAY;
00078 
00079         if (ADDR_ISHOST(&entry->route_dst)) {
00080                 rt.rt_flags |= RTF_HOST;
00081                 memcpy(&dst, &entry->route_dst, sizeof(dst));
00082         } else
00083                 addr_net(&entry->route_dst, &dst);
00084         
00085         if (addr_ntos(&dst, &rt.rt_dst) < 0 ||
00086             addr_ntos(&entry->route_gw, &rt.rt_gateway) < 0 ||
00087             addr_btos(entry->route_dst.addr_bits, &rt.rt_genmask) < 0)
00088                 return (-1);
00089         
00090         return (ioctl(r->fd, SIOCADDRT, &rt));
00091 }
00092 
00093 int
00094 route_delete(route_t *r, const struct route_entry *entry)
00095 {
00096         struct rtentry rt;
00097         struct addr dst;
00098         
00099         memset(&rt, 0, sizeof(rt));
00100         rt.rt_flags = RTF_UP;
00101 
00102         if (ADDR_ISHOST(&entry->route_dst)) {
00103                 rt.rt_flags |= RTF_HOST;
00104                 memcpy(&dst, &entry->route_dst, sizeof(dst));
00105         } else
00106                 addr_net(&entry->route_dst, &dst);
00107         
00108         if (addr_ntos(&dst, &rt.rt_dst) < 0 ||
00109             addr_btos(entry->route_dst.addr_bits, &rt.rt_genmask) < 0)
00110                 return (-1);
00111         
00112         return (ioctl(r->fd, SIOCDELRT, &rt));
00113 }
00114 
00115 int
00116 route_get(route_t *r, struct route_entry *entry)
00117 {
00118         static int seq;
00119         struct nlmsghdr *nmsg;
00120         struct rtmsg *rmsg;
00121         struct rtattr *rta;
00122         struct sockaddr_nl snl;
00123         struct iovec iov;
00124         struct msghdr msg;
00125         u_char buf[512];
00126         int i, af, alen;
00127 
00128         switch (entry->route_dst.addr_type) {
00129         case ADDR_TYPE_IP:
00130                 af = AF_INET;
00131                 alen = IP_ADDR_LEN;
00132                 break;
00133         case ADDR_TYPE_IP6:
00134                 af = AF_INET6;
00135                 alen = IP6_ADDR_LEN;
00136                 break;
00137         default:
00138                 errno = EINVAL;
00139                 return (-1);
00140         }
00141         memset(buf, 0, sizeof(buf));
00142 
00143         nmsg = (struct nlmsghdr *)buf;
00144         nmsg->nlmsg_len = NLMSG_LENGTH(sizeof(*nmsg)) + RTA_LENGTH(alen);
00145         nmsg->nlmsg_flags = NLM_F_REQUEST;
00146         nmsg->nlmsg_type = RTM_GETROUTE;
00147         nmsg->nlmsg_seq = ++seq;
00148 
00149         rmsg = (struct rtmsg *)(nmsg + 1);
00150         rmsg->rtm_family = af;
00151         rmsg->rtm_dst_len = entry->route_dst.addr_bits;
00152         
00153         rta = RTM_RTA(rmsg);
00154         rta->rta_type = RTA_DST;
00155         rta->rta_len = RTA_LENGTH(alen);
00156 
00157         /* XXX - gross hack for default route */
00158         if (af == AF_INET && entry->route_dst.addr_ip == IP_ADDR_ANY) {
00159                 i = htonl(0x60060606);
00160                 memcpy(RTA_DATA(rta), &i, alen);
00161         } else
00162                 memcpy(RTA_DATA(rta), entry->route_dst.addr_data8, alen);
00163         
00164         memset(&snl, 0, sizeof(snl));
00165         snl.nl_family = AF_NETLINK;
00166 
00167         iov.iov_base = nmsg;
00168         iov.iov_len = nmsg->nlmsg_len;
00169         
00170         memset(&msg, 0, sizeof(msg));
00171         msg.msg_name = &snl;
00172         msg.msg_namelen = sizeof(snl);
00173         msg.msg_iov = &iov;
00174         msg.msg_iovlen = 1;
00175         
00176         if (sendmsg(r->nlfd, &msg, 0) < 0)
00177                 return (-1);
00178 
00179         iov.iov_base = buf;
00180         iov.iov_len = sizeof(buf);
00181         
00182         if ((i = recvmsg(r->nlfd, &msg, 0)) <= 0)
00183                 return (-1);
00184 
00185         if (nmsg->nlmsg_len < (int)sizeof(*nmsg) || nmsg->nlmsg_len > i ||
00186             nmsg->nlmsg_seq != seq) {
00187                 errno = EINVAL;
00188                 return (-1);
00189         }
00190         if (nmsg->nlmsg_type == NLMSG_ERROR)
00191                 return (-1);
00192         
00193         i -= NLMSG_LENGTH(sizeof(*nmsg));
00194         
00195         while (RTA_OK(rta, i)) {
00196                 if (rta->rta_type == RTA_GATEWAY) {
00197                         entry->route_gw.addr_type = entry->route_dst.addr_type;
00198                         memcpy(entry->route_gw.addr_data8, RTA_DATA(rta), alen);
00199                         entry->route_gw.addr_bits = alen * 8;
00200                         return (0);
00201                 }
00202                 rta = RTA_NEXT(rta, i);
00203         }
00204         errno = ESRCH;
00205         
00206         return (-1);
00207 }
00208 
00209 int
00210 route_loop(route_t *r, route_handler callback, void *arg)
00211 {
00212         FILE *fp;
00213         struct route_entry entry;
00214         char buf[BUFSIZ];
00215         int ret = 0;
00216 
00217         if ((fp = fopen(PROC_ROUTE_FILE, "r")) != NULL) {
00218                 char ifbuf[16];
00219                 int i, iflags, refcnt, use, metric, mss, win, irtt;
00220                 uint32_t mask;
00221                 
00222                 while (fgets(buf, sizeof(buf), fp) != NULL) {
00223                         i = sscanf(buf, "%16s %X %X %X %d %d %d %X %d %d %d\n",
00224                             ifbuf, &entry.route_dst.addr_ip,
00225                             &entry.route_gw.addr_ip, &iflags, &refcnt, &use,
00226                             &metric, &mask, &mss, &win, &irtt);
00227                         
00228                         if (i < 10 || !(iflags & RTF_UP))
00229                                 continue;
00230                 
00231                         if (entry.route_gw.addr_ip == IP_ADDR_ANY)
00232                                 continue;
00233                 
00234                         entry.route_dst.addr_type = entry.route_gw.addr_type =
00235                             ADDR_TYPE_IP;
00236                 
00237                         if (addr_mtob(&mask, IP_ADDR_LEN,
00238                                 &entry.route_dst.addr_bits) < 0)
00239                                 continue;
00240                         
00241                         entry.route_gw.addr_bits = IP_ADDR_BITS;
00242                         
00243                         if ((ret = callback(&entry, arg)) != 0)
00244                                 break;
00245                 }
00246                 fclose(fp);
00247         }
00248         if (ret == 0 && (fp = fopen(PROC_IPV6_ROUTE_FILE, "r")) != NULL) {
00249                 char s[33], d[8][5], n[8][5];
00250                 u_int slen, dlen;
00251                 
00252                 while (fgets(buf, sizeof(buf), fp) != NULL) {
00253                         sscanf(buf, "%04s%04s%04s%04s%04s%04s%04s%04s %02x "
00254                             "%32s %02x %04s%04s%04s%04s%04s%04s%04s%04s ",
00255                             d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
00256                             &dlen, s, &slen,
00257                             n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]);
00258                         snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d",
00259                             d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
00260                             dlen);
00261                         addr_aton(buf, &entry.route_dst);
00262                         snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d",
00263                             n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7],
00264                             IP6_ADDR_BITS);
00265                         addr_aton(buf, &entry.route_gw);
00266                         
00267                         if ((ret = callback(&entry, arg)) != 0)
00268                                 break;
00269                 }
00270                 fclose(fp);
00271         }
00272         return (ret);
00273 }
00274 
00275 route_t *
00276 route_close(route_t *r)
00277 {
00278         if (r != NULL) {
00279                 if (r->fd >= 0)
00280                         close(r->fd);
00281                 if (r->nlfd >= 0)
00282                         close(r->nlfd);
00283                 free(r);
00284         }
00285         return (NULL);
00286 }

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