/* * returns: -1 - address not found, 0 - addr is ok, 1 - addr is tentative */ int is_addr_tentative(char * ifacename, int iface, char * addr) { char buf[256]; char packed1[16]; char packed2[16]; struct rtattr * rta_tb[IFA_MAX+1]; struct nlmsg_list *ainfo = NULL; struct nlmsg_list *head = NULL; struct rtnl_handle rth; int tentative = LOWLEVEL_TENTATIVE_DONT_KNOW; inet_pton6(addr,packed1); rtnl_open(&rth, 0); /* 2nd attribute: AF_UNSPEC, AF_INET, AF_INET6 */ /* rtnl_wilddump_request(&rth, AF_PACKET, RTM_GETLINK); */ rtnl_wilddump_request(&rth, AF_INET6, RTM_GETADDR); rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL); head = ainfo; while (ainfo) { struct nlmsghdr *n = &ainfo->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); memset(rta_tb, 0, sizeof(*rta_tb)); if (ifa->ifa_index == iface && ifa->ifa_family==AF_INET6) { parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; inet_ntop6(RTA_DATA(rta_tb[IFA_LOCAL]), buf /*, sizeof(buf)*/); memcpy(packed2,RTA_DATA(rta_tb[IFA_LOCAL]),16); /* print_packed(packed1); printf(" "); print_packed(packed2); printf("\n"); */ /* is this addr which are we looking for? */ if (!memcmp(packed1,packed2,16) ) { if (ifa->ifa_flags & IFA_F_TENTATIVE) tentative = LOWLEVEL_TENTATIVE_YES; else tentative = LOWLEVEL_TENTATIVE_NO; } } ainfo = ainfo->next; } /* now delete list */ while (head) { ainfo = head; head = head->next; free(ainfo); } rtnl_close(&rth); return tentative; }
static void g_pn_nl_addr(GPhonetNetlink *self, struct nlmsghdr *nlh) { int len; uint8_t local = 0xff; uint8_t remote = 0xff; const struct ifaddrmsg *ifa; const struct rtattr *rta; ifa = NLMSG_DATA(nlh); len = IFA_PAYLOAD(nlh); /* If Phonet is absent, kernel transmits other families... */ if (ifa->ifa_family != AF_PHONET) return; if (ifa->ifa_index != self->interface) return; for (rta = IFA_RTA(ifa); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { if (rta->rta_type == IFA_LOCAL) local = *(uint8_t *)RTA_DATA(rta); else if (rta->rta_type == IFA_ADDRESS) remote = *(uint8_t *)RTA_DATA(rta); } }
void linux_unicast_router::handle_addr_event(bool isnew, nlmsghdr *hdr) { ifaddrmsg *ifa = (ifaddrmsg *)NLMSG_DATA(hdr); if (ifa->ifa_family == AF_INET6) { rtattr *tb[IFA_MAX + 1]; memset(tb, 0, sizeof(tb)); netlink_msg::parse_rtatable(tb, IFA_MAX, IFA_RTA(ifa), hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); rtattr *arta = tb[IFA_LOCAL]; if (!arta) arta = tb[IFA_ADDRESS]; if (arta) { inet6_addr addr; memcpy(&addr.addr, RTA_DATA(arta), RTA_PAYLOAD(arta)); addr.prefixlen = ifa->ifa_prefixlen; if (addr.type() & (inet6_addr::multicast | inet6_addr::network)) return; if (addr.is_any()) return; interface *intf = g_mrd->get_interface_by_index(ifa->ifa_index); if (intf) { intf->address_added_or_removed(isnew, addr); } } } }
int TunnelIPv6Interface::process(void) { uint8_t buffer[1024]; ssize_t buffer_len(-1); if (mNetlinkFD >= 0) { buffer_len = recv(mNetlinkFD, buffer, sizeof(buffer), 0); } if (buffer_len > 0) { struct nlmsghdr *nlp; struct rtmsg *rtp; int rta_len; struct rtattr *rta; nlp = (struct nlmsghdr *)buffer; for (;NLMSG_OK(nlp, buffer_len); nlp=NLMSG_NEXT(nlp, buffer_len)) { if (nlp->nlmsg_type == RTM_NEWADDR || nlp->nlmsg_type == RTM_DELADDR) { struct ifaddrmsg *ifaddr = (struct ifaddrmsg *)NLMSG_DATA(nlp); char ifnamebuf[IF_NAMESIZE]; const char *ifname = if_indextoname(ifaddr->ifa_index, ifnamebuf); struct in6_addr addr; if ((ifname == NULL) || (get_interface_name() != ifname)) { continue; } // get RTNETLINK message header // get start of attributes rta = (struct rtattr *) IFA_RTA(ifaddr); // get length of attributes rta_len = IFA_PAYLOAD(nlp); for(;RTA_OK(rta, rta_len); rta = RTA_NEXT(rta, rta_len)) { switch(rta->rta_type) { case IFA_ADDRESS: case IFA_LOCAL: case IFA_BROADCAST: case IFA_ANYCAST: memcpy(addr.s6_addr, RTA_DATA(rta), sizeof(addr)); if (nlp->nlmsg_type == RTM_NEWADDR) { mAddressWasAdded(addr, ifaddr->ifa_prefixlen); } else if (nlp->nlmsg_type == RTM_DELADDR) { mAddressWasRemoved(addr, ifaddr->ifa_prefixlen); } break; default: break; } } } } } return nl::UnixSocket::process(); }
static int parse_addr_rta(struct ifaddrmsg *addr, int len, struct in6_addr *res) { struct rtattr *rta; len -= NLMSG_ALIGN(sizeof(*addr)); rta = IFA_RTA(addr); while (RTA_OK(rta, len)) { switch(rta->rta_type) { case IFA_LOCAL: case IFA_ADDRESS: switch (addr->ifa_family) { case AF_INET: if (res) v4tov6(res->s6_addr, RTA_DATA(rta)); break; case AF_INET6: if (res) memcpy(res->s6_addr, RTA_DATA(rta), 16); break; default: kdebugf("ifaddr: unexpected address family %d\n", addr->ifa_family); return -1; break; } break; default: break; } rta = RTA_NEXT(rta, len); } return 0; }
/* Add remote address */ static int netlink_addroute(uint32_t ifa_index, uint8_t remote) { struct rtmsg *rtm; struct rtattr *rta; uint32_t reqlen = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(*rtm)) + RTA_SPACE(1) + RTA_SPACE(sizeof(ifa_index))); struct req { struct nlmsghdr nlh; char buf[512]; } req = { .nlh = { .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_APPEND, .nlmsg_type = RTM_NEWROUTE, .nlmsg_pid = getpid(), .nlmsg_len = reqlen, }, }; size_t buflen = sizeof(req.buf) - sizeof(*rtm); int fd; int error; struct sockaddr_nl addr = { .nl_family = AF_NETLINK, }; rtm = NLMSG_DATA(&req.nlh); rtm->rtm_family = AF_PHONET; rtm->rtm_dst_len = 6; rtm->rtm_src_len = 0; rtm->rtm_tos = 0; rtm->rtm_table = RT_TABLE_MAIN; rtm->rtm_protocol = RTPROT_STATIC; rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_type = RTN_UNICAST; rtm->rtm_flags = 0; rta = IFA_RTA(rtm); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(1); *(uint8_t *)RTA_DATA(rta) = remote; rta = RTA_NEXT(rta, buflen); rta->rta_type = RTA_OIF; rta->rta_len = RTA_LENGTH(sizeof(ifa_index)); *(uint32_t *)RTA_DATA(rta) = ifa_index; fd = netlink_socket(); if (fd == -1) return -errno; if (sendto(fd, &req, reqlen, 0, (void *)&addr, sizeof(addr)) == -1) error = -errno; else error = netlink_getack(fd); close(fd); return error; }
int addr_do(const struct in6_addr *addr, int plen, int ifindex, void *arg, int (*do_callback)(struct ifaddrmsg *ifa, struct rtattr *rta_tb[], void *arg)) { uint8_t sbuf[256]; uint8_t rbuf[256]; struct nlmsghdr *sn, *rn; struct ifaddrmsg *ifa; int err; struct rtattr *rta_tb[IFA_MAX+1]; memset(sbuf, 0, sizeof(sbuf)); sn = (struct nlmsghdr *)sbuf; sn->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); sn->nlmsg_flags = NLM_F_REQUEST; sn->nlmsg_type = RTM_GETADDR; ifa = NLMSG_DATA(sn); ifa->ifa_family = AF_INET6; ifa->ifa_prefixlen = plen; ifa->ifa_scope = RT_SCOPE_UNIVERSE; ifa->ifa_index = ifindex; addattr_l(sn, sizeof(sbuf), IFA_LOCAL, addr, sizeof(*addr)); memset(rbuf, 0, sizeof(rbuf)); rn = (struct nlmsghdr *)rbuf; err = rtnl_route_do(sn, rn); if (err < 0) { rn = sn; ifa = NLMSG_DATA(rn); } else { ifa = NLMSG_DATA(rn); if (rn->nlmsg_type != RTM_NEWADDR || rn->nlmsg_len < NLMSG_LENGTH(sizeof(*ifa)) || ifa->ifa_family != AF_INET6) { return -EINVAL; } } memset(rta_tb, 0, sizeof(rta_tb)); parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), rn->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; if (!rta_tb[IFA_ADDRESS] || !IN6_ARE_ADDR_EQUAL(RTA_DATA(rta_tb[IFA_ADDRESS]), addr)) { return -EINVAL; } if (do_callback) err = do_callback(ifa, rta_tb, arg); return err; }
static int read_iface_prefix(const char *ip_str, int is_ipv6) { uint8_t family = is_ipv6 ? AF_INET6 : AF_INET; char buf[16384]; unsigned int len; struct { struct nlmsghdr nlhdr; struct ifaddrmsg addrmsg; } msg; struct nlmsghdr *retmsg; int sock = SAFE_SOCKET(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); memset(&msg, 0, sizeof(msg)); msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; msg.nlhdr.nlmsg_type = RTM_GETADDR; msg.addrmsg.ifa_family = family; SAFE_SEND(1, sock, &msg, msg.nlhdr.nlmsg_len, 0); len = recv(sock, buf, sizeof(buf), 0); retmsg = (struct nlmsghdr *)buf; while NLMSG_OK(retmsg, len) { char ifname[IFNAMSIZ]; struct ifaddrmsg *retaddr; struct rtattr *retrta; char pradd[128]; int attlen; retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg); retrta = (struct rtattr *)IFA_RTA(retaddr); attlen = IFA_PAYLOAD(retmsg); while RTA_OK(retrta, attlen) { if (retrta->rta_type == IFA_ADDRESS) { inet_ntop(family, RTA_DATA(retrta), pradd, sizeof(pradd)); if_indextoname(retaddr->ifa_index, ifname); if (!strcmp(pradd, ip_str)) { prefix = retaddr->ifa_prefixlen; iface = strdup(ifname); return 0; } } retrta = RTA_NEXT(retrta, attlen); } retmsg = NLMSG_NEXT(retmsg, len); } return -1; }
// Returns AF_MAX (with errno set) if error, AF_UNSPEC if no more addrs (socket closed) struct IPAddr nextAddr(struct AddrFilter const filter, struct MonitorState * const state){ // NLMSG_OK checks length first, so safe to call with state->nlh == NULL iff // state->nlmsg_len < (int) sizeof(struct nlmsghdr) if (NLMSG_OK(state->nlh, state->nlmsg_len) && (state->nlh->nlmsg_type != NLMSG_DONE)){ struct nlmsghdr * nlh = state->nlh; state->nlh = NLMSG_NEXT(state->nlh, state->nlmsg_len); switch(nlh->nlmsg_type){ case NLMSG_ERROR: errno = -((struct nlmsgerr *) NLMSG_DATA(nlh))->error; struct IPAddr addr = {.af = AF_MAX}; return addr; case RTM_NEWADDR: { struct ifaddrmsg * ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh); if (!filterIfAddrMsg(*ifa, filter)) return nextAddr(filter, state); { struct rtattr * rth; size_t rtmsg_len; for (rth = IFA_RTA(ifa), rtmsg_len = IFA_PAYLOAD(nlh); RTA_OK(rth, rtmsg_len); RTA_NEXT(rth, rtmsg_len)){ if (rth->rta_type != IFA_ADDRESS) continue; // family checked in filterIfAddrMsg, so always valid. struct IPAddr addr = {.af = ifa->ifa_family}; switch (ifa->ifa_family) { case AF_INET: addr.ipv4 = *((struct in_addr *) RTA_DATA(rth)); break; case AF_INET6: addr.ipv6 = *((struct in6_addr *) RTA_DATA(rth)); break; } if (addrIsPrivate(addr) && !filter.allow_private) return nextAddr(filter, state); else return addr; } } // Recieved RTM_NEWADDR without any address. errno = EBADMSG; struct IPAddr addr = {.af = AF_MAX}; return addr; } default: return nextAddr(filter, state); } } else { state->nlmsg_len = nextMessage(filter, state->socket, &state->buf, &state->buf_len); if (state->nlmsg_len == 0) { // Socket closed by kernel struct IPAddr addr = {.af = AF_UNSPEC}; return addr; } else if (state->nlmsg_len < 0) { // Socket error struct IPAddr addr = {.af = AF_MAX}; return addr; } else {
boost::asio::ip::address_v6 get_ipv6_address(const nlmsghdr *in, const nlmsghdr *an) { boost::asio::ip::address_v6 unspec; if (in->nlmsg_type != RTM_NEWLINK) return unspec; if (an->nlmsg_type != RTM_NEWADDR) return unspec; ifinfomsg* ifi = (ifinfomsg*)NLMSG_DATA(in); ifaddrmsg* ifa = (ifaddrmsg*)NLMSG_DATA(an); __u32 ilen = in->nlmsg_len; if (ilen < NLMSG_LENGTH(sizeof(*ifi))) return unspec; ilen -= NLMSG_LENGTH(sizeof(*ifi)); __u32 alen = an->nlmsg_len; if (alen < NLMSG_LENGTH(sizeof(*ifa))) return unspec; alen -= NLMSG_LENGTH(sizeof(*ifa)); /* NOTE: ifi_index and ifa_index should have the same type (int), but for * some reason they are not... So instead of a normal (in)equality comparison * we do a bit-wise compare. */ if (ifi->ifi_index ^ ifa->ifa_index) return unspec; if (ifi->ifi_family != AF_INET6 || ifa->ifa_family != AF_INET6) return unspec; rtattr* tbi[IFLA_MAX+1]; memset(tbi, 0, sizeof(tbi)); parse_rtattr(tbi, IFLA_MAX, IFLA_RTA(ifi), ilen); if (tbi[IFLA_IFNAME] == NULL) return unspec; rtattr* tba[IFA_MAX+1]; memset(tba, 0, sizeof(tba)); parse_rtattr(tba, IFA_MAX, IFA_RTA(ifa), alen); char abuf[256]; rt_addr_n2a(ifa->ifa_family, RTA_PAYLOAD(tba[IFA_ADDRESS]), RTA_DATA(tba[IFA_ADDRESS]), abuf, sizeof(abuf)); std::string ipaddr = abuf; try { boost::asio::ip::address_v6 addr(boost::asio::ip::address_v6::from_string(ipaddr)); addr.scope_id(ifi->ifi_index); return addr; } catch(...) { return unspec; } }
/* * Netlink interface address lookup filter * We need to handle multiple primary address and * multiple secondary address to the same interface. */ static int netlink_if_address_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { struct ifaddrmsg *ifa; struct rtattr *tb[IFA_MAX + 1]; interface_t *ifp; int len; void *addr; ifa = NLMSG_DATA(h); /* Only IPV4 are valid us */ if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) return 0; if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg)); if (len < 0) return -1; memset(tb, 0, sizeof (tb)); parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); /* Fetch interface_t */ ifp = if_get_by_ifindex(ifa->ifa_index); if (!ifp) return 0; if (tb[IFA_LOCAL] == NULL) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; /* local interface address */ addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); if (addr == NULL) return -1; /* If no address is set on interface then set the first time */ if (ifa->ifa_family == AF_INET) { if (!ifp->sin_addr.s_addr) ifp->sin_addr = *(struct in_addr *) addr; } else { if (!ifp->sin6_addr.s6_addr16[0] && ifa->ifa_scope == RT_SCOPE_LINK) ifp->sin6_addr = *(struct in6_addr *) addr; } #ifdef _WITH_LVS_ /* Refresh checkers state */ update_checker_activity(ifa->ifa_family, addr, (h->nlmsg_type == RTM_NEWADDR) ? 1 : 0); #endif return 0; }
static int handle_addr_msg(struct nlmsghdr *nlh, int n) { struct ifaddrmsg *ifa_msg = NLMSG_DATA(nlh); struct rtattr *tb[IFA_MAX]; parse_rt_attrs(tb, IFA_MAX, IFA_RTA(ifa_msg), IFA_PAYLOAD(nlh)); handle_addr_attrs(ifa_msg, tb, nlh->nlmsg_type); return 0; }
void process_nl_del_address (struct nlmsghdr *nlh) { struct ifaddrmsg *ifa = NULL; struct rtattr *rth = NULL; int iface_index = 0; int rt_length = 0; lispd_iface_elt *iface = NULL; lisp_addr_t new_addr; char iface_name[IF_NAMESIZE]; ifa = (struct ifaddrmsg *) NLMSG_DATA (nlh); iface_index = ifa->ifa_index; iface = get_interface_from_index(iface_index); if (iface == NULL) { if_indextoname(iface_index, iface_name); lispd_log_msg(LISP_LOG_DEBUG_2, "process_nl_add_address: the netlink message is not for any interface associated with RLOCs (%s)", iface_name); return; } rth = IFA_RTA (ifa); rth = IFA_RTA (ifa); rt_length = IFA_PAYLOAD (nlh); for (; rt_length && RTA_OK (rth, rt_length); rth = RTA_NEXT (rth,rt_length)) { if (rth->rta_type == IFA_ADDRESS) { if (ifa->ifa_family == AF_INET) { memcpy (&(new_addr.address),(struct in_addr *)RTA_DATA(rth),sizeof(struct in_addr)); new_addr.afi = AF_INET; } else if (ifa->ifa_family == AF_INET6) { memcpy (&(new_addr.address),(struct in6_addr *)RTA_DATA(rth),sizeof(struct in6_addr)); new_addr.afi = AF_INET6; } break; } } /* Actions to be done when address is removed */ lispd_log_msg(LISP_LOG_DEBUG_2," deleted address: %s\n", get_char_from_lisp_addr_t(new_addr)); }
int main() { struct sockaddr_nl addr; int sock, len; char buffer[4096]; struct nlmsghdr *nlh; if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { perror("couldn't open NETLINK_ROUTE socket"); return 1; } fprintf(stderr,"socket: f%d\n",sock); memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; addr.nl_groups = RTMGRP_IPV4_IFADDR; if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { perror("couldn't bind"); return 1; } fprintf(stderr,"bound\n"); nlh = (struct nlmsghdr *)buffer; while ((len = recv(sock, nlh, 4096, 0)) > 0) { fprintf(stderr,"recv returned %db (%d %s)\n",len,errno,strerror(errno)); while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) { if (nlh->nlmsg_type == RTM_NEWADDR) { struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh); struct rtattr *rth = IFA_RTA(ifa); int rtl = IFA_PAYLOAD(nlh); while (rtl && RTA_OK(rth, rtl)) { if (rth->rta_type == IFA_LOCAL) { uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth))); char name[IFNAMSIZ]; if_indextoname(ifa->ifa_index, name); printf("%s is now %d.%d.%d.%d\n", name, (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff); } rth = RTA_NEXT(rth, rtl); } } nlh = NLMSG_NEXT(nlh, len); } }
static void easycwmp_netlink_interface(struct nlmsghdr *nlh) { struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh); struct rtattr *rth = IFA_RTA(ifa); int rtl = IFA_PAYLOAD(nlh); char if_name[IFNAMSIZ], if_addr[INET_ADDRSTRLEN]; static old_addr=0; memset(&if_name, 0, sizeof(if_name)); memset(&if_addr, 0, sizeof(if_addr)); while (rtl && RTA_OK(rth, rtl)) { if (rth->rta_type != IFA_LOCAL) { rth = RTA_NEXT(rth, rtl); continue; } uint32_t addr = htonl(* (uint32_t *)RTA_DATA(rth)); if (htonl(13) == 13) { // running on big endian system } else { // running on little endian system addr = __bswap_32(addr); } if_indextoname(ifa->ifa_index, if_name); if (strncmp(config->local->interface, if_name, IFNAMSIZ)) { rth = RTA_NEXT(rth, rtl); continue; } if ((addr != old_addr) && (old_addr != 0)) { log_message(NAME, L_DEBUG, "ip address of the interface %s is changed\n", if_name); cwmp_add_event(EVENT_VALUE_CHANGE, NULL, 0, EVENT_NO_BACKUP); cwmp_add_inform_timer(); } old_addr = addr; inet_ntop(AF_INET, &(addr), if_addr, INET_ADDRSTRLEN); if (config->local) FREE(config->local->ip); config->local->ip = strdup(if_addr); break; } if (strlen(if_addr) == 0) return; log_message(NAME, L_DEBUG, "interface %s has ip %s\n", if_name, if_addr); }
/* ****************************************************************************** * dcs_local_ip_monitor_process *//** * * \brief - Called by the polling thread that gets an indication that the local * IP address has changed. The function sets the Local IP Address in * the dcs_local_ip variable * * \param[in] socket - The socket on which the information arrived * \param[in] context - NULL * * \retval DOVE_STATUS_OK * ****************************************************************************** */ static int dcs_local_ip_monitor_process(int socket, void *context) { struct nlmsghdr *nlh; char buf[4096]; int len; dove_status status = DOVE_STATUS_OK; while ((len = recv(dps_monitor_socket, buf, sizeof(buf), 0)) > 0) { nlh = (struct nlmsghdr *)buf; while ((NLMSG_OK(nlh, (uint32_t)len)) && (nlh->nlmsg_type != NLMSG_DONE)) { if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR) { struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nlh); struct rtattr *rth = IFA_RTA(ifa); int rtl = IFA_PAYLOAD(nlh); while (rtl && RTA_OK(rth, rtl)) { if (rth->rta_type == IFA_LOCAL) { char ifname[IFNAMSIZ]; if_indextoname(ifa->ifa_index, ifname); if (!strcmp(ifname, SVA_INTERFACE_NAME) && (nlh->nlmsg_type == RTM_NEWADDR)) { status = set_local_ip(); if (status != DOVE_STATUS_OK) { log_warn(PythonDataHandlerLogLevel, "Cannot get IP Address of SVA"); break; } // Register the Local DPS Node with the Cluster dcs_set_service_role(dcs_role_assigned); } } rth = RTA_NEXT(rth, rtl); } } nlh = NLMSG_NEXT(nlh, len); } } return DOVE_STATUS_OK; }
/* return true if there is a known address with 'tentative' flag set */ static bool virNetDevIPParseDadStatus(struct nlmsghdr *nlh, int len, virSocketAddrPtr *addrs, size_t count) { struct ifaddrmsg *ifaddrmsg_ptr; unsigned int ifaddrmsg_len; struct rtattr *rtattr_ptr; size_t i; struct in6_addr *addr; VIR_WARNINGS_NO_CAST_ALIGN for (; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) { VIR_WARNINGS_RESET if (NLMSG_PAYLOAD(nlh, 0) < sizeof(struct ifaddrmsg)) { /* Message without payload is the last one. */ break; } ifaddrmsg_ptr = (struct ifaddrmsg *)NLMSG_DATA(nlh); if (!(ifaddrmsg_ptr->ifa_flags & IFA_F_TENTATIVE)) { /* Not tentative: we are not interested in this entry. */ continue; } ifaddrmsg_len = IFA_PAYLOAD(nlh); VIR_WARNINGS_NO_CAST_ALIGN rtattr_ptr = (struct rtattr *) IFA_RTA(ifaddrmsg_ptr); for (; RTA_OK(rtattr_ptr, ifaddrmsg_len); rtattr_ptr = RTA_NEXT(rtattr_ptr, ifaddrmsg_len)) { VIR_WARNINGS_RESET if (RTA_PAYLOAD(rtattr_ptr) != sizeof(struct in6_addr)) { /* No address: ignore. */ continue; } /* We check only known addresses. */ for (i = 0; i < count; i++) { addr = &addrs[i]->data.inet6.sin6_addr; if (!memcmp(addr, RTA_DATA(rtattr_ptr), sizeof(struct in6_addr))) { /* We found matching tentative address. */ return true; } } } } return false; }
static int parse_v4_addr_msg(orc_options_t * options, struct nlmsghdr * nl_msg, u32 * ipv4_addr, int * if_index, char ifnam[IFNAMSIZ]) { struct ifaddrmsg * ifaddr_msg; struct rtattr * attr; int rtattr_len; int found_addr = 0; int found_ifnam = 0; ifaddr_msg = (struct ifaddrmsg *) NLMSG_DATA(nl_msg); /* extract the first attribute */ attr = (struct rtattr *) IFA_RTA(ifaddr_msg); rtattr_len = IFA_PAYLOAD(nl_msg); *if_index = ifaddr_msg->ifa_index; if (ifaddr_msg->ifa_family == AF_INET6) { /* TODO: add IPv6 support */ orc_debug("Ignoring new IPv6 address: IPv6 unsupported\n"); return 0; } /** 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 IFA_ADDRESS: memcpy(ipv4_addr, RTA_DATA(attr), sizeof(*ipv4_addr)); found_addr = 1; /* probably always there, but... */ break; case IFA_LABEL: snprintf(ifnam, IFNAMSIZ, "%s", (char *) RTA_DATA(attr)); found_ifnam = 1; break; case IFA_LOCAL: case IFA_BROADCAST: orc_trace("Intentionally ignoring address update %s - not needed\n", attr->rta_type == IFA_LOCAL? "IFA_LOCAL" : "IFA_BROADCAST"); break; default: orc_warn("Skipping unhandled ipv4 address attr: %d\n", attr->rta_type); } } return found_addr && found_ifnam; }
static int fill_if_addr(struct if_entry *dest, struct nlmsg_entry *ainfo) { struct if_addr *entry; struct nlmsghdr *n; struct ifaddrmsg *ifa; struct rtattr *rta_tb[IFA_MAX + 1]; int len, err; for (; ainfo; ainfo = ainfo->next) { n = &ainfo->h; ifa = NLMSG_DATA(n); if (ifa->ifa_index != dest->if_index) continue; if (n->nlmsg_type != RTM_NEWADDR) continue; len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)); if (len < 0) continue; if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) /* only IP addresses supported (at least for now) */ continue; rtnl_parse(rta_tb, IFA_MAX, IFA_RTA(ifa), len); if (!rta_tb[IFA_LOCAL] && !rta_tb[IFA_ADDRESS]) /* don't care about broadcast and anycast adresses */ continue; entry = calloc(sizeof(struct if_addr), 1); if (!entry) return ENOMEM; if (!rta_tb[IFA_LOCAL]) { rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; rta_tb[IFA_ADDRESS] = NULL; } if ((err = addr_init_netlink(&entry->addr, ifa, rta_tb[IFA_LOCAL]))) return err; if (rta_tb[IFA_ADDRESS] && memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), ifa->ifa_family == AF_INET ? 4 : 16)) { if ((err = addr_init_netlink(&entry->peer, ifa, rta_tb[IFA_ADDRESS]))) return err; } list_append(&dest->addr, node(entry)); } return 0; }
int main(int argc, const char *argv[]) { struct sockaddr_nl addr; int nls,len,rtl; char buffer[4096]; struct nlmsghdr *nlh; struct ifaddrmsg *ifa; struct rtattr *rth; if ((nls = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) perror ("socket failure\n"); memset (&addr,0,sizeof(addr)); addr.nl_family = AF_NETLINK; //addr.nl_groups = RTMGRP_IPV4_IFADDR; addr.nl_groups = RTNLGRP_IPV4_IFADDR; if (bind(nls, (struct sockaddr *)&addr, sizeof(addr)) == -1) perror ("bind failure\n"); nlh = (struct nlmsghdr *)buffer; while ((len = recv (nls,nlh,4096,0)) > 0) { for (;(NLMSG_OK (nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE); nlh = NLMSG_NEXT(nlh, len)) { if (nlh->nlmsg_type != RTM_NEWADDR) {printf("\nsomething....\n");continue; }/* some other kind of announcement */ ifa = (struct ifaddrmsg *) NLMSG_DATA (nlh); rth = IFA_RTA (ifa); rtl = IFA_PAYLOAD (nlh); for (;rtl && RTA_OK (rth, rtl); rth = RTA_NEXT (rth,rtl)) { char name[IFNAMSIZ]; uint32_t ipaddr; if (rth->rta_type != IFA_LOCAL) continue; ipaddr = * ((uint32_t *)RTA_DATA(rth)); ipaddr = htonl(ipaddr); fprintf (stdout,"%s is now %X\n",if_indextoname(ifa->ifa_index,name),ipaddr); } } } }
int TunManager::getAddrRespParser(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { // only cares about RTM_NEWADDR if (n->nlmsg_type != RTM_NEWADDR) { return 0; } struct ifaddrmsg *ifa = static_cast<struct ifaddrmsg *>(NLMSG_DATA(n)); struct rtattr *tb[IFA_MAX + 1]; int len = n->nlmsg_len; len -= NLMSG_LENGTH(sizeof(*ifa)); if (len < 0) { throw FbossError("Wrong length for RTM_GETADDR response ", len, " vs ", NLMSG_LENGTH(sizeof(*ifa))); } // only care about v4 and v6 address if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) { VLOG(3) << "Skip address from device @ index " << static_cast<int>(ifa->ifa_index) << " because of its address family " << static_cast<int>(ifa->ifa_family); return 0; } parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); if (tb[IFA_ADDRESS] == nullptr) { VLOG(3) << "Device @ index " << static_cast<int>(ifa->ifa_index) << " does not have address at family " << static_cast<int>(ifa->ifa_family); return 0; } IPAddress addr; const void *data = RTA_DATA(tb[IFA_ADDRESS]); if (ifa->ifa_family == AF_INET) { addr = IPAddress(*static_cast<const in_addr *>(data)); } else { addr = IPAddress(*static_cast<const in6_addr *>(data)); } TunManager *mgr = static_cast<TunManager *>(arg); mgr->addProbedAddr(ifa->ifa_index, addr, ifa->ifa_prefixlen); return 0; }
void process_nl_add_address (struct nlmsghdr *nlh) { struct ifaddrmsg *ifa = NULL; struct rtattr *rth = NULL; int iface_index = 0; int rt_length = 0; lispd_iface_elt *iface = NULL; lisp_addr_t new_addr; char iface_name[IF_NAMESIZE]; /* * Get the new address from the net link message */ ifa = (struct ifaddrmsg *) NLMSG_DATA (nlh); iface_index = ifa->ifa_index; iface = get_interface_from_index(iface_index); if (iface == NULL){ if_indextoname(iface_index, iface_name); lispd_log_msg(LISP_LOG_DEBUG_2, "process_nl_add_address: the netlink message is not for any interface associated with RLOCs (%s / %d)", iface_name, iface_index); return; } rth = IFA_RTA (ifa); rt_length = IFA_PAYLOAD (nlh); for (;rt_length && RTA_OK (rth, rt_length); rth = RTA_NEXT (rth,rt_length)) { if (ifa->ifa_family == AF_INET && rth->rta_type == IFA_LOCAL){ memcpy (&(new_addr.address),(struct in_addr *)RTA_DATA(rth),sizeof(struct in_addr)); new_addr.afi = AF_INET; process_address_change (iface, new_addr); } if (ifa->ifa_family == AF_INET6 && rth->rta_type == IFA_ADDRESS){ memcpy (&(new_addr.address),(struct in6_addr *)RTA_DATA(rth),sizeof(struct in6_addr)); new_addr.afi = AF_INET6; process_address_change (iface, new_addr); } } }
/** * returns non-local addresses for specified interface */ void ipaddr_global_get(int *count, char **bufPtr, int ifindex, struct nlmsg_list *ainfo) { int cnt=0; char * buf=0, * tmpbuf=0; char addr[16]; struct rtattr * rta_tb[IFA_MAX+1]; int pos; for ( ;ainfo ; ainfo = ainfo->next) { struct nlmsghdr *n = &ainfo->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); if ( (ifa->ifa_family == AF_INET6) && (ifa->ifa_index == ifindex) ) { memset(rta_tb, 0, sizeof(*rta_tb)); parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; memcpy(addr,(char*)RTA_DATA(rta_tb[IFLA_ADDRESS]),16); if ( (addr[0]==0xfe && addr[1]==0x80) || /* link local */ (addr[0]==0xff) ) { /* multicast */ continue; /* ignore non link-scoped addrs */ } /* ifa->ifa_flags & 128 - permenent */ /* printf("flags:%d : ",ifa->ifa_flags); */ pos = cnt*16; buf = (char*) malloc( pos + 16); if (pos > 0) { memcpy(buf,tmpbuf, pos); /* copy old addrs */ } memcpy(buf+pos,addr,16); /* copy new addr */ if (pos > 0) { free(tmpbuf); } tmpbuf = buf; cnt++; } } *count = cnt; *bufPtr = buf; }
static int rtnl_ifaddr_get(struct nlmsghdr *h, int (*if_callback)(int, struct in_ifaddr *)) { struct rtattr *tb[IFA_MAX + 1]; struct ifaddrmsg *ifaddr; int len; struct in_ifaddr in_ifaddr; if (h->nlmsg_type != RTM_NEWADDR) return 0; ifaddr = NLMSG_DATA(h); len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); if (len < 0) return -1; netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifaddr), len); strcpy(in_ifaddr.ifa_label, (char *)RTA_DATA(tb[IFA_LABEL])); in_ifaddr.ifa_address = *(uint32_t *)RTA_DATA(tb[IFA_ADDRESS]); in_ifaddr.ifa_local = *(uint32_t *)RTA_DATA(tb[IFA_LOCAL]); if (tb[IFA_BROADCAST]) in_ifaddr.ifa_broadcast = *(uint32_t *)RTA_DATA(tb[IFA_BROADCAST]); if (tb[IFA_ANYCAST]) in_ifaddr.ifa_anycast = *(uint32_t *)RTA_DATA(tb[IFA_ANYCAST]); in_ifaddr.ifa_family = ifaddr->ifa_family; in_ifaddr.ifa_prefixlen = ifaddr->ifa_prefixlen; in_ifaddr.ifa_flags = ifaddr->ifa_flags; in_ifaddr.ifa_scope = ifaddr->ifa_scope; return if_callback(ifaddr->ifa_index, &in_ifaddr); }
/**************************************************************** NAME : print_addr 00/06/02 18:24:09 AIM : REMARK : ****************************************************************/ static int get_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct ifaddrmsg *ifa = NLMSG_DATA(n); int len = n->nlmsg_len; iplist_ctx *ctx = (iplist_ctx *)arg; struct rtattr *rta_tb[IFA_MAX+1]; /* sanity check */ len -= NLMSG_LENGTH(sizeof(*ifa)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } /* check the message type */ if (n->nlmsg_type != RTM_NEWADDR ) return 0; /* check it is ipv4 */ if( ifa->ifa_family != AF_INET) return 0; /* check it is the good interface */ if( ifa->ifa_index != ctx->ifindex ) return 0; /* parse the attribute */ memset(rta_tb, 0, sizeof(rta_tb)); parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), len); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (rta_tb[IFA_LOCAL]) { u_char *src = RTA_DATA(rta_tb[IFA_LOCAL]); if( ctx->nb_elem >= ctx->max_elem ) return 0; ctx->addr[ctx->nb_elem++] = (src[0]<<24) + (src[1]<<16) + (src[2]<<8) + src[3]; } return 0; }
/* function: getaddr_cb * callback for getinterface_ip * msg - netlink message * data - (struct target) info for which address we're looking for */ static int getaddr_cb(struct nl_msg *msg, void *data) { struct ifaddrmsg *ifa_p; struct rtattr *rta_p; int rta_len; struct target *targ_p = (struct target *)data; ifa_p = (struct ifaddrmsg *)nlmsg_data(nlmsg_hdr(msg)); rta_p = (struct rtattr *)IFA_RTA(ifa_p); if(ifa_p->ifa_index != targ_p->ifindex) return NL_OK; if(ifa_p->ifa_scope != RT_SCOPE_UNIVERSE) return NL_OK; 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 IFA_ADDRESS: if((targ_p->family == AF_INET6) && !(ifa_p->ifa_flags & IFA_F_SECONDARY)) { memcpy(&targ_p->ip.ip6, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr)); targ_p->foundip = 1; return NL_OK; } break; case IFA_LOCAL: if(targ_p->family == AF_INET) { memcpy(&targ_p->ip.ip4, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr)); targ_p->foundip = 1; return NL_OK; } break; } } return NL_OK; }
void dispatch_ifaddr_v6(Tag, struct ifaddrmsg * ifa, std::size_t len) { acqua::network::internet6_address addr; std::string label; uint prefixlen = ifa->ifa_prefixlen; uint flags = ifa->ifa_flags; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" for(auto * rta = IFA_RTA(ifa); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { switch(rta->rta_type) { case IFA_ADDRESS: addr = addr.from_voidptr(RTA_DATA(rta)); break; case IFA_LABEL: label = static_cast<char const *>(RTA_DATA(rta)); break; } } #pragma GCC diagnostic pop static_cast<Derived *>(this)->on_ifaddr(addr, label, prefixlen, flags); }
int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = arg; struct ifaddrmsg *ifa = NLMSG_DATA(n); int len = n->nlmsg_len; int deprecated = 0; /* Use local copy of ifa_flags to not interfere with filtering code */ unsigned int ifa_flags; struct rtattr * rta_tb[IFA_MAX+1]; char abuf[256]; SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) return 0; len -= NLMSG_LENGTH(sizeof(*ifa)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (filter.flushb && n->nlmsg_type != RTM_NEWADDR) return 0; parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); ifa_flags = get_ifa_flags(ifa, rta_tb[IFA_FLAGS]); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; if (filter.ifindex && filter.ifindex != ifa->ifa_index) return 0; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) return 0; if ((filter.flags ^ ifa_flags) & filter.flagmask) return 0; if (filter.label) { SPRINT_BUF(b1); const char *label; if (rta_tb[IFA_LABEL]) label = RTA_DATA(rta_tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) return 0; } if (filter.pfx.family) { if (rta_tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) return 0; } } if (filter.family && filter.family != ifa->ifa_family) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELADDR; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELADDR) fprintf(fp, "Deleted "); if (filter.oneline || filter.flushb) fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index)); if (ifa->ifa_family == AF_INET) fprintf(fp, " inet "); else if (ifa->ifa_family == AF_INET6) fprintf(fp, " inet6 "); else if (ifa->ifa_family == AF_DECnet) fprintf(fp, " dnet "); else if (ifa->ifa_family == AF_IPX) fprintf(fp, " ipx "); else fprintf(fp, " family %d ", ifa->ifa_family); if (rta_tb[IFA_LOCAL]) { if (ifa->ifa_family == AF_INET) color_fprintf(fp, COLOR_INET, "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); else if (ifa->ifa_family == AF_INET6) color_fprintf(fp, COLOR_INET6, "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); else fprintf(fp, "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); if (rta_tb[IFA_ADDRESS] == NULL || memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), ifa->ifa_family == AF_INET ? 4 : 16) == 0) { fprintf(fp, "/%d ", ifa->ifa_prefixlen); } else { fprintf(fp, " peer %s/%d ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_ADDRESS]), abuf, sizeof(abuf)), ifa->ifa_prefixlen); } } if (rta_tb[IFA_BROADCAST]) { fprintf(fp, "brd %s ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), RTA_DATA(rta_tb[IFA_BROADCAST]), abuf, sizeof(abuf))); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any %s ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), RTA_DATA(rta_tb[IFA_ANYCAST]), abuf, sizeof(abuf))); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); if (ifa_flags & IFA_F_SECONDARY) { ifa_flags &= ~IFA_F_SECONDARY; if (ifa->ifa_family == AF_INET6) fprintf(fp, "temporary "); else fprintf(fp, "secondary "); } if (ifa_flags & IFA_F_TENTATIVE) { ifa_flags &= ~IFA_F_TENTATIVE; fprintf(fp, "tentative "); } if (ifa_flags & IFA_F_DEPRECATED) { ifa_flags &= ~IFA_F_DEPRECATED; deprecated = 1; fprintf(fp, "deprecated "); } if (ifa_flags & IFA_F_HOMEADDRESS) { ifa_flags &= ~IFA_F_HOMEADDRESS; fprintf(fp, "home "); } if (ifa_flags & IFA_F_NODAD) { ifa_flags &= ~IFA_F_NODAD; fprintf(fp, "nodad "); } if (ifa_flags & IFA_F_MANAGETEMPADDR) { ifa_flags &= ~IFA_F_MANAGETEMPADDR; fprintf(fp, "mngtmpaddr "); } if (ifa_flags & IFA_F_NOPREFIXROUTE) { ifa_flags &= ~IFA_F_NOPREFIXROUTE; fprintf(fp, "noprefixroute "); } if (ifa_flags & IFA_F_MCAUTOJOIN) { ifa_flags &= ~IFA_F_MCAUTOJOIN; fprintf(fp, "autojoin "); } if (!(ifa_flags & IFA_F_PERMANENT)) { fprintf(fp, "dynamic "); } else ifa_flags &= ~IFA_F_PERMANENT; if (ifa_flags & IFA_F_DADFAILED) { ifa_flags &= ~IFA_F_DADFAILED; fprintf(fp, "dadfailed "); } if (ifa_flags) fprintf(fp, "flags %02x ", ifa_flags); if (rta_tb[IFA_LABEL]) fprintf(fp, "%s", rta_getattr_str(rta_tb[IFA_LABEL])); if (rta_tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); fprintf(fp, "%s", _SL_); fprintf(fp, " valid_lft "); if (ci->ifa_valid == INFINITY_LIFE_TIME) fprintf(fp, "forever"); else fprintf(fp, "%usec", ci->ifa_valid); fprintf(fp, " preferred_lft "); if (ci->ifa_prefered == INFINITY_LIFE_TIME) fprintf(fp, "forever"); else { if (deprecated) fprintf(fp, "%dsec", ci->ifa_prefered); else fprintf(fp, "%usec", ci->ifa_prefered); } } fprintf(fp, "\n"); fflush(fp); return 0; }
static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo) { struct nlmsg_list *l, **lp; lp = &linfo->head; while ( (l = *lp) != NULL) { int ok = 0; int missing_net_address = 1; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a = ainfo->head; a; a = a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); struct rtattr *tb[IFA_MAX + 1]; unsigned int ifa_flags; if (ifa->ifa_index != ifi->ifi_index) continue; missing_net_address = 0; if (filter.family && filter.family != ifa->ifa_family) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); ifa_flags = get_ifa_flags(ifa, tb[IFA_FLAGS]); if ((filter.flags ^ ifa_flags) & filter.flagmask) continue; if (filter.pfx.family || filter.label) { if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (missing_net_address && (filter.family == AF_UNSPEC || filter.family == AF_PACKET)) ok = 1; if (!ok) { *lp = l->next; free(l); } else lp = &l->next; } }
/* Return value becomes exitcode. It's okay to not return at all */ int ipaddr_list_or_flush(int argc, char **argv, int flush) { static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0"; struct nlmsg_list *linfo = NULL; struct nlmsg_list *ainfo = NULL; struct nlmsg_list *l; struct rtnl_handle rth; char *filter_dev = NULL; int no_link = 0; ipaddr_reset_filter(oneline); filter.showqueue = 1; if (filter.family == AF_UNSPEC) filter.family = preferred_family; if (flush) { if (argc <= 0) { bb_error_msg_and_die(bb_msg_requires_arg, "flush"); } if (filter.family == AF_PACKET) { bb_error_msg_and_die("cannot flush link addresses"); } } while (argc > 0) { const int option_num = index_in_strings(option, *argv); switch (option_num) { case 0: /* to */ NEXT_ARG(); get_prefix(&filter.pfx, *argv, filter.family); if (filter.family == AF_UNSPEC) { filter.family = filter.pfx.family; } break; case 1: /* scope */ { uint32_t scope = 0; NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { if (strcmp(*argv, "all") != 0) { invarg(*argv, "scope"); } scope = RT_SCOPE_NOWHERE; filter.scopemask = 0; } filter.scope = scope; break; } case 2: /* up */ filter.up = 1; break; case 3: /* label */ NEXT_ARG(); filter.label = *argv; break; case 4: /* dev */ NEXT_ARG(); default: if (filter_dev) { duparg2("dev", *argv); } filter_dev = *argv; } argv++; argc--; } xrtnl_open(&rth); xrtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK); xrtnl_dump_filter(&rth, store_nlmsg, &linfo); if (filter_dev) { filter.ifindex = xll_name_to_index(filter_dev); } if (flush) { char flushb[4096-512]; filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.rth = &rth; for (;;) { xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); filter.flushed = 0; xrtnl_dump_filter(&rth, print_addrinfo, stdout); if (filter.flushed == 0) { return 0; } if (flush_update() < 0) return 1; } } if (filter.family != AF_PACKET) { xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); xrtnl_dump_filter(&rth, store_nlmsg, &ainfo); } if (filter.family && filter.family != AF_PACKET) { struct nlmsg_list **lp; lp=&linfo; if (filter.oneline) no_link = 1; while ((l=*lp)!=NULL) { int ok = 0; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct nlmsg_list *a; for (a=ainfo; a; a=a->next) { struct nlmsghdr *n = &a->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); if (ifa->ifa_index != ifi->ifi_index || (filter.family && filter.family != ifa->ifa_family)) continue; if ((filter.scope^ifa->ifa_scope)&filter.scopemask) continue; if ((filter.flags^ifa->ifa_flags)&filter.flagmask) continue; if (filter.pfx.family || filter.label) { struct rtattr *tb[IFA_MAX+1]; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); if (!tb[IFA_LOCAL]) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; } if (filter.label) { SPRINT_BUF(b1); const char *label; if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else label = ll_idx_n2a(ifa->ifa_index, b1); if (fnmatch(filter.label, label, 0) != 0) continue; } } ok = 1; break; } if (!ok) *lp = l->next; else lp = &l->next; } } for (l = linfo; l; l = l->next) { if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { struct ifinfomsg *ifi = NLMSG_DATA(&l->h); if (filter.family != AF_PACKET) print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); } fflush(stdout); /* why? */ } return 0; }