/* * rule_flush_table_range_filter: rtnl_dump filter for * rule_flush_table_range() (see below) */ int rule_flush_table_range_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rtnl_handle rth2; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[RTA_MAX + 1]; u_int a = *(u_int *) arg; u_int b = *((u_int *) arg + 1); len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); if (tb[RTA_PRIORITY] && (r->rtm_table >= a && r->rtm_table <= b)) { n->nlmsg_type = RTM_DELRULE; n->nlmsg_flags = NLM_F_REQUEST; if (rtnl_open(&rth2, 0) < 0) return -1; if (rtnl_talk(&rth2, n, 0, 0, NULL, NULL, NULL) < 0) return -2; rtnl_close(&rth2); } return 0; }
static void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo) { struct rtmsg *rtMsg = (struct rtmsg *)NLMSG_DATA(nlHdr); if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN)) return; struct rtattr *rtAttr = (struct rtattr *)RTM_RTA(rtMsg); int rtLen = RTM_PAYLOAD(nlHdr); for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) { switch (rtAttr->rta_type) { case RTA_OIF: if_indextoname(*(int *)RTA_DATA(rtAttr), rtInfo->ifName); break; case RTA_GATEWAY: rtInfo->gateWay = *(in_addr *)RTA_DATA(rtAttr); break; case RTA_PREFSRC: rtInfo->srcAddr = *(in_addr *)RTA_DATA(rtAttr); break; case RTA_DST: rtInfo->dstAddr = *(in_addr *)RTA_DATA(rtAttr); break; } } }
bool route_table_mgr::parse_enrty(nlmsghdr *nl_header, route_val *p_val) { int len; struct rtmsg *rt_msg; struct rtattr *rt_attribute; // get route entry header rt_msg = (struct rtmsg *) NLMSG_DATA(nl_header); // we are not concerned about the local and default route table if (rt_msg->rtm_family != AF_INET || rt_msg->rtm_table == RT_TABLE_LOCAL || rt_msg->rtm_table == RT_TABLE_DEFAULT) return false; p_val->set_protocol(rt_msg->rtm_protocol); p_val->set_scope(rt_msg->rtm_scope); p_val->set_type(rt_msg->rtm_type); p_val->set_table_id(rt_msg->rtm_table); in_addr_t dst_mask = htonl(VMA_NETMASK(rt_msg->rtm_dst_len)); p_val->set_dst_mask(dst_mask); p_val->set_dst_pref_len(rt_msg->rtm_dst_len); len = RTM_PAYLOAD(nl_header); rt_attribute = (struct rtattr *) RTM_RTA(rt_msg); for (;RTA_OK(rt_attribute, len);rt_attribute=RTA_NEXT(rt_attribute,len)) { parse_attr(rt_attribute, p_val); } p_val->set_state(true); p_val->set_str(); return true; }
static int resolve_mac_from_cache_parse(struct ndmsg *ndmsg, size_t len_payload, struct ether_addr *mac_addr, uint8_t *l3addr, size_t l3_len) { int l3found, llfound; struct rtattr *rtattr; struct ether_addr mac_empty; l3found = 0; llfound = 0; memset(&mac_empty, 0, sizeof(mac_empty)); for (rtattr = RTM_RTA(ndmsg); RTA_OK(rtattr, len_payload); rtattr = RTA_NEXT(rtattr, len_payload)) { switch (rtattr->rta_type) { case NDA_DST: memcpy(l3addr, RTA_DATA(rtattr), l3_len); l3found = 1; break; case NDA_LLADDR: memcpy(mac_addr, RTA_DATA(rtattr), ETH_ALEN); if (memcmp(mac_addr, &mac_empty, sizeof(mac_empty)) == 0) llfound = 0; else llfound = 1; break; } } return l3found && llfound; }
static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rtnl_handle rth2; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[FRA_MAX+1]; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); if (tb[FRA_PRIORITY]) { n->nlmsg_type = RTM_DELRULE; n->nlmsg_flags = NLM_F_REQUEST; if (rtnl_open(&rth2, 0) < 0) return -1; if (rtnl_talk(&rth2, n, 0, 0, NULL) < 0) return -2; rtnl_close(&rth2); } return 0; }
/* * Add RTA_SRC or RTA_DST attribute to netlink query message. */ void netlink_query_add(char *msgbuf, int rta_type, ip_address *addr) { struct nlmsghdr *nlmsg; struct rtmsg *rtmsg; struct rtattr *rtattr; int len, rtlen; void *p; nlmsg = (struct nlmsghdr *)msgbuf; rtmsg = (struct rtmsg *)NLMSG_DATA(nlmsg); /* Find first empty attribute slot */ rtlen = RTM_PAYLOAD(nlmsg); rtattr = (struct rtattr *)RTM_RTA(rtmsg); while (RTA_OK(rtattr, rtlen)) rtattr = RTA_NEXT(rtattr, rtlen); /* Add attribute */ if (rtmsg->rtm_family == AF_INET) { len = 4; p = (void*)&addr->u.v4.sin_addr.s_addr; } else { len = 16; p = (void*)addr->u.v6.sin6_addr.s6_addr; } rtattr->rta_type = rta_type; rtattr->rta_len = sizeof(struct rtattr) + len; /* bytes */ memmove(RTA_DATA(rtattr), p, len); if (rta_type == RTA_SRC) rtmsg->rtm_src_len = len * 8; /* bits */ else rtmsg->rtm_dst_len = len * 8; nlmsg->nlmsg_len += rtattr->rta_len; }
static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf) { mifi_t vifi; struct uvif *v; struct rtattr *rta[RTA_MAX + 1]; if (rtm->rtm_type == RTN_LOCAL) { /* tracef(TRF_NETLINK, "NETLINK: local address"); */ log_msg(LOG_DEBUG, 0, "NETLINK: local address"); if ((rpf->iif = local_address(&rpf->source)) != MAXMIFS) { rpf->rpfneighbor = rpf->source; return TRUE; } return FALSE; } memset(&rpf->rpfneighbor, 0, sizeof(rpf->rpfneighbor)); /* initialized */ if (rtm->rtm_type != RTN_UNICAST) { /* tracef(TRF_NETLINK, "NETLINK: route type is %d", rtm->rtm_type); */ log_msg(LOG_DEBUG, 0, "NETLINK: route type is %d", rtm->rtm_type); return FALSE; } memset(rta, 0, sizeof(rta)); parse_rtattr(rta, RTA_MAX, RTM_RTA(rtm), msglen - sizeof(*rtm)); if (rta[RTA_OIF]) { int ifindex = *(int *) RTA_DATA(rta[RTA_OIF]); for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { if (v->uv_ifindex == ifindex) break; } if (vifi >= numvifs) { log_msg(LOG_WARNING, 0, "NETLINK: ifindex=%d, but no vif", ifindex); return FALSE; } /* tracef(TRF_NETLINK, "NETLINK: vif %d, ifindex=%d", vifi, ifindex);*/ log_msg(LOG_DEBUG, 0, "NETLINK: vif %d, ifindex=%d", vifi, ifindex); } else { log_msg(LOG_WARNING, 0, "NETLINK: no interface"); return FALSE; } if (rta[RTA_GATEWAY]) { struct in6_addr gw; memcpy(&gw,RTA_DATA(rta[RTA_GATEWAY]),sizeof(gw)); /* __u32 gw = *(__u32 *) RTA_DATA(rta[RTA_GATEWAY]); */ /* tracef(TRF_NETLINK, "NETLINK: gateway is %s", inet6_fmt(gw)); */ log_msg(LOG_DEBUG, 0, "NETLINK: gateway is %s", inet6_fmt(&gw)); init_sin6(&rpf->rpfneighbor); rpf->rpfneighbor.sin6_addr = gw; rpf->rpfneighbor.sin6_scope_id = v->uv_ifindex; } else rpf->rpfneighbor = rpf->source; rpf->iif = vifi; return TRUE; }
// gw and iface[IF_NAMESIZE] MUST be allocated int get_default_gw(struct in_addr *gw, char *iface) { struct rtmsg req; unsigned int nl_len; char buf[8192]; struct nlmsghdr *nlhdr; if (!gw || !iface) { return -1; } // Send RTM_GETROUTE request memset(&req, 0, sizeof(req)); int sock = send_nl_req(RTM_GETROUTE, 0, &req, sizeof(req)); // Read responses nl_len = read_nl_sock(sock, buf, sizeof(buf)); if (nl_len <= 0) { return -1; } // Parse responses nlhdr = (struct nlmsghdr *)buf; while (NLMSG_OK(nlhdr, nl_len)) { struct rtattr *rt_attr; struct rtmsg *rt_msg; int rt_len; int has_gw = 0; rt_msg = (struct rtmsg *) NLMSG_DATA(nlhdr); if ((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN)) { return -1; } rt_attr = (struct rtattr *) RTM_RTA(rt_msg); rt_len = RTM_PAYLOAD(nlhdr); while (RTA_OK(rt_attr, rt_len)) { switch (rt_attr->rta_type) { case RTA_OIF: if_indextoname(*(int *) RTA_DATA(rt_attr), iface); break; case RTA_GATEWAY: gw->s_addr = *(unsigned int *) RTA_DATA(rt_attr); has_gw = 1; break; } rt_attr = RTA_NEXT(rt_attr, rt_len); } if (has_gw) { return 0; } nlhdr = NLMSG_NEXT(nlhdr, nl_len); } return -1; }
static int handle_neigh_msg(struct nlmsghdr *nlh, int n) { struct rtattr *tb[NDA_MAX]; struct ndmsg *ndm = NLMSG_DATA(nlh); parse_rt_attrs(tb, NDA_MAX, RTM_RTA(ndm), RTM_PAYLOAD(nlh)); handle_neigh_attrs(ndm, tb, nlh->nlmsg_type); return 0; }
static int handle_route_msg(struct nlmsghdr *nlh, int n) { struct rtmsg *rtm = NLMSG_DATA(nlh); struct rtattr *tb[RTN_MAX]; parse_rt_attrs(tb, RTN_MAX, RTM_RTA(rtm), RTM_PAYLOAD(nlh)); handle_route_attrs(rtm, tb, nlh->nlmsg_type); return 0; }
int read_reply() { //string to hold content of the route // table (i.e. one entry) char dsts[24], gws[24], ifs[16], ms[24]; // outer loop: loops thru all the NETLINK // headers that also include the route entry // header nlp = (struct nlmsghdr *) buf; for(; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll)) { // get route entry header rtp = (struct rtmsg *) NLMSG_DATA(nlp); // we are only concerned about the // main route table if(rtp->rtm_table != RT_TABLE_MAIN) continue; // init all the strings bzero(dsts, sizeof(dsts)); bzero(gws, sizeof(gws)); bzero(ifs, sizeof(ifs)); bzero(ms, sizeof(ms)); // inner loop: loop thru all the attributes of // one route entry rtap = (struct rtattr *) RTM_RTA(rtp); rtl = RTM_PAYLOAD(nlp); for( ; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap,rtl)) { switch(rtap->rta_type) { // destination IPv4 address case RTA_DST: inet_ntop(AF_INET, RTA_DATA(rtap), dsts, 24); break; // next hop IPv4 address case RTA_GATEWAY: inet_ntop(AF_INET, RTA_DATA(rtap), gws, 24); break; // unique ID associated with the network // interface case RTA_OIF: sprintf(ifs, "%d", *((int *) RTA_DATA(rtap))); default: break; } } sprintf(ms, "%d", rtp->rtm_dst_len); test_msg("dst %s/%s gw %s if %s\n", dsts, ms, gws, ifs); } return 0; }
static void test_route(void) { _cleanup_rtnl_message_unref_ sd_rtnl_message *req; struct in_addr addr; uint32_t index = 2; uint16_t type; void *data; uint32_t u32_data; int r; struct rtmsg *rtm; r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET); if (r < 0) { log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r)); return; } addr.s_addr = htonl(INADDR_LOOPBACK); r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr); if (r < 0) { log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r)); return; } r = sd_rtnl_message_append_u32(req, RTA_OIF, index); if (r < 0) { log_error("Could not append RTA_OIF attribute: %s", strerror(-r)); return; } assert_se(rtnl_message_seal(NULL, req) >= 0); assert_se(sd_rtnl_message_read(req, &type, &data) > 0); assert_se(type == RTA_GATEWAY); assert_se(((struct in_addr *)data)->s_addr == addr.s_addr); assert_se(sd_rtnl_message_read(req, &type, &data) > 0); assert_se(type == RTA_OIF); assert_se(*(uint32_t *) data == index); rtm = NLMSG_DATA(req->hdr); r = rtnl_message_parse(req, &req->rta_offset_tb, &req->rta_tb_size, RTA_MAX, RTM_RTA(rtm), RTM_PAYLOAD(req->hdr)); assert_se(sd_rtnl_message_read_u32(req, RTA_GATEWAY, &u32_data) == 0); assert_se(sd_rtnl_message_read_u32(req, RTA_OIF, &u32_data) == 0); assert_se((req = sd_rtnl_message_unref(req)) == NULL); }
struct ip4_routing_table *parse_nlmsg(struct nlmsghdr *msg) { char dst_temp[IP4_ALEN]; char gw_temp[IP4_ALEN]; uint32_t priority; uint32_t interface; struct ip4_routing_table *table_pointer = NULL; switch (msg->nlmsg_type) { case NLMSG_ERROR: { struct nlmsgerr* errorMsg = (struct nlmsgerr*) NLMSG_DATA(msg); PRINT_DEBUG("recvd NLMSG_ERROR error seq:%d code:%d...", msg->nlmsg_seq, errorMsg->error); break; } case RTM_NEWROUTE: { struct rtmsg* rtm = (struct rtmsg*) NLMSG_DATA(msg); struct rtattr* rta = RTM_RTA(rtm); int rtaLen = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); if (rtm->rtm_type == RTN_UNICAST) // don't consider local, broadcast and unreachable routes { table_pointer = (struct ip4_routing_table*) secure_malloc(sizeof(struct ip4_routing_table)); for (; RTA_OK(rta, rtaLen); rta = RTA_NEXT(rta, rtaLen)) { switch (rta->rta_type) { case RTA_DST: //destination table_pointer->mask = rtm->rtm_dst_len; memcpy(dst_temp, RTA_DATA(rta), IP4_ALEN); //PRINT_DEBUG("received RTA_DST"); PRINT_DEBUG("dst_str = %u.%u.%u.%u", dst_temp[0] & 0xFF, dst_temp[1] & 0xFF, dst_temp[2] & 0xFF, dst_temp[3] & 0xFF); table_pointer->dst = IP4_ADR_P2H(dst_temp[0]&0xFF, dst_temp[1]&0xFF, dst_temp[2]&0xFF, dst_temp[3]&0xFF); break; case RTA_GATEWAY: //next hop table_pointer->mask = rtm->rtm_dst_len; memcpy(gw_temp, RTA_DATA(rta), IP4_ALEN); //PRINT_DEBUG("received RTA_GATEWAY"); PRINT_DEBUG("gw_str = %u.%u.%u.%u", gw_temp[0] & 0xFF, gw_temp[1] & 0xFF, gw_temp[2] & 0xFF, gw_temp[3] & 0xFF); table_pointer->gw = IP4_ADR_P2H(gw_temp[0]&0xFF, gw_temp[1]&0xFF, gw_temp[2]&0xFF, gw_temp[3]&0xFF); break; case RTA_OIF: //interface memcpy(&table_pointer->interface, RTA_DATA(rta), sizeof(interface)); //TODO won't work with current hack PRINT_DEBUG("interface:%u", table_pointer->interface); break; case RTA_PRIORITY: //metric memcpy(&table_pointer->metric, RTA_DATA(rta), sizeof(priority)); PRINT_DEBUG("metric:%u", table_pointer->metric); break; } //switch(rta->) } // for() } // if RTN_UNICAST return (table_pointer); } } //switch (msg->nlmsg_type) return (NULL); }
/* For parsing the route info returned */ static int parseRoutes(const char* ifName, struct nlmsghdr *nlHdr, struct route_info *rtInfo) { struct rtmsg *rtMsg; struct rtattr *rtAttr; int rtLen; int i_ret = ZQERROR; rtMsg = (struct rtmsg *)NLMSG_DATA(nlHdr); /* If the route is not for AF_INET or does not belong to main routing table then return. */ if((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN)) { ///NOTE , free must be called , otherwise memory leak will occur goto ExitPoint; } /* get the rtattr field */ rtAttr = (struct rtattr *)RTM_RTA(rtMsg); rtLen = RTM_PAYLOAD(nlHdr); for(;RTA_OK(rtAttr,rtLen);rtAttr = RTA_NEXT(rtAttr,rtLen)) { switch(rtAttr->rta_type) { case RTA_OIF: if_indextoname(*(int *)RTA_DATA(rtAttr), rtInfo->ifName); break; case RTA_GATEWAY: rtInfo->gateWay = *(u_int *)RTA_DATA(rtAttr); break; case RTA_PREFSRC: rtInfo->srcAddr = *(u_int *)RTA_DATA(rtAttr); break; case RTA_DST: rtInfo->dstAddr = *(u_int *)RTA_DATA(rtAttr); break; } } struct in_addr* p_dstAddr = (struct in_addr*)&rtInfo->dstAddr; struct in_addr* p_gateWay = (struct in_addr*)&rtInfo->gateWay; if ( !strcmp( ifName, rtInfo->ifName ) && strstr((char *)inet_ntoa(*p_dstAddr), "0.0.0.0")) { sprintf(gateway, (char *)inet_ntoa(*p_gateWay)); i_ret = ZQSUCCESS; } ExitPoint: return i_ret; }
/* function: get_default_route_cb * finds the default route with the request family and out interface and saves the gateway * msg - netlink message * data - (struct default_route_data) requested filters and response storage */ static int get_default_route_cb(struct nl_msg *msg, void *data) { struct rtmsg *rt_p; struct rtattr *rta_p; int rta_len; struct default_route_data *default_route = data; union anyip *this_gateway = NULL; ssize_t this_gateway_size; int this_interface_id = -1; if(default_route->reply_found_route) { // we already found our route return NL_OK; } rt_p = (struct rtmsg *)nlmsg_data(nlmsg_hdr(msg)); if(rt_p->rtm_dst_len != 0) { // not a default route return NL_OK; } if((rt_p->rtm_family != default_route->request_family) || (rt_p->rtm_table != RT_TABLE_MAIN)) { // not a route we care about return NL_OK; } rta_p = (struct rtattr *)RTM_RTA(rt_p); rta_len = RTM_PAYLOAD(nlmsg_hdr(msg)); for(; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) { switch(rta_p->rta_type) { case RTA_GATEWAY: this_gateway = RTA_DATA(rta_p); this_gateway_size = RTA_PAYLOAD(rta_p); break; case RTA_OIF: this_interface_id = *(int *)RTA_DATA(rta_p); break; default: break; } } if(this_interface_id == default_route->request_interface_id) { default_route->reply_found_route = 1; if(this_gateway != NULL) { memcpy(&default_route->reply_gateway, this_gateway, this_gateway_size); default_route->reply_has_gateway = 1; } else { default_route->reply_has_gateway = 0; } } return NL_OK; }
void parseRoutes (struct nlmsghdr *nlHdr, struct route_info *rtInfo, char *gateway) { struct rtmsg *rtMsg; struct rtattr *rtAttr; int rtLen; char *tempBuf = NULL; //2007-12-10 struct in_addr dst; struct in_addr gate; tempBuf = (char *)malloc (100); rtMsg = (struct rtmsg *)NLMSG_DATA (nlHdr); // If the route is not for AF_INET or does not belong to main routing table //then return. if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN)) { free (tempBuf); return; } /* get the rtattr field */ rtAttr = (struct rtattr *)RTM_RTA (rtMsg); rtLen = RTM_PAYLOAD (nlHdr); for (; RTA_OK (rtAttr, rtLen); rtAttr = RTA_NEXT (rtAttr, rtLen)) { switch (rtAttr->rta_type) { case RTA_OIF: if_indextoname (*(int *)RTA_DATA (rtAttr), rtInfo->ifName); break; case RTA_GATEWAY: rtInfo->gateWay = *(u_int *) RTA_DATA (rtAttr); break; case RTA_PREFSRC: rtInfo->srcAddr = *(u_int *) RTA_DATA (rtAttr); break; case RTA_DST: rtInfo->dstAddr = *(u_int *) RTA_DATA (rtAttr); break; } } //2007-12-10 dst.s_addr = rtInfo->dstAddr; /*lint !e632*/ if (strstr ((char *)inet_ntoa (dst), "0.0.0.0")) { gate.s_addr = rtInfo->gateWay; /*lint !e632*/ sprintf (gateway, (char *)inet_ntoa (gate)); } free (tempBuf); return; }
/** * Extract each route table entry and print */ static void netlink_parse_routes(struct rtmon_t *rtmon, char *b, int blen) { struct nlmsghdr *hdr = (struct nlmsghdr *) b; struct rtattr * attr; struct rtmon_route rt; int payload; for(; NLMSG_OK(hdr, blen); hdr = NLMSG_NEXT(hdr, blen)) { struct rtmsg * rtm = (struct rtmsg *) NLMSG_DATA(hdr); if (rtm->rtm_table != RT_TABLE_MAIN) continue; attr = (struct rtattr *) RTM_RTA(rtm); payload = RTM_PAYLOAD(hdr); memset(&rt, 0, sizeof(rt)); for (;RTA_OK(attr, payload); attr = RTA_NEXT(attr, payload)) { switch(attr->rta_type) { case RTA_DST: rt.destination = *(struct in_addr *)RTA_DATA(attr); break; case RTA_GATEWAY: rt.gateway = *(struct in_addr *)RTA_DATA(attr); break; case RTA_OIF: rt.if_index = *((int *) RTA_DATA(attr)); default: break; } } { uint32_t mask = 0; int i; for (i=0; i<rtm->rtm_dst_len; i++) { mask |= (1 << (32-i-1)); } rt.netmask.s_addr = htonl(mask); } rtmon_add_route(rtmon, &rt); } }
/* * parse_route_msg */ int parse_route_msg (netlink_msg_ctx_t *ctx) { int len; struct rtattr **rtattrs, *rtattr, *gateway, *oif; int if_index; ctx->rtmsg = NLMSG_DATA(ctx->hdr); len = ctx->hdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); if (len < 0) { netlink_msg_ctx_set_err(ctx, "Bad message length"); return 0; } if (!parse_rtattrs(ctx, RTM_RTA(ctx->rtmsg), len)) { return 0; } rtattrs = ctx->rtattrs; ctx->dest = rtattrs[RTA_DST]; ctx->src = rtattrs[RTA_PREFSRC]; rtattr = rtattrs[RTA_PRIORITY]; if (rtattr) { ctx->metric = (int *) RTA_DATA(rtattr); } gateway = rtattrs[RTA_GATEWAY]; oif = rtattrs[RTA_OIF]; if (gateway || oif) { if_index = 0; if (oif) { if_index = *((int *) RTA_DATA(oif)); } netlink_msg_ctx_add_nh(ctx, if_index, gateway); } rtattr = rtattrs[RTA_MULTIPATH]; if (rtattr) { parse_multipath_attr(ctx, rtattr); } return 1; }
static void nl_route(struct nlmsghdr *nlmsg) { struct rtmsg *r; struct rtattr *a; int la; int gw = 0, dst = 0, mask = 0, idx = 0; if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) { _e("Packet too small or truncated!"); return; } r = NLMSG_DATA(nlmsg); a = RTM_RTA(r); la = RTM_PAYLOAD(nlmsg); while (RTA_OK(a, la)) { void *data = RTA_DATA(a); switch (a->rta_type) { case RTA_GATEWAY: gw = *((int *)data); //_d("GW: 0x%04x", gw); break; case RTA_DST: dst = *((int *)data); mask = r->rtm_dst_len; //_d("MASK: 0x%04x", mask); break; case RTA_OIF: idx = *((int *)data); //_d("IDX: 0x%04x", idx); break; } a = RTA_NEXT(a, la); } if ((!dst && !mask) && (gw || idx)) { if (nlmsg->nlmsg_type == RTM_DELROUTE) cond_clear("net/route/default"); else cond_set("net/route/default"); } }
/* For parsing the route info returned */ void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo,char *gateway) { struct rtmsg *rtMsg; struct rtattr *rtAttr; int rtLen; char *tempBuf = NULL; tempBuf = (char *)malloc(100); rtMsg = (struct rtmsg *)NLMSG_DATA(nlHdr); /* If the route is not for AF_INET or does not belong to main routing table then return. */ if((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN)) return; /* get the rtattr field */ rtAttr = (struct rtattr *)RTM_RTA(rtMsg); rtLen = RTM_PAYLOAD(nlHdr); for(;RTA_OK(rtAttr,rtLen);rtAttr = RTA_NEXT(rtAttr,rtLen)){ switch(rtAttr->rta_type) { case RTA_OIF: if_indextoname(*(int *)RTA_DATA(rtAttr), rtInfo->ifName); break; case RTA_GATEWAY: rtInfo->gateWay = *(u_int *)RTA_DATA(rtAttr); break; case RTA_PREFSRC: rtInfo->srcAddr = *(u_int *)RTA_DATA(rtAttr); break; case RTA_DST: rtInfo->dstAddr = *(u_int *)RTA_DATA(rtAttr); break; } } //printf("%s\n", (char *)inet_ntoa(rtInfo->dstAddr)); // ADDED BY BOB - ALSO COMMENTED printRoute if (strstr((char *)inet_ntoa(rtInfo->dstAddr), "0.0.0.0")) sprintf(gateway, (char *)inet_ntoa(rtInfo->gateWay)); printRoute(rtInfo); free(tempBuf); return; }
bool route_table_mgr::rt_mgr_parse_enrty(nlmsghdr *nl_header, route_val *p_rtv) { int len; struct rtmsg *rt_msg; struct rtattr *rt_attribute; // get route entry header rt_msg = (struct rtmsg *) NLMSG_DATA(nl_header); // we are only concerned about the main route table if (rt_msg->rtm_family != AF_INET || rt_msg->rtm_table != RT_TABLE_MAIN) return false; p_rtv->set_protocol(rt_msg->rtm_protocol); p_rtv->set_scope(rt_msg->rtm_scope); p_rtv->set_type(rt_msg->rtm_type); in_addr_t dst_mask = htonl(VMA_NETMASK(rt_msg->rtm_dst_len)); p_rtv->set_dst_mask(dst_mask); p_rtv->set_dst_pref_len(rt_msg->rtm_dst_len); len = RTM_PAYLOAD(nl_header); rt_attribute = (struct rtattr *) RTM_RTA(rt_msg); for (;RTA_OK(rt_attribute, len);rt_attribute=RTA_NEXT(rt_attribute,len)) { rt_mgr_parse_attr(rt_attribute, p_rtv); } p_rtv->set_state(true); if (!p_rtv->get_src_addr()) { struct sockaddr_in src_addr; char *if_name = (char *)p_rtv->get_if_name(); if (!get_ipv4_from_ifname(if_name, &src_addr)) { p_rtv->set_src_addr(src_addr.sin_addr.s_addr); } else { // Failed mapping if_name to IPv4 address // Should we log or return error also from here? } } p_rtv->set_str(); return true; }
/* For parsing the route info returned */ void route_parse(struct nlmsghdr *nl_msg, struct route_info *rt_info) { struct rtmsg *rt_msg; struct rtattr *rt_attr; int rt_len = 0; rt_msg = (struct rtmsg *) NLMSG_DATA(nl_msg); /* If the route is not for AF_INET or does not belong to main routing table then return. */ if ((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN)) { return; } /* get the rtattr field */ rt_attr = (struct rtattr *) RTM_RTA(rt_msg); rt_len = RTM_PAYLOAD(nl_msg); for ( ; RTA_OK(rt_attr, rt_len); rt_attr = RTA_NEXT(rt_attr, rt_len)) { switch (rt_attr->rta_type) { case RTA_OIF: if_indextoname(*(int *) RTA_DATA(rt_attr), rt_info->if_name); break; case RTA_GATEWAY: rt_info->gateway.s_addr= *(u_int *) RTA_DATA(rt_attr); break; case RTA_PREFSRC: rt_info->src_addr.s_addr= *(u_int *) RTA_DATA(rt_attr); break; case RTA_DST: rt_info->dst_addr .s_addr= *(u_int *) RTA_DATA(rt_attr); break; } } //printf("%s\n", inet_ntoa(rt_info->dst_addr)); if (rt_info->dst_addr.s_addr == 0) { sprintf(gateway, "%s", (char *) inet_ntoa(rt_info->gateway)); } route_print(rt_info); return; }
static int link_neigh(struct dhcpcd_ctx *ctx, __unused struct interface *ifp, struct nlmsghdr *nlm) { struct ndmsg *r; struct rtattr *rta; size_t len; struct in6_addr addr6; int flags; if (nlm->nlmsg_type != RTM_NEWNEIGH && nlm->nlmsg_type != RTM_DELNEIGH) return 0; if (nlm->nlmsg_len < sizeof(*r)) return -1; r = NLMSG_DATA(nlm); rta = (struct rtattr *)RTM_RTA(r); len = RTM_PAYLOAD(nlm); if (r->ndm_family == AF_INET6) { flags = 0; if (r->ndm_flags & NTF_ROUTER) flags |= IPV6ND_ROUTER; if (nlm->nlmsg_type == RTM_NEWNEIGH && r->ndm_state & (NUD_REACHABLE | NUD_STALE | NUD_DELAY | NUD_PROBE | NUD_PERMANENT)) flags |= IPV6ND_REACHABLE; memset(&addr6, 0, sizeof(addr6)); while (RTA_OK(rta, len)) { switch (rta->rta_type) { case NDA_DST: memcpy(&addr6.s6_addr, RTA_DATA(rta), sizeof(addr6.s6_addr)); break; } rta = RTA_NEXT(rta, len); } ipv6nd_neighbour(ctx, &addr6, flags); } return 0; }
/** * Handle a netlink message. If this message is a routing table message and it * contains the default route, then either: * i) default_gateway is updated with the address of the gateway. * ii) if_index is updated with the interface index for the default route. * @param if_index[out] possibly updated with interface index for the default * route. * @param default_gateway[out] possibly updated with the default gateway. * @param nl_hdr the netlink message. */ void MessageHandler(int32_t *if_index, IPV4Address *default_gateway, const struct nlmsghdr *nl_hdr) { // Unless RTA_DST is provided, an RTA_GATEWAY or RTA_OIF attribute implies // it's the default route. IPV4Address gateway; int32_t index = Interface::DEFAULT_INDEX; bool is_default_route = true; // Loop over the attributes looking for RTA_GATEWAY and/or RTA_DST const rtmsg *rt_msg = reinterpret_cast<const rtmsg*>(NLMSG_DATA(nl_hdr)); if (rt_msg->rtm_family == AF_INET && rt_msg->rtm_table == RT_TABLE_MAIN) { int rt_len = RTM_PAYLOAD(nl_hdr); for (const rtattr* rt_attr = reinterpret_cast<const rtattr*>( RTM_RTA(rt_msg)); RTA_OK(rt_attr, rt_len); rt_attr = RTA_NEXT(rt_attr, rt_len)) { switch (rt_attr->rta_type) { case RTA_OIF: index = *(reinterpret_cast<int32_t*>(RTA_DATA(rt_attr))); break; case RTA_GATEWAY: gateway = IPV4Address( reinterpret_cast<const in_addr*>(RTA_DATA(rt_attr))->s_addr); break; case RTA_DST: IPV4Address dest( reinterpret_cast<const in_addr*>(RTA_DATA(rt_attr))->s_addr); is_default_route = dest.IsWildcard(); break; } } } if (is_default_route && (!gateway.IsWildcard() || index != Interface::DEFAULT_INDEX)) { *default_gateway = gateway; *if_index = index; } }
void linux_unicast_router::handle_route_event(bool isnew, nlmsghdr *hdr) { rtattr *tb[RTA_MAX + 1]; memset(tb, 0, sizeof(tb)); netlink_msg *msg = (netlink_msg *)hdr; if (msg->r.rtm_family != AF_INET6 || (msg->r.rtm_flags & RTM_F_CLONED) == RTM_F_CLONED) { return; } netlink_msg::parse_rtatable(tb, RTA_MAX, RTM_RTA(NLMSG_DATA(hdr)), hdr->nlmsg_len - NLMSG_LENGTH(sizeof(rtmsg))); if (tb[RTA_DST]) { lookup_result res; parse_prefix_rec(tb, msg->r.rtm_dst_len, msg->r.rtm_protocol, res); if (g_mrd->should_log(MESSAGE_SIG)) { g_mrd->log().xprintf( "(NETLINK) route event: %s route for " "%{Addr} with dev %i gw %{addr} prefsrc " "%{addr}\n", isnew ? "new" : "lost", res.dst, res.dev, res.nexthop, res.source); } if (res.protocol == RTPROT_UNSPEC || res.protocol == RTPROT_REDIRECT) return; if (filter_protos.find(res.protocol) != filter_protos.end()) { if (g_mrd->should_log(INTERNAL_FLOW)) g_mrd->log().xprintf("(LINUX) Filtered %s route for " "%{Addr} with dev %i gw %{addr} prefsrc " "%{addr} by policy.\n", isnew ? "new" : "lost", res.dst, res.dev, res.nexthop, res.source); } prefix_changed(isnew, res); } }
/* For parsing the route info returned */ static int parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo) { struct rtmsg *rtMsg; struct rtattr *rtAttr; int rtLen = 0; rtMsg = (struct rtmsg *) NLMSG_DATA(nlHdr); /* This must be an IPv4 (AF_INET) route */ if (rtMsg->rtm_family != AF_INET) return 1; /* This must be in main routing table */ if (rtMsg->rtm_table != RT_TABLE_MAIN) return 1; /* Attributes field*/ rtAttr = (struct rtattr *)RTM_RTA(rtMsg); rtLen = RTM_PAYLOAD(nlHdr); for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) { switch (rtAttr->rta_type) { case RTA_OIF: if_indextoname(*(int *) RTA_DATA(rtAttr), rtInfo->ifName); break; case RTA_GATEWAY: rtInfo->gateWay.s_addr = *(u_int *)RTA_DATA(rtAttr); break; case RTA_PREFSRC: rtInfo->srcAddr.s_addr = *(u_int *)RTA_DATA(rtAttr); break; case RTA_DST: rtInfo->dstAddr .s_addr = *(u_int *)RTA_DATA(rtAttr); break; } } return 0; }
void notify(const struct sockaddr_nl *nlp, struct nlmsghdr *nlmsgp) { int len; int host_len; unsigned char cmd; struct in_addr any; struct iovec iov[NUM_RESP]; struct rtmsg *rtmp; struct rtattr *attrs[RTA_MAX + 1]; switch (nlmsgp->nlmsg_type) { case RTM_NEWROUTE: cmd = RTM_CMD_ROUTE_ADD; break; case RTM_DELROUTE: cmd = RTM_CMD_ROUTE_DEL; break; default: error_reply("not a route"); return; } len = nlmsgp->nlmsg_len - NLMSG_LENGTH(sizeof(*nlmsgp)); if (len < 0) { error_reply("wrong message length"); return; } rtmp = NLMSG_DATA(nlmsgp); /* Don't notify routes added by ourselves. */ if (rtmp->rtm_protocol == RTPROT_ROUTEMACHINE) return; if (rtmp->rtm_table != RT_TABLE_MAIN) return; switch (rtmp->rtm_family) { case AF_INET: host_len = 4; break; case AF_INET6: host_len = 16; break; default: error_reply("bad message family"); return; } parse_attrs(attrs, RTM_RTA(rtmp), len); iov[CMD].iov_base = &cmd; iov[CMD].iov_len = 1; iov[MASK].iov_base = &rtmp->rtm_dst_len; iov[MASK].iov_len = 1; any.s_addr = INADDR_ANY; if (attrs[RTA_DST] != NULL) { iov[DST].iov_base = RTA_DATA(attrs[RTA_DST]); iov[DST].iov_len = (rtmp->rtm_dst_len + 7)/8; } else { iov[DST].iov_base = &any; iov[DST].iov_len = sizeof(any); } if (attrs[RTA_GATEWAY] != NULL) { iov[GW].iov_base = RTA_DATA(attrs[RTA_GATEWAY]); iov[GW].iov_len = host_len; } else { iov[GW].iov_base = &any; iov[GW].iov_len = sizeof(any); } if (attrs[RTA_PRIORITY] != NULL) { uint32_t prio = htonl(*(uint32_t *)RTA_DATA(attrs[RTA_PRIORITY])); iov[PRIO].iov_base = &prio; iov[PRIO].iov_len = 4; } else { uint32_t prio = htonl(0); iov[PRIO].iov_base = &prio; iov[PRIO].iov_len = 4; } writev(STDOUT_FILENO, iov, NUM_RESP); }
static int parse_v4_route( orc_options_t * options, struct nlmsghdr * nl_msg, orc_v4_route_t * entry) { struct rtmsg * rt_msg; struct rtattr * attr; int rtattr_len; int found_dst = 0; int found_dst_if = 0; rt_msg = (struct rtmsg *) NLMSG_DATA(nl_msg); /* extract the first attribute */ attr = (struct rtattr *) RTM_RTA(rt_msg); rtattr_len = RTM_PAYLOAD(nl_msg); if (rt_msg->rtm_family == AF_INET6) { /* TODO: add IPv6 support */ orc_debug("Ignoring IPv6 route update: IPv6 unsupported\n"); return 0; } /** FIXME: figure out if we should qualify on * rt_msg -> rtm_table == RT_TABLE_DEFAULT _or_ * rt_msg -> rtm_protocol == ??? _or_ * rt_msg -> rtm_scope == ??? */ /** ignore BROADCAST, LOCAL, ANYCAST, MULTICAST routes updates; * for now, just accept unicast routes */ if ( rt_msg -> rtm_type != RTN_UNICAST) return 0; orc_debug("Parsed IPv4 route Update: \n" " rtm_family = 0x%x\n" " rtm_dst_len = %d\n" " rtm_src_len = %d\n" " rtm_tos = 0x%x\n" " rtm_table = 0x%x\n" " rtm_protocol = 0x%x\n" " rtm_scope = 0x%x\n" " rtm_type = 0x%x\n" " rtm_flags = 0x%x\n", rt_msg -> rtm_family, rt_msg -> rtm_dst_len, rt_msg -> rtm_src_len, rt_msg -> rtm_tos, rt_msg -> rtm_table, rt_msg -> rtm_protocol, rt_msg -> rtm_scope, rt_msg -> rtm_type, rt_msg -> rtm_flags); bzero(entry, sizeof(*entry)); /* get the dest mask from main msg */ entry->dst_mask_len = rt_msg->rtm_dst_len; entry->src_mask_len = rt_msg->rtm_src_len; /** note: the RTA_NEXT() macro decrements rtattr_len each time */ for(; RTA_OK(attr, rtattr_len); attr = RTA_NEXT(attr, rtattr_len)) { switch (attr->rta_type) { case RTA_DST: memcpy( &entry->dst_ip, RTA_DATA(attr), sizeof(entry->dst_ip)); found_dst = 1; orc_debug("Parsed IPv4 route dst: " IPV4_FORMAT "/%d\n", IPV4_ADDR_PRINT(entry->dst_ip), entry->dst_mask_len); break; case RTA_SRC: memcpy( &entry->src_ip, RTA_DATA(attr), sizeof(entry->src_ip)); entry->src_route_valid = 1; /* FIXME: check RTA_IIF as well */ orc_debug("Parsed IPv4 route src: " IPV4_FORMAT "/%d\n", IPV4_ADDR_PRINT(entry->src_ip), entry->src_mask_len); break; case RTA_IIF: memcpy( &entry->src_if_index, RTA_DATA(attr), sizeof(entry->src_if_index)); orc_debug("Parsed IPv4 route IIF index: %d\n", entry->src_if_index); break; case RTA_OIF: memcpy( &entry->dst_if_index, RTA_DATA(attr), sizeof(entry->dst_if_index)); found_dst_if = 1; orc_debug("Parsed IPv4 route OIF index: %d\n", entry->dst_if_index); break; case RTA_GATEWAY: memcpy( &entry->gateway, RTA_DATA(attr), sizeof(entry->gateway)); entry->gateway_valid = 1; orc_debug("Parsed IPv4 route gateway: " IPV4_FORMAT "\n", IPV4_ADDR_PRINT(entry->gateway)); break; case RTA_PREFSRC: orc_trace("Skipping unhandled RTA_PREFSRC route attr\n"); break; case RTA_TABLE: orc_trace("Skipping unhandled RTA_TABLE route attr\n"); break; default: /** TODO: decide if we actually need anything else from here */ orc_warn("Skipping unhandled ipv4 route attr: %d\n", attr->rta_type); } } if (found_dst && found_dst_if) entry->dst_route_valid = 1; return entry->dst_route_valid; }
/* Our rt netlink filter */ int rt_filter(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rt_entry *rtarg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[RTA_MAX+1]; struct rt_entry *entry; rtarg = (struct rt_entry *)arg; /* Just lookup the Main routing table */ if (r->rtm_table != RT_TABLE_MAIN) return 0; /* init len value */ len -= NLMSG_LENGTH(sizeof(*r)); if (len <0) { printf("BUG: wrong nlmsg len %d\n", len); return -1; } /* init the parse attribute space */ memset(tb, 0, sizeof(tb)); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); /* * we return from filter when route is * cloned from another route, learn by an * ICMP redirect or set by kernel. * Return too when rt type != gateway or direct route. */ if (r->rtm_flags & RTM_F_CLONED) return 0; if (r->rtm_protocol == RTPROT_REDIRECT) return 0; if (r->rtm_protocol == RTPROT_KERNEL) return 0; if (r->rtm_type != RTN_UNICAST) return 0; if (tb[RTA_OIF]) { /* alloc new memory entry */ entry = rt_new(); /* copy the rtmsg infos */ memcpy(entry->rtm, r, sizeof(struct rtmsg)); /* * can use RTA_PAYLOAD(tb[RTA_SRC]) * but ipv4 addr are 4 bytes coded */ entry->oif = *(int *) RTA_DATA(tb[RTA_OIF]); if (tb[RTA_SRC]) memcpy(&entry->src, RTA_DATA(tb[RTA_SRC]), 4); if (tb[RTA_PREFSRC]) memcpy(&entry->psrc, RTA_DATA(tb[RTA_PREFSRC]), 4); if (tb[RTA_DST]) memcpy(&entry->dest, RTA_DATA(tb[RTA_DST]), 4); if (tb[RTA_GATEWAY]) memcpy(&entry->gate, RTA_DATA(tb[RTA_GATEWAY]), 4); if (tb[RTA_FLOW]) memcpy(&entry->flow, RTA_DATA(tb[RTA_FLOW]), 4); if (tb[RTA_IIF]) entry->iif = *(int *) RTA_DATA(tb[RTA_IIF]); if (tb[RTA_PRIORITY]) entry->prio = *(int *) RTA_DATA(tb[RTA_PRIORITY]); if (tb[RTA_METRICS]) entry->metrics = *(int *) RTA_DATA(tb[RTA_METRICS]); /* save this entry */ rtarg = rt_append(rtarg, entry); } return 0; }
static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rtnl_handle rth2; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[IFAL_MAX+1]; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len); if (tb[IFAL_ADDRESS]) { n->nlmsg_type = RTM_DELADDRLABEL; n->nlmsg_flags = NLM_F_REQUEST; if (rtnl_open(&rth2, 0) < 0) return -1; if (rtnl_talk(&rth2, n, NULL, 0) < 0) return -2; rtnl_close(&rth2); } return 0; }