Ejemplo n.º 1
0
static switchlink_handle_t
process_oif_list(struct nlattr *attr, switchlink_handle_t vrf_h) {
    switchlink_db_status_t status;

    switchlink_db_oifl_info_t oifl_info;
    memset(&oifl_info, 0, sizeof(switchlink_db_oifl_info_t));

    struct rtnexthop *rnh = (struct rtnexthop *)nla_data(attr);
    int attrlen = nla_len(attr);
    while (RTNH_OK(rnh, attrlen)) {
        switchlink_db_interface_info_t ifinfo;
        memset(&ifinfo, 0, sizeof(switchlink_db_interface_info_t));
        status = switchlink_db_interface_get_info(rnh->rtnh_ifindex, &ifinfo);
        if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
            oifl_info.intfs[oifl_info.num_intfs++] = ifinfo.intf_h;
        }
        rnh = RTNH_NEXT(rnh);
    }

    if (!oifl_info.num_intfs) {
        return 0;
    }

    status = switchlink_db_oifl_get_info(&oifl_info);
    if (status == SWITCHLINK_DB_STATUS_ITEM_NOT_FOUND) {
        switchlink_db_oifl_add(&oifl_info);
    }

    return oifl_info.oifl_h;
}
Ejemplo n.º 2
0
Archivo: rtmsg.c Proyecto: t2mune/nield
/*
 * debug attribute RTA_MULTIPATH
 */
void debug_rta_multipath(int lev, struct rtmsg *rtm, struct rtattr *rta, const char *name)
{
    struct rtnexthop *rtnh;
    int rtnh_len = RTA_PAYLOAD(rta);
    struct rtattr *rtnha[__RTA_MAX];
    char ifname[IFNAMSIZ] = "";
    char flags_list[MAX_STR_SIZE] = "";

    if(debug_rta_len_chk(lev, rta, name, sizeof(*rtnh)))
        return;

    rec_dbg(lev, "%s(%hu):", name, RTA_ALIGN(rta->rta_len));

    for(rtnh = RTA_DATA(rta); RTNH_OK(rtnh, rtnh_len);
        rtnh = RTNH_NEXT(rtnh), rtnh_len -= RTNH_ALIGN(rtnh->rtnh_len)) {
        conv_rtnh_flags(rtnh->rtnh_flags, flags_list, sizeof(flags_list));
        if_indextoname_from_lists(rtnh->rtnh_ifindex, ifname);

        rec_dbg(lev, "    [ rtnexthop(%d) ]", sizeof(*rtnh));
        rec_dbg(lev, "        rtnh_len(%d): %hu",
            sizeof(rtnh->rtnh_len), rtnh->rtnh_len);
        rec_dbg(lev, "        rtnh_flags(%d): %d(%s)",
            sizeof(rtnh->rtnh_flags), rtnh->rtnh_flags, flags_list);
        rec_dbg(lev, "        rtnh_hops(%d): %d",
            sizeof(rtnh->rtnh_hops), rtnh->rtnh_hops);
        rec_dbg(lev, "        rtnh_ifindex(%d): %d(%s)",
            sizeof(rtnh->rtnh_ifindex), rtnh->rtnh_ifindex, ifname);

        parse_rtattr(rtnha, RTA_MAX, RTNH_DATA(rtnh), rtnh->rtnh_len - sizeof(*rtnh));

        if(rtnha[RTA_GATEWAY])
            debug_rta_af(lev+3, rtnha[RTA_GATEWAY], "RTA_GATEWAY", rtm->rtm_family);
    }
}
Ejemplo n.º 3
0
/*
 * parse_multipath_attr
 */
