00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "config.h"
00010
00011 #include <sys/types.h>
00012 #include <sys/ioctl.h>
00013 #include <sys/mib.h>
00014 #include <sys/socket.h>
00015
00016 #include <net/route.h>
00017
00018 #include <errno.h>
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <unistd.h>
00023
00024 #include "dnet.h"
00025
00026 #define ADDR_ISHOST(a) (((a)->addr_type == ADDR_TYPE_IP && \
00027 (a)->addr_bits == IP_ADDR_BITS) || \
00028 ((a)->addr_type == ADDR_TYPE_IP6 && \
00029 (a)->addr_bits == IP6_ADDR_BITS))
00030
00031 struct route_handle {
00032 int fd;
00033 };
00034
00035 route_t *
00036 route_open(void)
00037 {
00038 route_t *r;
00039
00040 if ((r = calloc(1, sizeof(*r))) != NULL) {
00041 if ((r->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00042 return (route_close(r));
00043 }
00044 return (r);
00045 }
00046
00047 int
00048 route_add(route_t *r, const struct route_entry *entry)
00049 {
00050 struct rtentry rt;
00051 struct addr dst;
00052
00053 memset(&rt, 0, sizeof(rt));
00054 rt.rt_flags = RTF_UP | RTF_GATEWAY;
00055
00056 if (ADDR_ISHOST(&entry->route_dst)) {
00057 rt.rt_flags |= RTF_HOST;
00058 memcpy(&dst, &entry->route_dst, sizeof(dst));
00059 } else
00060 addr_net(&entry->route_dst, &dst);
00061
00062 if (addr_ntos(&dst, &rt.rt_dst) < 0 ||
00063 addr_ntos(&entry->route_gw, &rt.rt_gateway) < 0 ||
00064 addr_btom(entry->route_dst.addr_bits, &rt.rt_subnetmask,
00065 IP_ADDR_LEN) < 0)
00066 return (-1);
00067
00068 return (ioctl(r->fd, SIOCADDRT, &rt));
00069 }
00070
00071 int
00072 route_delete(route_t *r, const struct route_entry *entry)
00073 {
00074 struct rtentry rt;
00075 struct addr dst;
00076
00077 memset(&rt, 0, sizeof(rt));
00078 rt.rt_flags = RTF_UP;
00079
00080 if (ADDR_ISHOST(&entry->route_dst)) {
00081 rt.rt_flags |= RTF_HOST;
00082 memcpy(&dst, &entry->route_dst, sizeof(dst));
00083 } else
00084 addr_net(&entry->route_dst, &dst);
00085
00086 if (addr_ntos(&dst, &rt.rt_dst) < 0 ||
00087 addr_btom(entry->route_dst.addr_bits, &rt.rt_subnetmask,
00088 IP_ADDR_LEN) < 0)
00089 return (-1);
00090
00091 return (ioctl(r->fd, SIOCDELRT, &rt));
00092 }
00093
00094 int
00095 route_get(route_t *r, struct route_entry *entry)
00096 {
00097 struct rtreq rtr;
00098
00099 memset(&rtr, 0, sizeof(rtr));
00100
00101
00102 if (entry->route_dst.addr_ip == IP_ADDR_ANY) {
00103 rtr.rtr_destaddr = htonl(0x60060606);
00104 rtr.rtr_subnetmask = 0xffffffff;
00105 } else {
00106 memcpy(&rtr.rtr_destaddr, &entry->route_dst.addr_ip,
00107 IP_ADDR_LEN);
00108 if (entry->route_dst.addr_bits < IP_ADDR_BITS)
00109 addr_btom(entry->route_dst.addr_bits,
00110 &rtr.rtr_subnetmask, IP_ADDR_LEN);
00111 }
00112 if (ioctl(r->fd, SIOCGRTENTRY, &rtr) < 0)
00113 return (-1);
00114
00115 if (rtr.rtr_gwayaddr == 0) {
00116 errno = ESRCH;
00117 return (-1);
00118 }
00119 entry->route_gw.addr_type = ADDR_TYPE_IP;
00120 entry->route_gw.addr_bits = IP_ADDR_BITS;
00121 memcpy(&entry->route_gw.addr_ip, &rtr.rtr_gwayaddr, IP_ADDR_LEN);
00122
00123 return (0);
00124 }
00125
00126 #define MAX_RTENTRIES 256
00127
00128 int
00129 route_loop(route_t *r, route_handler callback, void *arg)
00130 {
00131 struct nmparms nm;
00132 struct route_entry entry;
00133 mib_ipRouteEnt rtentries[MAX_RTENTRIES];
00134 int fd, i, n, ret;
00135
00136 if ((fd = open_mib("/dev/ip", O_RDWR, 0 , 0)) < 0)
00137 return (-1);
00138
00139 nm.objid = ID_ipRouteTable;
00140 nm.buffer = rtentries;
00141 n = sizeof(rtentries);
00142 nm.len = &n;
00143
00144 if (get_mib_info(fd, &nm) < 0) {
00145 close_mib(fd);
00146 return (-1);
00147 }
00148 close_mib(fd);
00149
00150 entry.route_dst.addr_type = entry.route_gw.addr_type = ADDR_TYPE_IP;
00151 entry.route_dst.addr_bits = entry.route_gw.addr_bits = IP_ADDR_BITS;
00152 n /= sizeof(*rtentries);
00153 ret = 0;
00154
00155 for (i = 0; i < n; i++) {
00156 if (rtentries[i].Type != NMDIRECT &&
00157 rtentries[i].Type != NMREMOTE)
00158 continue;
00159
00160 entry.route_dst.addr_ip = rtentries[i].Dest;
00161 addr_mtob(&rtentries[i].Mask, IP_ADDR_LEN,
00162 &entry.route_dst.addr_bits);
00163 entry.route_gw.addr_ip = rtentries[i].NextHop;
00164
00165 if ((ret = callback(&entry, arg)) != 0)
00166 break;
00167 }
00168 return (ret);
00169 }
00170
00171 route_t *
00172 route_close(route_t *r)
00173 {
00174 if (r != NULL) {
00175 if (r->fd >= 0)
00176 close(r->fd);
00177 free(r);
00178 }
00179 return (NULL);
00180 }