+
+ memset (rt, '\0', sizeof (struct rtentry));
+
+ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
+ return 0;
+
+ p = route_buffer;
+ for (col = 0; col < route_num_cols; ++col) {
+ cols[col] = strtok(p, route_delims);
+ if (cols[col] == NULL)
+ return 0; /* didn't get enough columns */
+ p = NULL;
+ }
+
+ SIN_ADDR(rt->rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
+ SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
+ SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
+
+ rt->rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16);
+ rt->rt_metric = (short) strtoul(cols[route_metric_col], NULL, 10);
+ rt->rt_dev = cols[route_dev_col];
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * defaultroute_exists - determine if there is a default route
+ * with the given metric (or negative for any)
+ */
+
+static int defaultroute_exists (struct rtentry *rt, int metric)
+{
+ int result = 0;
+
+ if (!open_route_table())
+ return 0;
+
+ while (read_route_table(rt) != 0) {
+ if ((rt->rt_flags & RTF_UP) == 0)
+ continue;
+
+ if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
+ continue;
+ if (SIN_ADDR(rt->rt_dst) == 0L && (metric < 0
+ || rt->rt_metric == metric)) {
+ result = 1;
+ break;
+ }
+ }
+
+ close_route_table();
+ return result;
+}
+
+/*
+ * have_route_to - determine if the system has any route to
+ * a given IP address. `addr' is in network byte order.
+ * Return value is 1 if yes, 0 if no, -1 if don't know.
+ * For demand mode to work properly, we have to ignore routes
+ * through our own interface.
+ */
+int have_route_to(u_int32_t addr)
+{
+ struct rtentry rt;
+ int result = 0;
+
+ if (!open_route_table())
+ return -1; /* don't know */
+
+ while (read_route_table(&rt)) {
+ if ((rt.rt_flags & RTF_UP) == 0 || strcmp(rt.rt_dev, ifname) == 0)
+ continue;
+ if ((addr & SIN_ADDR(rt.rt_genmask)) == SIN_ADDR(rt.rt_dst)) {
+ result = 1;
+ break;
+ }
+ }
+
+ close_route_table();
+ return result;
+}
+
+/********************************************************************
+ *
+ * sifdefaultroute - assign a default route through the address given.
+ */
+
+int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
+{
+ struct rtentry rt;
+
+ if (defaultroute_exists(&rt, dfl_route_metric) && strcmp(rt.rt_dev, ifname) != 0) {
+ if (rt.rt_flags & RTF_GATEWAY)
+ error("not replacing existing default route via %I with metric %d",
+ SIN_ADDR(rt.rt_gateway), dfl_route_metric);
+ else
+ error("not replacing existing default route through %s with metric %d",
+ rt.rt_dev, dfl_route_metric);
+ return 0;
+ }
+
+ memset (&rt, 0, sizeof (rt));
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+
+ rt.rt_dev = ifname;
+ rt.rt_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = 0L;
+ }
+
+ rt.rt_flags = RTF_UP;
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+
+ have_default_route = 1;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cifdefaultroute - delete a default route through the address given.
+ */
+
+int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
+{
+ struct rtentry rt;
+
+ have_default_route = 0;
+
+ memset (&rt, '\0', sizeof (rt));
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+ rt.rt_dev = ifname;
+
+ rt.rt_dev = ifname;
+ rt.rt_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = 0L;
+ }
+
+ rt.rt_flags = RTF_UP;
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp()) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+#ifdef INET6
+/*
+ * /proc/net/ipv6_route parsing stuff.
+ */
+static int route_dest_plen_col;
+static int open_route6_table (void);
+static int read_route6_table (struct in6_rtmsg *rt);
+
+/********************************************************************
+ *
+ * open_route6_table - open the interface to the route table
+ */
+static int open_route6_table (void)
+{
+ char *path;
+
+ close_route_table();
+
+ path = path_to_procfs("/net/ipv6_route");
+ route_fd = fopen (path, "r");
+ if (route_fd == NULL) {
+ error("can't open routing table %s: %m", path);
+ return 0;
+ }
+
+ /* default to usual columns */
+ route_dest_col = 0;
+ route_dest_plen_col = 1;
+ route_gw_col = 4;
+ route_metric_col = 5;
+ route_flags_col = 8;
+ route_dev_col = 9;
+ route_num_cols = 10;
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * read_route6_table - read the next entry from the route table
+ */
+
+static void hex_to_in6_addr(struct in6_addr *addr, const char *s)
+{
+ char hex8[9];
+ unsigned i;
+ uint32_t v;
+
+ hex8[8] = 0;
+ for (i = 0; i < 4; i++) {
+ memcpy(hex8, s + 8*i, 8);
+ v = strtoul(hex8, NULL, 16);
+ addr->s6_addr32[i] = v;
+ }
+}
+
+static int read_route6_table(struct in6_rtmsg *rt)
+{
+ char *cols[ROUTE_MAX_COLS], *p;
+ int col;
+
+ memset (rt, '\0', sizeof (struct in6_rtmsg));