int
parse_multipath_attr (netlink_msg_ctx_t *ctx, struct rtattr *mpath_rtattr)
{
  size_t len, attr_len;
  struct rtnexthop *rtnh;
  struct rtattr *rtattrs[RTA_MAX + 1];
  struct rtattr *rtattr, *gateway;
  int if_index;
  const char *err_msg;

  rtnh = RTA_DATA(mpath_rtattr);
  len = RTA_PAYLOAD(mpath_rtattr);

  for (; len > 0; 
       len -= NLMSG_ALIGN(rtnh->rtnh_len), rtnh = RTNH_NEXT(rtnh)) {

    if (!RTNH_OK(rtnh, len)) {
      netlink_msg_ctx_set_err(ctx, "Malformed nh");
      return 0;
    }

    if (rtnh->rtnh_len <= sizeof(*rtnh)) {
      netlink_msg_ctx_set_err(ctx, "NH len too small");
      return 0;
    }

    /*
     * Parse attributes included in the nexthop.
     */
    err_msg = NULL;
    if (!parse_rtattrs_(RTNH_DATA(rtnh), rtnh->rtnh_len - sizeof(*rtnh),
			rtattrs, NUM_OF(rtattrs), &err_msg)) {
      netlink_msg_ctx_set_err(ctx, err_msg);
      return 0;
    }

    gateway = rtattrs[RTA_GATEWAY];
    netlink_msg_ctx_add_nh(ctx, rtnh->rtnh_ifindex, gateway);
  }

  return 1;
}
Ejemplo n.º 4
0
//db_route_t
bool nl_to_route_info(int rt_msg_type, struct nlmsghdr *hdr, cps_api_object_t obj) {

    struct rtmsg    *rtmsg = (struct rtmsg *)NLMSG_DATA(hdr);
    char            addr_str[INET6_ADDRSTRLEN];

    if(hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*rtmsg)))
        return false;

    if(rt_msg_type == RTM_NEWROUTE) {
        cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_MSG_TYPE,ROUTE_ADD);
    } else if(rt_msg_type == RTM_DELROUTE) {
        cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_MSG_TYPE,ROUTE_DEL);
    } else {
        return false;
    }

    cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_PROTOCOL,rtmsg->rtm_protocol);

    cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_FAMILY,rtmsg->rtm_family);


    int attr_len = nlmsg_attrlen(hdr,sizeof(*rtmsg));
    struct nlattr *head = nlmsg_attrdata(hdr, sizeof(struct rtmsg));

    struct nlattr *attrs[__IFLA_MAX];
    memset(attrs,0,sizeof(attrs));

    if (nla_parse(attrs,__IFLA_MAX,head,attr_len)!=0) {
        EV_LOG(ERR,ROUTE,0,"NL-ROUTE-PARSE","Failed to parse attributes");
        return false;
    }

    cps_api_key_init(cps_api_object_key(obj),cps_api_qualifier_TARGET,
            cps_api_obj_cat_ROUTE,cps_api_route_obj_ROUTE,0 );

    if(attrs[RTA_DST]!=NULL) {
        rta_add_ip((struct nlattr*)attrs[RTA_DST],rtmsg->rtm_family,
                obj,cps_api_if_ROUTE_A_PREFIX);
    }

    if((rtmsg->rtm_flags & RTM_F_CLONED) && (rtmsg->rtm_family == AF_INET6)) {
        // Skip cloned route updates
        char addr_str[INET6_ADDRSTRLEN];
        EV_LOG(INFO, NETLINK,3,"ROUTE-EVENT","Cache entry %s",
                (attrs[RTA_DST]!=NULL)?(inet_ntop(rtmsg->rtm_family,
                ((struct in6_addr *) nla_data((struct nlattr*)attrs[RTA_DST])),
                addr_str, INET6_ADDRSTRLEN)):"");
        return false;
    }

    cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_PREFIX_LEN,rtmsg->rtm_dst_len);
    size_t hop_count = 0;

    cps_api_attr_id_t ids[3];

    const int ids_len = sizeof(ids)/sizeof(*ids);
    ids[0] = cps_api_if_ROUTE_A_NH;
    ids[1] = hop_count;

    if (attrs[RTA_GATEWAY]!=NULL) {
        ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_ADDR;
        rta_add_e_ip((struct nlattr*)attrs[RTA_GATEWAY],
                rtmsg->rtm_family,obj, ids,ids_len);

        rta_add_ip((struct nlattr*)attrs[RTA_GATEWAY],rtmsg->rtm_family,obj,
                cps_api_if_ROUTE_A_NEXT_HOP_ADDR);
    }

    if (attrs[RTA_OIF]!=NULL) {
        ids[2] = cps_api_if_ROUTE_A_NH_IFINDEX;
        unsigned int *x = (unsigned int *) nla_data(attrs[RTA_OIF]);

        cps_api_object_e_add(obj,ids,ids_len,cps_api_object_ATTR_T_U32,
                nla_data(attrs[RTA_OIF]),sizeof(uint32_t));

        cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_NH_IFINDEX,*x);
    }
    nas_os_log_route_info(rt_msg_type, rtmsg, attrs);
    if (attrs[RTA_MULTIPATH]) {
        //array of next hops
        struct rtnexthop * rtnh = (struct rtnexthop * )nla_data(attrs[RTA_MULTIPATH]);
        int remaining = nla_len(attrs[RTA_MULTIPATH]);
        while (RTNH_OK(rtnh, remaining)) {
            ids[1] = hop_count;
            ids[2] = cps_api_if_ROUTE_A_NH_IFINDEX;
            uint32_t _int = rtnh->rtnh_ifindex;
            cps_api_object_e_add(obj,ids,ids_len,cps_api_object_ATTR_T_U32,
                    &rtnh->rtnh_ifindex,sizeof(uint32_t));

            _int = rtnh->rtnh_flags;
            ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_FLAGS;
            cps_api_object_e_add(obj,ids,ids_len,cps_api_object_ATTR_T_U32,
                    &_int,sizeof(uint32_t));

            ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_WEIGHT;
            _int = rtnh->rtnh_hops;
            cps_api_object_e_add(obj,ids,ids_len,cps_api_object_ATTR_T_U32,
                    &_int,sizeof(uint32_t));

            struct nlattr *nhattr[__RTA_MAX];
            memset(nhattr,0,sizeof(nhattr));
            nhrt_parse(nhattr,__IFLA_MAX,rtnh);
            if (nhattr[RTA_GATEWAY]) {
                ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_ADDR;
                rta_add_e_ip((struct nlattr*)nhattr[RTA_GATEWAY],
                             rtmsg->rtm_family,obj, ids,ids_len);
                EV_LOG(INFO, NETLINK,3,"ROUTE-EVENT","MultiPath nh-cnt:%d gateway:%s ifIndex:%d nh-flags:0x%x weight:%d",
                       hop_count,
                       ((rtmsg->rtm_family == AF_INET) ?
                        (inet_ntop(rtmsg->rtm_family, ((struct in_addr *) nla_data((struct nlattr*)nhattr[RTA_GATEWAY])), addr_str,
                                   INET_ADDRSTRLEN)) :
                        (inet_ntop(rtmsg->rtm_family, ((struct in6_addr *) nla_data((struct nlattr*)nhattr[RTA_GATEWAY])),
                                   addr_str, INET6_ADDRSTRLEN))),
                        rtnh->rtnh_ifindex, rtnh->rtnh_flags, rtnh->rtnh_hops);
            } else {
                EV_LOG(INFO, NETLINK,3,"ROUTE-EVENT","MultiPath nh-cnt:%d ifIndex:%d nh-flags:0x%x weight:%d",
                       hop_count, rtnh->rtnh_ifindex, rtnh->rtnh_flags, rtnh->rtnh_hops);
            }
            rtnh = rtnh_next(rtnh,&remaining);
            ++hop_count;
        }

    } else {
        ++hop_count;
    }
    cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_HOP_COUNT,hop_count);

    return true;
}
Ejemplo n.º 5
0
static switchlink_handle_t
process_ecmp(uint8_t family, struct nlattr *attr, switchlink_handle_t vrf_h) {
    switchlink_db_status_t status;

    if ((family != AF_INET) && (family != AF_INET6)) {
        return 0;
    }

    switchlink_db_ecmp_info_t ecmp_info;
    memset(&ecmp_info, 0, sizeof(switchlink_db_ecmp_info_t));

    struct rtnexthop *rnh = (struct rtnexthop *)nla_data(attr);
    int attrlen = nla_len(attr);
    while (RTNH_OK(rnh, attrlen)) {
        struct rtattr *rta = RTNH_DATA(rnh);
        if (rta->rta_type == RTA_GATEWAY) {
            switchlink_ip_addr_t gateway;
            memset(&gateway, 0, sizeof(switchlink_ip_addr_t));
            gateway.family = family;
            if (family == AF_INET) {
                gateway.ip.v4addr.s_addr = ntohl(*((uint32_t *)RTA_DATA(rta)));
                gateway.prefix_len = 32;
            } else {
                gateway.prefix_len = 128;
            }

            switchlink_db_interface_info_t ifinfo;
            memset(&ifinfo, 0, sizeof(switchlink_db_interface_info_t));
            status = switchlink_db_interface_get_info(rnh->rtnh_ifindex,
                                                      &ifinfo);
            if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
                switchlink_db_neigh_info_t neigh_info;
                memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t));
                memcpy(&(neigh_info.ip_addr), &gateway,
                       sizeof(switchlink_ip_addr_t));
                neigh_info.intf_h = ifinfo.intf_h;
                neigh_info.vrf_h = vrf_h;
                status = switchlink_db_neighbor_get_info(&neigh_info);
                if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
                    ecmp_info.nhops[ecmp_info.num_nhops] = neigh_info.nhop_h;
                } else {
                    ecmp_info.nhops[ecmp_info.num_nhops] = g_cpu_rx_nhop_h;
                }
                ecmp_info.num_nhops++;
                assert(ecmp_info.num_nhops < SWITCHLINK_ECMP_NUM_MEMBERS_MAX);
            }
        }
        rnh = RTNH_NEXT(rnh);
    }

    if (!ecmp_info.num_nhops) {
        return 0;
    }

    status = switchlink_db_ecmp_get_info(&ecmp_info);
    if (status == SWITCHLINK_DB_STATUS_ITEM_NOT_FOUND) {
        switchlink_ecmp_create(&ecmp_info);
        switchlink_db_ecmp_add(&ecmp_info);
    }

    return ecmp_info.ecmp_h;
}
Ejemplo n.º 6
0
static boolean_t addRoute(route_entry_t *entry) {

    static int skfd = -1;

#if !defined(freebsd8)
    struct rtentry rt;
#else
    struct ortentry rt;
#endif


    if (entry) {

        memset((char *) &rt, 0, sizeof (rt));

        rt.rt_flags |= RTF_UP;

        if (entry->mask == 0xffffffff) {

            rt.rt_flags |= RTF_HOST;

        }

#if !defined(freebsd8)

        rt.rt_metric = 0;

        ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = entry->mask;
        ((struct sockaddr_in *) &rt.rt_genmask)->sin_family = AF_INET;

        if (entry->iface[0] != '\0') {

            rt.rt_dev = entry->iface;

        }

#else


#endif

        ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = entry->dst;
        ((struct sockaddr_in *) &rt.rt_dst)->sin_family = AF_INET;

        ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = entry->gateway;
        ((struct sockaddr_in *) &rt.rt_gateway)->sin_family = AF_INET;

        rt.rt_flags |= RTF_GATEWAY;

#if !defined(freebsd8)

        if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
#else
        if ((skfd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
#endif

            DEBUGP(DERROR, "addRoute", "socket: %s", strerror(errno));
            return FALSE;

        }

#if !defined(freebsd8)

        if (ioctl(skfd, SIOCADDRT, &rt) < 0) {

            DEBUGP(DERROR, "addRoute", "ioctl: %s", strerror(errno));
            close(skfd);
            return FALSE;

        }

#else

        struct {
            struct rt_msghdr rtm;
            struct sockaddr addrs[RTAX_MAX];
        } r;

        memset(&r, 0, sizeof (r));

        r.rtm.rtm_version = RTM_VERSION;
        r.rtm.rtm_type = RTM_ADD;
        r.rtm.rtm_pid = getpid();
        r.rtm.rtm_seq = 0;

        struct sockaddr_in dst = {.sin_addr.s_addr = entry->dst, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in gw = {.sin_addr.s_addr = entry->gateway, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in mask = {.sin_addr.s_addr = entry->mask, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};


        memcpy(&r.addrs[RTAX_DST], &dst, dst.sin_len);
        memcpy(&r.addrs[RTAX_GATEWAY], &gw, gw.sin_len);
        memcpy(&r.addrs[RTAX_NETMASK], &mask, mask.sin_len);

        r.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
        r.rtm.rtm_flags = RTF_STATIC | RTF_GATEWAY;
        r.rtm.rtm_msglen = sizeof (r);

        if (entry->mask != 0xffffffff) {

            r.rtm.rtm_addrs |= RTA_NETMASK;

        } else {

            r.rtm.rtm_flags |= (RTF_HOST);

        }

        if (write(skfd, &r, r.rtm.rtm_msglen) != r.rtm.rtm_msglen) {

            DEBUGP(DERROR, "addRoute", "write: %s", strerror(errno));
            close(skfd);
            return FALSE;

        }

#endif

        close(skfd);

        return TRUE;

    }
    return FALSE;

}

static boolean_t delRoute(route_entry_t * entry) {

    static int skfd = -1;

#if !defined(freebsd8)
    struct rtentry rt;
#else
    struct ortentry rt;
#endif


    if (entry) {

        memset((char *) &rt, 0, sizeof (rt));

        rt.rt_flags |= RTF_UP;

        if (entry->mask == 0xffffffff) {

            rt.rt_flags |= RTF_HOST;

        }

#if !defined(freebsd8)

        rt.rt_metric = 0;

        ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = entry->mask;
        ((struct sockaddr_in *) &rt.rt_genmask)->sin_family = AF_INET;

        if (entry->iface[0] != '\0') {

            rt.rt_dev = entry->iface;

        }

#else


#endif

        ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = entry->dst;
        ((struct sockaddr_in *) &rt.rt_dst)->sin_family = AF_INET;

        ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = entry->gateway;
        ((struct sockaddr_in *) &rt.rt_gateway)->sin_family = AF_INET;

        rt.rt_flags |= RTF_GATEWAY;

#if !defined(freebsd8)

        if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
#else
        if ((skfd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
#endif

            DEBUGP(DERROR, "delRoute", "socket: %s", strerror(errno));
            return FALSE;

        }

#if !defined(freebsd8)

        if (ioctl(skfd, SIOCDELRT, &rt) < 0) {

            DEBUGP(DERROR, "delRoute", "ioctl: %s", strerror(errno));
            close(skfd);
            return FALSE;

        }

#else

        struct {
            struct rt_msghdr rtm;
            struct sockaddr addrs[RTAX_MAX];
        } r;

        memset(&r, 0, sizeof (r));

        r.rtm.rtm_version = RTM_VERSION;
        r.rtm.rtm_type = RTM_DELETE;
        r.rtm.rtm_pid = getpid();
        r.rtm.rtm_seq = 0;

        struct sockaddr_in dst = {.sin_addr.s_addr = entry->dst, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in gw = {.sin_addr.s_addr = entry->gateway, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in mask = {.sin_addr.s_addr = entry->mask, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};


        memcpy(&r.addrs[RTAX_DST], &dst, dst.sin_len);
        memcpy(&r.addrs[RTAX_GATEWAY], &gw, gw.sin_len);
        memcpy(&r.addrs[RTAX_NETMASK], &mask, mask.sin_len);

        r.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
        r.rtm.rtm_flags = RTF_DONE;
        r.rtm.rtm_msglen = sizeof (r);

        if (entry->mask != 0xffffffff) {

            r.rtm.rtm_addrs |= RTA_NETMASK;

        } else {

            r.rtm.rtm_flags |= (RTF_HOST);

        }

        if (write(skfd, &r, r.rtm.rtm_msglen) != r.rtm.rtm_msglen) {

            DEBUGP(DERROR, "delRoute", "write: %s", strerror(errno));
            close(skfd);
            return FALSE;

        }

#endif

        close(skfd);

        return TRUE;

    }
    return FALSE;

}

static list_t *routeLookup(route_entry_t *key) {

    list_t *result = NULL;
    int skfd = -1;

    if (key) {

#ifdef freebsd8

        struct ortentry rt;

        memset((char *) &rt, 0, sizeof (rt));

        rt.rt_flags |= RTF_UP;

        if (key->mask == 0xffffffff) {

            rt.rt_flags |= RTF_HOST;

        }

        rt.rt_flags |= RTF_GATEWAY;

        if ((skfd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {

            DEBUGP(DERROR, "routeLookup", "socket: %s", strerror(errno));
            return result;

        }

        struct {
            struct rt_msghdr rtm;
            struct sockaddr addrs[RTAX_MAX];
        } r;

        memset(&r, 0, sizeof (r));

        r.rtm.rtm_version = RTM_VERSION;
        r.rtm.rtm_type = RTM_GET;
        r.rtm.rtm_pid = getpid();
        r.rtm.rtm_seq = 0;

        struct sockaddr_in dst = {.sin_addr.s_addr = key->dst, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in mask = {.sin_addr.s_addr = key->mask, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};


        memcpy(&r.addrs[RTAX_DST], &dst, dst.sin_len);
        memcpy(&r.addrs[RTAX_NETMASK], &mask, mask.sin_len);

        r.rtm.rtm_addrs = RTA_DST;
        r.rtm.rtm_flags = RTF_DONE;
        r.rtm.rtm_msglen = sizeof (r);

        if (key->mask != 0xffffffff) {

            r.rtm.rtm_addrs |= RTA_NETMASK;

        } else {

            r.rtm.rtm_flags |= (RTF_HOST);

        }

        if (write(skfd, &r, r.rtm.rtm_msglen) != r.rtm.rtm_msglen) {

            DEBUGP(DERROR, "routeLookup", "write: %s", strerror(errno));
            close(skfd);
            return result;

        }

        result = I(List)->new();

        while (1) {


            if (read(skfd, (struct rt_msghdr *) &r, sizeof (r)) < 0) {

                DEBUGP(DERROR, "routeLookup", "read: %s", strerror(errno));
                close(skfd);
                break;

            }

            route_entry_t *e = calloc(1, sizeof (route_entry_t));

            e->gateway = ((struct sockaddr_in*) &r.addrs[RTAX_GATEWAY])->sin_addr.s_addr;

            I(List)->insert(result, I(ListItem)->new(e));

            if (r.rtm.rtm_flags & RTF_DONE) {

                break;

            }

        }

#endif

#ifdef linux

        struct {
            struct nlmsghdr n;
            struct rtmsg r;
            char buf[1024];
        } req;

        struct nhop {
            in_addr_t gw;
            char dev[IFNAMSIZ];
        };

        list_t *nhops = NULL;

        struct nlmsghdr *h;
        struct rtmsg *rtmp;
        struct rtattr *rtatp;
        int rtattrlen;
        int rval = -1;
        char buf[4096];
        char dev[IFNAMSIZ];
        in_addr_t src = 0;
        in_addr_t dst = 0;
        in_addr_t mask = 0;
        in_addr_t gw = 0;

        if ((skfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {

            DEBUGP(DERROR, "routeLookup", "socket: %s", strerror(errno));
            return FALSE;

        }

        memset(&req, 0, sizeof (req));
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct rtmsg));
        req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
        req.n.nlmsg_type = RTM_GETROUTE;
        req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len);

        if (send(skfd, &req, req.n.nlmsg_len, 0) < 0) {

            DEBUGP(DERROR, "routeLookup", "send: %s", strerror(errno));
            close(skfd);
            return result;

        }

        if ((rval = recv(skfd, buf, sizeof (buf), 0)) < 0) {

            DEBUGP(DERROR, "routeLookup", "recv: %s", strerror(errno));
            close(skfd);
            return result;

        }

        for (h = (struct nlmsghdr *) buf; NLMSG_OK(h, rval); h = NLMSG_NEXT(h, rval)) {

            rtmp = (struct rtmsg *) NLMSG_DATA(h);
            rtatp = (struct rtattr *) RTM_RTA(rtmp);
            rtattrlen = RTM_PAYLOAD(h);

            src = 0;
            dst = 0;
            mask = 0;
            gw = 0;


            if (result == NULL) {

                result = I(List)->new();

            }

            for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) {

                switch (rtatp->rta_type) {

                    case RTA_OIF:
                    {
                        int oif_index = *(int *) RTA_DATA(rtatp);

                        if_indextoname(oif_index, dev);
                        break;
                    }

                    case RTA_PREFSRC: src = *((in_addr_t *) RTA_DATA(rtatp));
                        break;
                    case RTA_DST: dst = *((in_addr_t *) RTA_DATA(rtatp));
                        mask = rtmp->rtm_dst_len != 0 ? htonl(~0 << (32 - rtmp->rtm_dst_len)) : 0;
                        break;
                    case RTA_GATEWAY: gw = *((in_addr_t *) RTA_DATA(rtatp));
                        break;

                    case RTA_MULTIPATH:
                    {

                        nhops = I(List)->new();

                        struct rtnexthop *nh = NULL;
                        
                        struct rtattr *nhrtattr = NULL;
                        int nh_len = RTA_PAYLOAD(rtatp);

                        for (nh = RTA_DATA(rtatp); RTNH_OK(nh, nh_len); nh = RTNH_NEXT(nh)) {

                            struct nhop *hop = calloc(1, sizeof (struct nhop));

                            int attr_len = nh->rtnh_len - sizeof (*nh);

                            if (nh_len < sizeof (*nh))
                                break;
                            if (nh->rtnh_len > nh_len)
                                break;

                            if (nh->rtnh_len > sizeof (*nh)) {

                                if_indextoname(nh->rtnh_ifindex, hop->dev);

                                for (nhrtattr = RTNH_DATA(nh); RTA_OK(nhrtattr, attr_len); nhrtattr = RTA_NEXT(nhrtattr, attr_len)) {

                                    switch (nhrtattr->rta_type) {

                                        case RTA_GATEWAY:
                                            hop->gw = *((in_addr_t *) RTA_DATA(nhrtattr));
                                            break;


                                    }

                                }

                                I(List)->insert(nhops, I(ListItem)->new(hop));

                            }

                            nh_len -= NLMSG_ALIGN(nh->rtnh_len);
                        }

                        break;
                    }

                }

            }

            if (nhops == NULL) {

                if (key && ((key->dst != dst) || (key->iface[0] != '\0' && strcmp(key->iface, dev) != 0))) {

                    continue;

                }

                route_entry_t *r = calloc(1, sizeof (route_entry_t));

                r->gateway = gw;
                r->mask = mask;
                r->dst = dst;
                r->src = src;
                strcpy(r->iface, dev);

                I(List)->insert(result, I(ListItem)->new(r));

            } else {

                struct nhop *h = NULL;
                list_item_t *item = NULL;

                while (item = I(List)->pop(nhops)) {

                    h = item->data;

                    if (key && ((key->dst != dst) || (key->iface[0] != '\0' && strcmp(key->iface, h->dev) != 0))) {

                        I(ListItem)->destroy(&item);
                        free(h);
                        continue;

                    }

                    route_entry_t *r = calloc(1, sizeof (route_entry_t));

                    r->gateway = h->gw;
                    r->mask = mask;
                    r->dst = dst;
                    r->src = src;
                    strcpy(r->iface, h->dev);

                    I(List)->insert(result, I(ListItem)->new(r));
                    I(ListItem)->destroy(&item);
                    free(h);

                }

                I(List)->destroy(&nhops);

            }

        }

#endif

        close(skfd);

        return result;

    }

    return result;

}

static list_t * cacheLookup(route_entry_t * dest) {

    list_t *result = NULL;

#if defined(linux)

    FILE *f = fopen("/proc/net/rt_cache", "r");

    if (f) {

        char buf[512];

        result = I(List)->new();

        fgets(buf, sizeof (buf), f); // skip header

        while (!feof(f)) {

            if (fgets(buf, sizeof (buf), f)) {

                list_t *fields = I(String)->tokenize(buf, "\t");

                int i = 0;
                list_item_t *item;

                route_entry_t *entry = calloc(1, sizeof (route_entry_t));

                while ((item = I(List)->pop(fields))) {

                    switch (i) {

                        case 0: strcpy(entry->iface, (char*) item->data);
                            break;
                        case 1: sscanf((char*) item->data, "%X", &entry->dst);
                            break;
                        case 2: sscanf((char*) item->data, "%X", &entry->gateway);
                            break;
                        case 7: sscanf((char*) item->data, "%X", &entry->src);
                            break;

                    }

                    free(item->data);
                    I(ListItem)->destroy(&item);
                    i++;

                }

                I(List)->destroy(&fields);

                if (dest) {

                    if (dest->dst && dest->dst != entry->dst) {

                        free(entry);
                        continue;

                    }

                }

                I(List)->insert(result, I(ListItem)->new(entry));


            }

        }

        fclose(f);

    }

#endif

    return result;

}

static boolean_t addHostRoute(in_addr_t dst, in_addr_t gw, char *iface) {

    route_entry_t route = {.dst = dst, .src = 0, .gateway = gw, .mask = 0xffffffff};
    boolean_t result = FALSE;

    if (iface)
        strcpy(route.iface, iface);
    else
        route.iface[0] = '\0';

    result = addRoute(&route);

    return result;

}

static boolean_t delHostRoute(in_addr_t dst, in_addr_t gw, char *iface) {

    route_entry_t route = {.dst = dst, .src = 0, .gateway = gw, .mask = 0xffffffff};
    boolean_t result = FALSE;

    if (iface)
        strcpy(route.iface, iface);
    else
        route.iface[0] = '\0';

    result = delRoute(&route);

    return result;

}

static in_addr_t getIfIP(char *iface) {

    in_addr_t result = 0;

    if (iface) {

        struct ifreq req;
        int sock = socket(AF_INET, SOCK_DGRAM, 0);

        memset(&req, 0, sizeof (struct ifreq));
        strcpy(req.ifr_name, iface);

        if (ioctl(sock, SIOCGIFADDR, &req) >= 0) {

            result = ((struct sockaddr_in *) &req.ifr_addr)->sin_addr.s_addr;

        } else {

            DEBUGP(DERROR, "getIfIP", "ioctl: %s", strerror(errno));

        }

        close(sock);

    }

    return result;

}

static in_addr_t getIfGW(char *iface) {

    route_entry_t route = {.dst = 0, .src = 0, .gateway = 0, .mask = 0};
    list_t *routes = NULL;
    in_addr_t result = 0;

    if (iface)
        strcpy(route.iface, iface);
    else
        route.iface[0] = '\0';

    routes = routeLookup(&route);

    if (routes) {

        if (I(List)->count(routes) > 0) {

            list_item_t *e = I(List)->pop(routes);
            route_entry_t *entry = (route_entry_t *) e->data;

            result = entry->gateway;

            free(entry);
            I(ListItem)->destroy(&e);

        }

        I(List)->clear(routes, TRUE);
        I(List)->destroy(&routes);

    }

    return result;

}

IMPLEMENT_INTERFACE(Route) = {

    .addRoute = addRoute,
    .delRoute = delRoute,
    .cacheLookup = cacheLookup,
    .addHostRoute = addHostRoute,
    .delHostRoute = delHostRoute,
    .getIfGW = getIfGW,
    .getIfIP = getIfIP

};
Ejemplo n.º 7
0
Archivo: rtmsg.c Proyecto: t2mune/nield
/*
 * parse route message
 */
int parse_rtmsg(struct nlmsghdr *nlh)
{
    struct rtmsg *rtm;
    int rtm_len;
    struct rtattr *rta[__RTA_MAX];
    char ipv[MAX_STR_SIZE] = "";
    char msg[MAX_MSG_SIZE] = "";
    char *mp = msg;
    int log_opts = get_log_opts();
    int res;

    /* debug nlmsghdr */
    if(log_opts & L_DEBUG)
        debug_nlmsg(0, nlh);

    /* get rtmsg */
    rtm_len = NLMSG_PAYLOAD(nlh, 0);
    if(rtm_len < sizeof(*rtm)) {
        rec_log("error: %s: rtmsg: length too short", __func__);
        return(1);
    }
    rtm = (struct rtmsg *)NLMSG_DATA(nlh);

    /* parse route attributes */
    parse_rtattr(rta, RTA_MAX, RTM_RTA(rtm), RTM_PAYLOAD(nlh));

    /* debug rtmsg */
    if(log_opts & L_DEBUG)
        debug_rtmsg(0, rtm, rta, rtm_len);

    /* check address family */
    char dst[INET6_ADDRSTRLEN] = "";
    if(rtm->rtm_family == AF_INET) {
        strcpy(ipv, "ipv4");
        strcpy(dst, "0.0.0.0");
    } else if(rtm->rtm_family == AF_INET6) {
        strcpy(ipv, "ipv6");
        strcpy(dst, "::");
    } else {
        rec_log("error: %s: unknown address family: %d",
                __func__, rtm->rtm_family);
        return(1);
    }

    /* convert from table id to table name */
    char table[MAX_STR_SIZE] = "";
    snprintf(table, sizeof(table), "%s", conv_rt_table(rtm->rtm_table, 0));
    if(!strncmp(table, "unknown", sizeof(table)))
        snprintf(table, sizeof(table), "%d", rtm->rtm_table);

    /* check route table id(other than RT_TABLE_LOCAL) */
    if(rtm->rtm_table == RT_TABLE_LOCAL)
        return(1);

    /* check route protocol(other than RTPROT_UNSPEC) */
    if(rtm->rtm_protocol == RTPROT_UNSPEC)
        return(1);
    
    /* check route flags(other then RTM_F_CLONED) */
    if(rtm->rtm_flags & RTM_F_CLONED)
        return(1);

    /* get destination prefix */
    if(rta[RTA_DST]) {
        res = inet_ntop_ifa(rtm->rtm_family, rta[RTA_DST], dst, sizeof(dst));
        if(res) {
            rec_log("error: %s: RTA_DST: %s", __func__,
                (res == 1) ? strerror(errno) : "payload too short");
            return(1);
        }
    }
    /* no RTA_DST attribute if destination is a default gateway */
    mp = add_log(msg, mp, "destination=%s/%d ", dst, rtm->rtm_dst_len);

    /* get source prefix */
    if(rta[RTA_SRC]) {
        char src[INET6_ADDRSTRLEN] = "";

        res = inet_ntop_ifa(rtm->rtm_family, rta[RTA_SRC], src, sizeof(src));
        if(res == 1) {
            rec_log("error: %s: RTA_SRC: %s", __func__,
                (res == 1) ? strerror(errno) : "payload too short");
            return(1);
        }
        mp = add_log(msg, mp, "source=%s/%d ", src, rtm->rtm_src_len);
    }

    /* get preferred source address */
    if(rta[RTA_PREFSRC]) {
        char prefsrc[INET6_ADDRSTRLEN] = "";

        res = inet_ntop_ifa(rtm->rtm_family, rta[RTA_PREFSRC], prefsrc, sizeof(prefsrc));
        if(res) {
            rec_log("error: %s: RTA_PREFSRC: %s", __func__,
                (res == 1) ? strerror(errno) : "payload too short");
            return(1);
        }
        mp = add_log(msg, mp, "preferred-source=%s ", prefsrc);
    }

    /* get tos */
    if(rtm->rtm_tos)
        mp = add_log(msg, mp, "tos=0x%.2x ", rtm->rtm_tos);

    /* get ingress interface */
    if(rta[RTA_IIF]) {
        unsigned iifindex;
        char iifname[IFNAMSIZ] = "";

        if(RTA_PAYLOAD(rta[RTA_IIF]) < sizeof(iifindex)) {
            rec_log("error: %s: RTA_IIF: payload too short", __func__);
            return(1);
        }
        iifindex = *((unsigned *)RTA_DATA(rta[RTA_IIF]));
        if_indextoname_from_lists(iifindex, iifname);

        mp = add_log(msg, mp, "in=%s ", iifname);
    }

    /* get gateway address */
    if(rta[RTA_GATEWAY]) {
        char nexthop[INET6_ADDRSTRLEN] = "";

        res = inet_ntop_ifa(rtm->rtm_family, rta[RTA_GATEWAY], nexthop, sizeof(nexthop));
        if(res) {
            rec_log("error: %s: RTA_GATEWAY: %s", __func__,
                (res == 1) ? strerror(errno) : "payload too short");
            return(1);
        }
        mp = add_log(msg, mp, "nexthop=%s ", nexthop);
    }

    /* get egress interface */
    if(rta[RTA_OIF]) {
        unsigned oifindex;
        char oifname[IFNAMSIZ] = "";

        if(RTA_PAYLOAD(rta[RTA_OIF]) < sizeof(oifindex)) {
            rec_log("error: %s: RTA_OIF: payload too short", __func__);
            return(1);
        }
        oifindex = *((unsigned *)RTA_DATA(rta[RTA_OIF]));
        if_indextoname_from_lists(oifindex, oifname);

        mp = add_log(msg, mp, "interface=%s ", oifname);
    }

    /* get priority(but metric) */
    char metric[MAX_STR_SIZE] = "";
    if(rta[RTA_PRIORITY]) {
        if(RTA_PAYLOAD(rta[RTA_PRIORITY]) < sizeof(int)) {
            rec_log("error: %s: RTA_PRIORITY: payload too short", __func__);
            return(1);
        }
        snprintf(metric, sizeof(metric), "metric=%d ", *((int *)RTA_DATA(rta[RTA_PRIORITY])));
    }

    /* convert route message type */
    char type[MAX_STR_SIZE] = "";
    snprintf(type, sizeof(type), "%s", conv_rtn_type(rtm->rtm_type, 0));

    /* convert route message protocol */
    char proto[MAX_STR_SIZE] = "";
    snprintf(proto, sizeof(proto), "%s", conv_rtprot(rtm->rtm_protocol, 0));

    /* get table id & name */
    if(rta[RTA_TABLE]) {
        int table_id = *(int *)RTA_DATA(rta[RTA_TABLE]);

        if(RTA_PAYLOAD(rta[RTA_TABLE]) < sizeof(int)) {
            rec_log("error: %s: RTA_TABLE: payload too short", __func__);
            return(1);
        }
        snprintf(table, sizeof(table), "%s", conv_rt_table(table_id, 0));
        if(!strncmp(table, "unknown", sizeof(table)))
            snprintf(table, sizeof(table), "%d", table_id);
    }

    /* get multipath */
    if(rta[RTA_MULTIPATH]) {
        struct rtnexthop *rtnh;
        int rtnh_len = RTA_PAYLOAD(rta[RTA_MULTIPATH]);
        struct rtattr *rtna[__RTA_MAX];
        char rtnh_ifname[IFNAMSIZ] = "";
        char rtnh_nexthop[INET6_ADDRSTRLEN] = "";

        if(RTA_PAYLOAD(rta[RTA_MULTIPATH]) < sizeof(*rtnh)) {
            rec_log("error: %s: RTA_MULTIPATH: payload too short", __func__);
            return(1);
        }
        rtnh = RTA_DATA(rta[RTA_MULTIPATH]);

        for(; RTNH_OK(rtnh, rtnh_len);
            rtnh = RTNH_NEXT(rtnh), rtnh_len -= RTNH_ALIGN(rtnh->rtnh_len)) {
            parse_rtattr(rtna, RTA_MAX, RTNH_DATA(rtnh), rtnh->rtnh_len - sizeof(*rtnh));

            if(rtna[RTA_GATEWAY]) {
                res = inet_ntop_ifa(rtm->rtm_family, rtna[RTA_GATEWAY],
                    rtnh_nexthop, sizeof(rtnh_nexthop));
                if(res) {
                    rec_log("error: %s: RTA_GATEWAY: %s", __func__,
                        (res == 1) ? strerror(errno) : "payload too short");
                    return(1);
                }
            }

            /* get interface name & logging routing table message */
            if_indextoname_from_lists(rtnh->rtnh_ifindex, rtnh_ifname);
            if(nlh->nlmsg_type == RTM_NEWROUTE)
                rec_log("%s route added: %snexthop=%s interface=%s "
                    "%sweight=%d type=%s protocol=%s table=%s",
                    ipv, msg, rtnh_nexthop, rtnh_ifname,
                    metric, rtnh->rtnh_hops+1, type, proto, table);
            else if(nlh->nlmsg_type == RTM_DELROUTE)
                rec_log("%s route deleted: %snexthop=%s interface=%s " 
                    "%sweight=%d type=%s protocol=%s table=%s",
                    ipv, msg, rtnh_nexthop, rtnh_ifname,
                    metric, rtnh->rtnh_hops+1, type, proto, table);
        }

        return(0);
    }

    /* logging routing message */
    if(nlh->nlmsg_type == RTM_NEWROUTE)
        rec_log("%s route added: %s%stype=%s protocol=%s table=%s",
            ipv, msg, metric, type, proto, table);
    else if(nlh->nlmsg_type == RTM_DELROUTE)
        rec_log("%s route deleted: %s%stype=%s proto=%s table=%s",
            ipv, msg, metric, type, proto, table);

    return(0);
}