static void rtnl_print_route(struct nlmsghdr *hdr) { struct rtmsg *rtm = NLMSG_DATA(hdr); uint32_t attrs_len = RTM_PAYLOAD(hdr); struct rtattr *attr = RTM_RTA(rtm); struct rta_cacheinfo *ci; int hz = get_user_hz(); char addr_str[256]; char flags[256]; tprintf(" [ Route Family %d (%s%s%s)", rtm->rtm_family, colorize_start(bold), addr_family2str(rtm->rtm_family), colorize_end()); tprintf(", Dst Len %d", rtm->rtm_dst_len); tprintf(", Src Len %d", rtm->rtm_src_len); tprintf(", ToS %d", rtm->rtm_tos); tprintf(", Table %d (%s%s%s)", rtm->rtm_table, colorize_start(bold), route_table2str(rtm->rtm_table), colorize_end()); tprintf(", Proto %d (%s%s%s)", rtm->rtm_protocol, colorize_start(bold), route_proto2str(rtm->rtm_protocol), colorize_end()); tprintf(", Scope %d (%s%s%s)", rtm->rtm_scope, colorize_start(bold), scope2str(rtm->rtm_scope), colorize_end()); tprintf(", Type %d (%s%s%s)", rtm->rtm_type, colorize_start(bold), route_type2str(rtm->rtm_type), colorize_end()); tprintf(", Flags 0x%x (%s%s%s) ]\n", rtm->rtm_flags, colorize_start(bold), flags2str(route_flags, rtm->rtm_flags, flags, sizeof(flags)), colorize_end()); for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) { switch (attr->rta_type) { case RTA_DST: attr_fmt(attr, "Dst %s", addr2str(rtm->rtm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case RTA_SRC: attr_fmt(attr, "Src %s", addr2str(rtm->rtm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case RTA_IIF: attr_fmt(attr, "Iif %d", RTA_INT(attr)); break; case RTA_OIF: attr_fmt(attr, "Oif %d", RTA_INT(attr)); break; case RTA_GATEWAY: attr_fmt(attr, "Gateway %s", addr2str(rtm->rtm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case RTA_PRIORITY: attr_fmt(attr, "Priority %u", RTA_UINT32(attr)); break; case RTA_PREFSRC: attr_fmt(attr, "Pref Src %s", addr2str(rtm->rtm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case RTA_MARK: attr_fmt(attr, "Mark 0x%x", RTA_UINT(attr)); break; case RTA_FLOW: attr_fmt(attr, "Flow 0x%x", RTA_UINT(attr)); break; case RTA_TABLE: attr_fmt(attr, "Table %d (%s%s%s)", RTA_UINT32(attr), colorize_start(bold), route_table2str(RTA_UINT32(attr)), colorize_end()); break; case RTA_CACHEINFO: ci = RTA_DATA(attr); tprintf("\tA: Cache ("); tprintf("expires(%ds)", ci->rta_expires / hz); tprintf(", error(%d)", ci->rta_error); tprintf(", users(%d)", ci->rta_clntref); tprintf(", used(%d)", ci->rta_used); tprintf(", last use(%ds)", ci->rta_lastuse / hz); tprintf(", id(%d)", ci->rta_id); tprintf(", ts(%d)", ci->rta_ts); tprintf(", ts age(%ds))", ci->rta_tsage); tprintf(", Len %lu\n", RTA_LEN(attr)); break; } } }
int get_bind_addr(bin_addr *dest, struct addrinfo *ba) { int s; int len; struct rtattr *rta; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } rreq; int status; unsigned seq; struct nlmsghdr *h; struct sockaddr_nl nladdr; struct iovec iov; char buf[8192]; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; pid_t pid; struct rtattr * tb[RTA_MAX+1]; struct rtmsg *r; struct sockaddr_in *sin; struct in_addr ia; struct addrinfo hints, *res, *res0; int error; char host[256]; int found = 0; unsigned *d; /* IPv6 routing is not implemented yet */ switch (dest->atype) { case S5ATIPV4: memcpy(&ia, &(dest->v4_addr), 4); break; case S5ATIPV6: return -1; case S5ATFQDN: memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_INET; memcpy(host, &dest->fqdn, dest->len_fqdn); host[dest->len_fqdn] = '\0'; error = getaddrinfo(host, NULL, &hints, &res0); if (error) { return -1; } for (res = res0; res; res = res->ai_next) { if (res->ai_family != AF_INET) continue; sin = (struct sockaddr_in *)res->ai_addr; memcpy(&ia, &(sin->sin_addr), sizeof(ia)); found++; break; } freeaddrinfo(res0); if (!found) return -1; break; default: return -1; } memset(&rreq, 0, sizeof(rreq)); rreq.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); rreq.n.nlmsg_flags = NLM_F_REQUEST; rreq.n.nlmsg_type = RTM_GETROUTE; rreq.r.rtm_family = AF_INET; len = RTA_LENGTH(4); if (NLMSG_ALIGN(rreq.n.nlmsg_len) + len > sizeof(rreq)) return(-1); rta = (struct rtattr*)((char *)&rreq.n + NLMSG_ALIGN(rreq.n.nlmsg_len)); rta->rta_type = RTA_DST; rta->rta_len = len; memcpy(RTA_DATA(rta), &ia, 4); rreq.n.nlmsg_len = NLMSG_ALIGN(rreq.n.nlmsg_len) + len; rreq.r.rtm_dst_len = 32; /* 32 bit */ s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; rreq.n.nlmsg_seq = seq = 9999; iov.iov_base = (void*)&rreq.n; iov.iov_len = rreq.n.nlmsg_len; status = sendmsg(s, &msg, 0); if (status < 0) { /* perror("Cannot talk to rtnetlink"); */ return -1; } pid = getpid(); iov.iov_base = buf; do { iov.iov_len = sizeof(buf); status = recvmsg(s, &msg, 0); h = (struct nlmsghdr*)buf; } while (h->nlmsg_pid != pid || h->nlmsg_seq != seq); close(s); /* msg_out(norm,"nlmsg_pid: %d, nlmsg_seq: %d", h->nlmsg_pid, h->nlmsg_seq); */ len = h->nlmsg_len; r = NLMSG_DATA(buf); rta = RTM_RTA(r); while (RTA_OK(rta, len)) { if (rta->rta_type <= RTA_MAX) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta,len); } /* if (tb[RTA_DST]) { inet_ntop(AF_INET, RTA_DATA(tb[RTA_DST]), str, sizeof(str)); msg_out(norm, "DST %s", str); } if (tb[RTA_GATEWAY]) { inet_ntop(AF_INET, RTA_DATA(tb[RTA_GATEWAY]), str, sizeof(str)); msg_out(norm, "GW %s", str); } */ if (tb[RTA_OIF]) { d = RTA_DATA(tb[RTA_OIF]); return(get_ifconf(*d, ba)); } return(-1); }
static int process_nlmsg(struct nlmsghdr *n) { assert(n); if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) { /* A link appeared or was removed */ struct ifinfomsg *ifi; ifi = NLMSG_DATA(n); if (ifi->ifi_family != AF_UNSPEC || (int) ifi->ifi_index != ifindex) return 0; if (n->nlmsg_type == RTM_DELLINK) { daemon_log(LOG_ERR, "Interface vanished."); return -1; } assert(n->nlmsg_type == RTM_NEWLINK); if ((ifi->ifi_flags & IFF_LOOPBACK) || (ifi->ifi_flags & IFF_NOARP) || ifi->ifi_type != ARPHRD_ETHER) { daemon_log(LOG_ERR, "Interface not suitable."); return -1; } } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) { /* An address was added or removed */ struct rtattr *a = NULL; struct ifaddrmsg *ifa; int l; uint32_t address = 0; Address *i; ifa = NLMSG_DATA(n); if (ifa->ifa_family != AF_INET || (int) ifa->ifa_index != ifindex) return 0; l = NLMSG_PAYLOAD(n, sizeof(*ifa)); a = IFLA_RTA(ifa); while(RTA_OK(a, l)) { switch(a->rta_type) { case IFA_LOCAL: case IFA_ADDRESS: assert(RTA_PAYLOAD(a) == 4); memcpy(&address, RTA_DATA(a), sizeof(uint32_t)); break; } a = RTA_NEXT(a, l); } if (!address || is_ll_address(address)) return 0; for (i = addresses; i; i = i->addresses_next) if (i->address == address) break; if (n->nlmsg_type == RTM_DELADDR && i) { AVAHI_LLIST_REMOVE(Address, addresses, addresses, i); avahi_free(i); } if (n->nlmsg_type == RTM_NEWADDR && !i) { i = avahi_new(Address, 1); i->address = address; AVAHI_LLIST_PREPEND(Address, addresses, addresses, i); } } return 0; }
static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) { struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); size_t l_nameSize = 0; size_t l_addrSize = 0; int l_addedNetmask = 0; size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); struct rtattr *l_rta; for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); if(l_info->ifa_family == AF_PACKET) { continue; } switch(l_rta->rta_type) { case IFA_ADDRESS: case IFA_LOCAL: if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) { // make room for netmask l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); l_addedNetmask = 1; } case IFA_BROADCAST: l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); break; case IFA_LABEL: l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); break; default: break; } } struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); memset(l_entry, 0, sizeof(struct ifaddrs)); l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name; char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); char *l_addr = l_name + l_nameSize; l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags; l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { void *l_rtaData = RTA_DATA(l_rta); size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFA_ADDRESS: case IFA_BROADCAST: case IFA_LOCAL: { size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); if(l_info->ifa_family == AF_INET6) { if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) { ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; } } if(l_rta->rta_type == IFA_ADDRESS) { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address if(l_entry->ifa_addr) { l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; } else { l_entry->ifa_addr = (struct sockaddr *)l_addr; } } else if(l_rta->rta_type == IFA_LOCAL) { if(l_entry->ifa_addr) { l_entry->ifa_dstaddr = l_entry->ifa_addr; } l_entry->ifa_addr = (struct sockaddr *)l_addr; } else { l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; } l_addr += NLMSG_ALIGN(l_addrLen); break; } case IFA_LABEL: strncpy(l_name, l_rtaData, l_rtaDataSize); l_name[l_rtaDataSize] = '\0'; l_entry->ifa_name = l_name; break; default: break; } } if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) { unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); char l_mask[16] = {0}; unsigned i; for(i=0; i<(l_prefix/8); ++i) { l_mask[i] = 0xff; } l_mask[i] = 0xff << (8 - (l_prefix % 8)); makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); l_entry->ifa_netmask = (struct sockaddr *)l_addr; } addToEnd(p_resultList, l_entry); }
/** * @brief Handle an RTM_NEWLINK message from the driver, generating the * appropriate events from it. * * @param [in] state the internal state for this instance * @param [in] hdr the netlink message header; the length field has * already been validated * @param [in] payloadLen the length of the payload (not including the * netlink header) */ static void wlanifLinkEventsHandleNewLink(wlanifLinkEventsHandle_t state, const struct nlmsghdr *hdr, u_int32_t payloadLen) { const struct ifinfomsg *ifaceInfo = NLMSG_DATA(hdr); size_t ifaceLen = NLMSG_ALIGN(sizeof(*ifaceInfo)); if (payloadLen < ifaceLen) { dbgf(state->dbgModule, DBGERR, "%s: Malformed netlink payload " "length %u", __func__, payloadLen); return; } wlanif_band_e band = wlanifBSteerControlResolveBandFromSystemIndex(state->bsteerControlHandle, ifaceInfo->ifi_index); if (wlanif_band_invalid == band) { dbgf(state->dbgModule, DBGDUMP, "%s: Received message from ifindex %u not managed by lbd", __func__, ifaceInfo->ifi_index); return; } const struct rtattr *attr = IFLA_RTA(ifaceInfo); const size_t RTATTR_LEN = RTA_ALIGN(sizeof(*attr)); // This will keep track of the amount of data remaining in the payload // for the RT attributes. size_t attrLen = payloadLen - ifaceLen; // Iterate over all of the RT attributes, looking for a wireless one // and then dispatch to a separate function to parse the event. while (RTA_OK(attr, attrLen)) { const u_int8_t *data = ((const u_int8_t *) attr) + RTATTR_LEN; switch (attr->rta_type) { case IFLA_WIRELESS: { wlanifLinkEventsHandleIWEvent(state, data, attr->rta_len - RTATTR_LEN, band, ifaceInfo->ifi_index); break; } case IFLA_OPERSTATE: { wlanifLinkEventsHandleOperState(state, data, attr->rta_len - RTATTR_LEN, band, ifaceInfo->ifi_index); break; } default: { // Nop (other than a log) dbgf(state->dbgModule, DBGDUMP, "%s: Unhandled attribute: type=%04x len=%u", __func__, attr->rta_type, attr->rta_len); break; } } attr = RTA_NEXT(attr, attrLen); } if (attrLen != 0) { dbgf(state->dbgModule, DBGERR, "%s: Did not consume all attributes: %u bytes left", __func__, attrLen); } }
static struct if_nameindex * if_nameindex_netlink (void) { struct netlink_handle nh = { 0, 0, 0, NULL, NULL }; struct if_nameindex *idx = NULL; if (__no_netlink_support || __netlink_open (&nh) < 0) return NULL; /* Tell the kernel that we wish to get a list of all active interfaces. Collect all data for every interface. */ if (__netlink_request (&nh, RTM_GETLINK) < 0) goto exit_free; /* Count the interfaces. */ unsigned int nifs = 0; for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next) { struct nlmsghdr *nlh; size_t size = nlp->size; if (nlp->nlh == NULL) continue; /* Walk through all entries we got from the kernel and look, which message type they contain. */ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size)) { /* Check if the message is what we want. */ if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) break; /* ok */ if (nlh->nlmsg_type == RTM_NEWLINK) ++nifs; } } idx = malloc ((nifs + 1) * sizeof (struct if_nameindex)); if (idx == NULL) { nomem: __set_errno (ENOBUFS); goto exit_free; } /* Add the interfaces. */ nifs = 0; for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next) { struct nlmsghdr *nlh; size_t size = nlp->size; if (nlp->nlh == NULL) continue; /* Walk through all entries we got from the kernel and look, which message type they contain. */ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size)) { /* Check if the message is what we want. */ if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) break; /* ok */ if (nlh->nlmsg_type == RTM_NEWLINK) { struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh); struct rtattr *rta = IFLA_RTA (ifim); size_t rtasize = IFLA_PAYLOAD (nlh); idx[nifs].if_index = ifim->ifi_index; while (RTA_OK (rta, rtasize)) { char *rta_data = RTA_DATA (rta); size_t rta_payload = RTA_PAYLOAD (rta); if (rta->rta_type == IFLA_IFNAME) { idx[nifs].if_name = __strndup (rta_data, rta_payload); if (idx[nifs].if_name == NULL) { idx[nifs].if_index = 0; if_freenameindex (idx); idx = NULL; goto nomem; } break; } rta = RTA_NEXT (rta, rtasize); } ++nifs; } } } idx[nifs].if_index = 0; idx[nifs].if_name = NULL; exit_free: __netlink_free_handle (&nh); __netlink_close (&nh); return idx; }
int reportRoutinTable( int route_sock, FILE * fpRouting , struct timespec tv , char * ifNameVar) { int i,j; route_request *request = (route_request *)malloc(sizeof(route_request)); int retValue = -1,nbytes = 0,reply_len = 0; char reply_ptr[1024]; ssize_t counter = 1024; // int count = 0; struct rtmsg *rtp; struct rtattr *rtap; struct nlmsghdr *nlp; int rtl; struct RouteInfo route[24]; char* buf = reply_ptr; unsigned long bufsize ; char * outputRouting ; outputRouting = (char *)malloc(sizeof(char) * 1024); bzero(request,sizeof(route_request)); // Fill in the NETLINK header request->nlMsgHdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); request->nlMsgHdr.nlmsg_type = RTM_GETROUTE; request->nlMsgHdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; // set the routing message header request->rtMsg.rtm_family = AF_INET; request->rtMsg.rtm_table = 254; // Send routing request if ((retValue = send(route_sock, request, sizeof(route_request), 0)) < 0) { perror("send"); exit(1); } for(;;) { if( counter < sizeof( struct nlmsghdr)) { printf("Routing table is bigger than 1024\n"); exit(1); } nbytes = recv(route_sock, &reply_ptr[reply_len], counter, 0); if(nbytes < 0 ) { printf("Error in recv\n"); break; } if(nbytes == 0) printf("EOF in netlink\n"); nlp = (struct nlmsghdr*)(&reply_ptr[reply_len]); if (nlp->nlmsg_type == NLMSG_DONE) { // All data has been received. // Truncate the reply to exclude this message, // i.e. do not increase reply_len. break; } if (nlp->nlmsg_type == NLMSG_ERROR) { printf("Error in msg\n"); exit(1); } reply_len += nbytes; counter -= nbytes; } /*======================================================*/ bufsize = reply_len; // string to hold content of the route // table (i.e. one entry) // unsigned int flags; // outer loop: loops thru all the NETLINK // headers that also include the route entry // header nlp = (struct nlmsghdr *) buf; for(i= -1; NLMSG_OK(nlp, bufsize); nlp=NLMSG_NEXT(nlp, bufsize)) { // // get route entry header rtp = (struct rtmsg *) NLMSG_DATA(nlp); // we are only concerned about the // tableId route table if(rtp->rtm_table != 254) continue; i++; // init all the strings bzero(&route[i], sizeof(struct RouteInfo)); // flags = rtp->rtm_flags; // route[i].proto = rtp->rtm_protocol; // // 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: // count = 32 - rtp->rtm_dst_len; route[i].dstAddr = *(unsigned long *) RTA_DATA(rtap); break; case RTA_GATEWAY: route[i].gateWay = *(unsigned long *) RTA_DATA(rtap); //printf("gw:%s\t",inet_ntoa(route[i].gateWay)); break; // // unique ID associated with the network // // interface case RTA_OIF: ifname(*((int *) RTA_DATA(rtap)),route[i].ifName); //printf( "ifname %s\n", route[i].ifName); break; default: break; } } } for( j = 0; j<= i; j++) { if(strcmp(route[j].ifName, ifNameVar)==0) { char ipbuf[INET_ADDRSTRLEN]; char ipbuf2[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &route[j].dstAddr, ipbuf, INET_ADDRSTRLEN); inet_ntop(AF_INET, &route[j].gateWay, ipbuf2, INET_ADDRSTRLEN); sprintf(outputRouting, "%lu.%lu:%s:%s", (unsigned long) tv.tv_sec,(unsigned long) tv.tv_nsec, ipbuf ,ipbuf2); fprintf(fpRouting, "%s\n" ,outputRouting); } } fflush(fpRouting); // close(route_sock); return 0; }
static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdata) { AvahiInterfaceMonitor *m = userdata; /* This routine is called for every RTNETLINK response packet */ assert(m); assert(n); assert(m->osdep.netlink == nl); if (n->nlmsg_type == RTM_NEWLINK) { /* A new interface appeared or an existing one has been modified */ struct ifinfomsg *ifinfomsg = NLMSG_DATA(n); AvahiHwInterface *hw; struct rtattr *a = NULL; size_t l; /* A (superfluous?) sanity check */ if (ifinfomsg->ifi_family != AF_UNSPEC) return; /* Check whether there already is an AvahiHwInterface object * for this link, so that we can update its data. Note that * Netlink sends us an RTM_NEWLINK not only when a new * interface appears, but when it changes, too */ if (!(hw = avahi_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index))) /* No object found, so let's create a new * one. avahi_hw_interface_new() will call * avahi_interface_new() internally twice for IPv4 and * IPv6, so there is no need for us to do that * ourselves */ if (!(hw = avahi_hw_interface_new(m, (AvahiIfIndex) ifinfomsg->ifi_index))) return; /* OOM */ /* Check whether the flags of this interface are OK for us */ hw->flags_ok = (ifinfomsg->ifi_flags & IFF_UP) && (!m->server->config.use_iff_running || (ifinfomsg->ifi_flags & IFF_RUNNING)) && !(ifinfomsg->ifi_flags & IFF_LOOPBACK) && (ifinfomsg->ifi_flags & IFF_MULTICAST) && (m->server->config.allow_point_to_point || !(ifinfomsg->ifi_flags & IFF_POINTOPOINT)); /* Handle interface attributes */ l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg)); a = IFLA_RTA(ifinfomsg); while (RTA_OK(a, l)) { switch(a->rta_type) { case IFLA_IFNAME: /* Fill in interface name */ avahi_free(hw->name); hw->name = avahi_strndup(RTA_DATA(a), RTA_PAYLOAD(a)); break; case IFLA_MTU: /* Fill in MTU */ assert(RTA_PAYLOAD(a) == sizeof(unsigned int)); hw->mtu = *((unsigned int*) RTA_DATA(a)); break; case IFLA_ADDRESS: /* Fill in hardware (MAC) address */ hw->mac_address_size = RTA_PAYLOAD(a); if (hw->mac_address_size > AVAHI_MAC_ADDRESS_MAX) hw->mac_address_size = AVAHI_MAC_ADDRESS_MAX; memcpy(hw->mac_address, RTA_DATA(a), hw->mac_address_size); break; default: ; } a = RTA_NEXT(a, l); } /* Check whether this interface is now "relevant" for us. If * it is Avahi will start to announce its records on this * interface and send out queries for subscribed records on * it */ avahi_hw_interface_check_relevant(hw, AVAHI_MDNS); avahi_hw_interface_check_relevant(hw, AVAHI_LLMNR); /* Update any associated RRs of this interface. (i.e. the * _workstation._tcp record containing the MAC address) */ avahi_hw_interface_update_rrs(hw, 0); } else if (n->nlmsg_type == RTM_DELLINK) { /* An interface has been removed */ struct ifinfomsg *ifinfomsg = NLMSG_DATA(n); AvahiHwInterface *hw; /* A (superfluous?) sanity check */ if (ifinfomsg->ifi_family != AF_UNSPEC) return; /* Get a reference to our AvahiHwInterface object of this interface */ if (!(hw = avahi_interface_monitor_get_hw_interface(m, (AvahiIfIndex) ifinfomsg->ifi_index))) return; /* Free our object */ avahi_hw_interface_free(hw, 0); } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) { /* An address has been added, modified or removed */ struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n); AvahiInterface *i; struct rtattr *a = NULL; size_t l; AvahiAddress raddr, rlocal, *r; int raddr_valid = 0, rlocal_valid = 0; /* We are only interested in IPv4 and IPv6 */ if (ifaddrmsg->ifa_family != AF_INET && ifaddrmsg->ifa_family != AF_INET6) return; /* Try to get a reference to our AvahiInterface object for the * interface this address is assigned to. If ther is no object * for this interface, we ignore this address. */ if (!(i = avahi_interface_monitor_get_interface(m, (AvahiIfIndex) ifaddrmsg->ifa_index, avahi_af_to_proto(ifaddrmsg->ifa_family)))) return; /* Fill in address family for our new address */ rlocal.proto = raddr.proto = avahi_af_to_proto(ifaddrmsg->ifa_family); l = NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg)); a = IFA_RTA(ifaddrmsg); while (RTA_OK(a, l)) { switch(a->rta_type) { case IFA_ADDRESS: if ((rlocal.proto == AVAHI_PROTO_INET6 && RTA_PAYLOAD(a) != 16) || (rlocal.proto == AVAHI_PROTO_INET && RTA_PAYLOAD(a) != 4)) return; memcpy(rlocal.data.data, RTA_DATA(a), RTA_PAYLOAD(a)); rlocal_valid = 1; break; case IFA_LOCAL: /* Fill in local address data. Usually this is * preferable over IFA_ADDRESS if both are set, * since this refers to the local address of a PPP * link while IFA_ADDRESS refers to the other * end. */ if ((raddr.proto == AVAHI_PROTO_INET6 && RTA_PAYLOAD(a) != 16) || (raddr.proto == AVAHI_PROTO_INET && RTA_PAYLOAD(a) != 4)) return; memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a)); raddr_valid = 1; break; default: ; } a = RTA_NEXT(a, l); } /* If there was no adress attached to this message, let's quit. */ if (rlocal_valid) r = &rlocal; else if (raddr_valid) r = &raddr; else return; if (n->nlmsg_type == RTM_NEWADDR) { AvahiInterfaceAddress *addr; /* This address is new or has been modified, so let's get an object for it */ if (!(addr = avahi_interface_monitor_get_address(m, i, r))) /* Mmm, no object existing yet, so let's create a new one */ if (!(addr = avahi_interface_address_new(m, i, r, ifaddrmsg->ifa_prefixlen))) return; /* OOM */ /* Update the scope field for the address */ addr->global_scope = ifaddrmsg->ifa_scope == RT_SCOPE_UNIVERSE || ifaddrmsg->ifa_scope == RT_SCOPE_SITE; addr->deprecated = !!(ifaddrmsg->ifa_flags & IFA_F_DEPRECATED); } else { AvahiInterfaceAddress *addr; assert(n->nlmsg_type == RTM_DELADDR); /* Try to get a reference to our AvahiInterfaceAddress object for this address */ if (!(addr = avahi_interface_monitor_get_address(m, i, r))) return; /* And free it */ avahi_interface_address_free(addr); } /* Avahi only considers interfaces with at least one address * attached relevant. Since we migh have added or removed an * address, let's have it check again whether the interface is * now relevant */ avahi_interface_check_relevant(i, AVAHI_MDNS); avahi_interface_check_relevant(i, AVAHI_LLMNR); /* Update any associated RRs, like A or AAAA for our new/removed address */ avahi_interface_update_rrs(i, 0); } else if (n->nlmsg_type == NLMSG_DONE) { /* This wild dump request ended, so let's see what we do next */ if (m->osdep.list == LIST_IFACE) { /* Mmmm, interfaces have been wild dumped already, so * let's go on with wild dumping the addresses */ if (netlink_list_items(m->osdep.netlink, RTM_GETADDR, &m->osdep.query_addr_seq) < 0) { avahi_log_warn("NETLINK: Failed to list addrs: %s", strerror(errno)); m->osdep.list = LIST_DONE; } else /* Update state information */ m->osdep.list = LIST_ADDR; } else /* We're done. Tell avahi_interface_monitor_sync() to finish. */ m->osdep.list = LIST_DONE; if (m->osdep.list == LIST_DONE) { /* Only after this boolean variable has been set, Avahi * will start to announce or browse on all interfaces. It * is originaly set to 0, which means that relevancy * checks and RR updates are disabled during the wild * dumps. */ m->list_complete = 1; /* So let's check if any interfaces are relevant now */ avahi_interface_monitor_check_relevant(m, AVAHI_MDNS); avahi_interface_monitor_check_relevant(m, AVAHI_LLMNR); /* And update all RRs attached to any interface */ avahi_interface_monitor_update_rrs(m, 0); /* Tell the user that the wild dump is complete */ avahi_log_info("Network interface enumeration completed."); } } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->osdep.query_link_seq || n->nlmsg_seq == m->osdep.query_addr_seq)) { struct nlmsgerr *e = NLMSG_DATA (n); /* Some kind of error happened. Let's just tell the user and * ignore it otherwise */ if (e->error) avahi_log_warn("NETLINK: Failed to browse: %s", strerror(-e->error)); } }
static void get_if_prefix(struct nlmsghdr *nlm, int nlm_len, int request, struct dhcp6_if *ifp) { struct rtmsg *rtm = (struct rtmsg *)NLMSG_DATA(nlm); struct rtattr *rta; size_t rtasize, rtapayload; void *rtadata; struct ra_info *rainfo; char addr[64]; if (rtm->rtm_family != AF_INET6 || nlm->nlmsg_type != request) return; if (!(rtm->rtm_flags & RTM_F_PREFIX)) return; rtasize = NLMSG_PAYLOAD(nlm, nlm_len) - NLMSG_ALIGN(sizeof(*rtm)); rta = (struct rtattr *) (((char *) NLMSG_DATA(nlm)) + NLMSG_ALIGN(sizeof(*rtm))); if (!RTA_OK(rta, rtasize)) return; rtadata = RTA_DATA(rta); rtapayload = RTA_PAYLOAD(rta); switch(rta->rta_type) { case RTA_OIF: break; default: break; } switch (rta->rta_type) { case RTA_DST: rainfo = (struct ra_info *)malloc(sizeof(*rainfo)); if (rainfo == NULL) return; memset(rainfo, 0, sizeof(rainfo)); memcpy(&(rainfo->prefix), (struct in6_addr *)rtadata, sizeof(struct in6_addr)); rainfo->plen = rtm->rtm_dst_len; if (ifp->ralist == NULL) { ifp->ralist = rainfo; rainfo->next = NULL; } else { struct ra_info *ra, *ra_prev; ra_prev = ifp->ralist; for (ra = ifp->ralist; ra; ra = ra->next) { if (rainfo->plen >= ra->plen) { if (ra_prev == ra) { ifp->ralist = rainfo; rainfo->next = ra; } else { ra_prev->next = rainfo; rainfo->next = ra; } break; } else { if (ra->next == NULL) { ra->next = rainfo; rainfo->next = NULL; break; } else { ra_prev = ra; continue; } } } } inet_ntop(AF_INET6, &(rainfo->prefix), addr, INET6_ADDRSTRLEN); dprintf(LOG_DEBUG, "get prefix address %s", addr); dprintf(LOG_DEBUG, "get prefix plen %d",rtm->rtm_dst_len); break; case RTA_CACHEINFO: dprintf(LOG_DEBUG, "prefix route life time is %d\n", ((struct rta_cacheinfo *)rtadata)->rta_expires); break; default: break; } return; }
void process_nl_new_route (struct nlmsghdr *nlh) { struct rtmsg *rtm = NULL; struct rtattr *rt_attr = NULL; int rt_length = 0; lispd_iface_elt *iface = NULL; int iface_index = 0; char iface_name[IF_NAMESIZE]; lisp_addr_t gateway = {.afi=AF_UNSPEC}; lisp_addr_t dst = {.afi=AF_UNSPEC};; rtm = (struct rtmsg *) NLMSG_DATA (nlh); if ((rtm->rtm_family != AF_INET) && (rtm->rtm_family != AF_INET6)) { lispd_log_msg(LISP_LOG_DEBUG_2,"process_nl_new_route: Unknown adddress family"); return; } if (rtm->rtm_table != RT_TABLE_MAIN) { /* Not interested in routes/gateways affecting tables other the main routing table */ return; } rt_attr = (struct rtattr *)RTM_RTA(rtm); rt_length = RTM_PAYLOAD(nlh); for (; RTA_OK(rt_attr, rt_length); rt_attr = RTA_NEXT(rt_attr, rt_length)) { switch (rt_attr->rta_type) { case RTA_OIF: iface_index = *(int *)RTA_DATA(rt_attr); iface = get_interface_from_index(iface_index); if_indextoname(iface_index, iface_name); if (iface == NULL) { lispd_log_msg(LISP_LOG_DEBUG_2, "process_nl_new_route: the netlink message is not for any interface associated with RLOCs (%s)", iface_name); return; } break; case RTA_GATEWAY: gateway.afi = rtm->rtm_family; switch (gateway.afi) { case AF_INET: memcpy(&(gateway.address),(struct in_addr *)RTA_DATA(rt_attr), sizeof(struct in_addr)); break; case AF_INET6: memcpy(&(gateway.address),(struct in6_addr *)RTA_DATA(rt_attr), sizeof(struct in6_addr)); break; default: break; } break; case RTA_DST: // We check if the new route message contains a destintaion. If it is, then the gateway address is not a default route. Discard it dst.afi = rtm->rtm_family; switch (dst.afi) { case AF_INET: memcpy(&(dst.address),(struct in_addr *)RTA_DATA(rt_attr), sizeof(struct in_addr)); break; case AF_INET6: memcpy(&(dst.address),(struct in6_addr *)RTA_DATA(rt_attr), sizeof(struct in6_addr)); break; default: break; } break; default: break; } } if (gateway.afi != AF_UNSPEC && iface_index != 0 && dst.afi == AF_UNSPEC) { /* Check default afi*/ if (default_rloc_afi != AF_UNSPEC && default_rloc_afi != gateway.afi) { lispd_log_msg(LISP_LOG_DEBUG_1, "process_nl_new_route: Default RLOC afi defined (-a #): Skipped %s gateway in iface %s", (gateway.afi == AF_INET) ? "IPv4" : "IPv6",iface->iface_name); return; } /* Check if the addres is a global address*/ if (is_link_local_addr(gateway) == TRUE) { lispd_log_msg(LISP_LOG_DEBUG_2,"process_nl_new_route: the extractet address from the netlink " "messages is a local link address: %s discarded", get_char_from_lisp_addr_t(gateway)); return; } /* Process the new gateway */ lispd_log_msg(LISP_LOG_DEBUG_1, "process_nl_new_route: Process new gateway associated to the interface %s: %s", iface_name, get_char_from_lisp_addr_t(gateway)); process_new_gateway(gateway,iface); } }
static __inline__ int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) { struct rtnetlink_link *link; struct rtnetlink_link *link_tab; int sz_idx, kind; int min_len; int family; int type; int err; /* Only requests are handled by kernel now */ if (!(nlh->nlmsg_flags&NLM_F_REQUEST)) return 0; type = nlh->nlmsg_type; /* A control message: ignore them */ if (type < RTM_BASE) return 0; /* Unknown message: reply with EINVAL */ if (type > RTM_MAX) goto err_inval; type -= RTM_BASE; /* All the messages must have at least 1 byte length */ if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) return 0; family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; if (family >= NPROTO) { *errp = -EAFNOSUPPORT; return -1; } link_tab = rtnetlink_links[family]; if (link_tab == NULL) link_tab = rtnetlink_links[PF_UNSPEC]; link = &link_tab[type]; sz_idx = type>>2; kind = type&3; if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) { *errp = -EPERM; return -1; } if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { if (link->dumpit == NULL) link = &(rtnetlink_links[PF_UNSPEC][type]); if (link->dumpit == NULL) goto err_inval; if ((*errp = netlink_dump_start(rtnl, skb, nlh, link->dumpit, NULL)) != 0) { return -1; } netlink_queue_skip(nlh, skb); return -1; } memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); min_len = rtm_min[sz_idx]; if (nlh->nlmsg_len < min_len) goto err_inval; if (nlh->nlmsg_len > min_len) { int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len); while (RTA_OK(attr, attrlen)) { unsigned flavor = attr->rta_type; if (flavor) { if (flavor > rta_max[sz_idx]) goto err_inval; rta_buf[flavor-1] = attr; } attr = RTA_NEXT(attr, attrlen); } } if (link->doit == NULL) link = &(rtnetlink_links[PF_UNSPEC][type]); if (link->doit == NULL) goto err_inval; err = link->doit(skb, nlh, (void *)&rta_buf[0]); *errp = err; return err; err_inval: *errp = -EINVAL; return -1; }
static NOINLINE int check_existence_through_netlink(void) { int iface_len; /* Buffer was 1K, but on linux-3.9.9 it was reported to be too small. * netlink.h: "limit to 8K to avoid MSG_TRUNC when PAGE_SIZE is very large". * Note: on error returns (-1) we exit, no need to free replybuf. */ enum { BUF_SIZE = 8 * 1024 }; char *replybuf = xmalloc(BUF_SIZE); iface_len = strlen(G.iface); while (1) { struct nlmsghdr *mhdr; ssize_t bytes; bytes = recv(netlink_fd, replybuf, BUF_SIZE, MSG_DONTWAIT); if (bytes < 0) { if (errno == EAGAIN) goto ret; if (errno == EINTR) continue; bb_perror_msg("netlink: recv"); return -1; } mhdr = (struct nlmsghdr*)replybuf; while (bytes > 0) { if (!NLMSG_OK(mhdr, bytes)) { bb_error_msg("netlink packet too small or truncated"); return -1; } if (mhdr->nlmsg_type == RTM_NEWLINK || mhdr->nlmsg_type == RTM_DELLINK) { struct rtattr *attr; int attr_len; if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) { bb_error_msg("netlink packet too small or truncated"); return -1; } attr = IFLA_RTA(NLMSG_DATA(mhdr)); attr_len = IFLA_PAYLOAD(mhdr); while (RTA_OK(attr, attr_len)) { if (attr->rta_type == IFLA_IFNAME) { int len = RTA_PAYLOAD(attr); if (len > IFNAMSIZ) len = IFNAMSIZ; if (iface_len <= len && strncmp(G.iface, RTA_DATA(attr), len) == 0 ) { G.iface_exists = (mhdr->nlmsg_type == RTM_NEWLINK); } } attr = RTA_NEXT(attr, attr_len); } } mhdr = NLMSG_NEXT(mhdr, bytes); } } ret: free(replybuf); return G.iface_exists; }
static __inline__ int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) { struct rtnetlink_link *link; struct rtnetlink_link *link_tab; struct rtattr *rta[RTATTR_MAX]; int exclusive = 0; int sz_idx, kind; int min_len; int family; int type; int err; /* Only requests are handled by kernel now */ if (!(nlh->nlmsg_flags&NLM_F_REQUEST)) return 0; type = nlh->nlmsg_type; /* A control message: ignore them */ if (type < RTM_BASE) return 0; /* Unknown message: reply with EINVAL */ if (type > RTM_MAX) goto err_inval; type -= RTM_BASE; /* All the messages must have at least 1 byte length */ if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) return 0; family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; if (family > NPROTO) { *errp = -EAFNOSUPPORT; return -1; } link_tab = rtnetlink_links[family]; if (link_tab == NULL) link_tab = rtnetlink_links[PF_UNSPEC]; link = &link_tab[type]; sz_idx = type>>2; kind = type&3; if (kind != 2 && !cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) { *errp = -EPERM; return -1; } if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { u32 rlen; if (link->dumpit == NULL) link = &(rtnetlink_links[PF_UNSPEC][type]); if (link->dumpit == NULL) goto err_inval; if ((*errp = netlink_dump_start(rtnl, skb, nlh, link->dumpit, rtnetlink_done)) != 0) { return -1; } rlen = NLMSG_ALIGN(nlh->nlmsg_len); if (rlen > skb->len) rlen = skb->len; skb_pull(skb, rlen); return -1; } if (kind != 2) { if (rtnl_exlock_nowait()) { *errp = 0; return -1; } exclusive = 1; } memset(&rta, 0, sizeof(rta)); min_len = rtm_min[sz_idx]; if (nlh->nlmsg_len < min_len) goto err_inval; if (nlh->nlmsg_len > min_len) { int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len); while (RTA_OK(attr, attrlen)) { unsigned flavor = attr->rta_type; if (flavor) { if (flavor > rta_max[sz_idx]) goto err_inval; rta[flavor-1] = attr; } attr = RTA_NEXT(attr, attrlen); } } if (link->doit == NULL) link = &(rtnetlink_links[PF_UNSPEC][type]); if (link->doit == NULL) goto err_inval; err = link->doit(skb, nlh, (void *)&rta); if (exclusive) rtnl_exunlock(); *errp = err; return err; err_inval: if (exclusive) rtnl_exunlock(); *errp = -EINVAL; return -1; }
static void rtnl_print_neigh(struct nlmsghdr *hdr) { struct ndmsg *ndm = NLMSG_DATA(hdr); uint32_t attrs_len = NDA_PAYLOAD(hdr); struct rtattr *attr = NDA_RTA(ndm); struct nda_cacheinfo *ci; int hz = get_user_hz(); char addr_str[256]; char hw_addr[30]; char states[256]; char flags[256]; tprintf(" [ Neigh Family %d (%s%s%s)", ndm->ndm_family, colorize_start(bold), addr_family2str(ndm->ndm_family), colorize_end()); tprintf(", Link Index %d", ndm->ndm_ifindex); tprintf(", State %d (%s%s%s)", ndm->ndm_state, colorize_start(bold), flags2str(neigh_states, ndm->ndm_state, states, sizeof(states)), colorize_end()); tprintf(", Flags %d (%s%s%s)", ndm->ndm_flags, colorize_start(bold), flags2str(neigh_flags, ndm->ndm_flags, flags, sizeof(flags)), colorize_end()); tprintf(", Type %d (%s%s%s)", ndm->ndm_type, colorize_start(bold), route_type2str(ndm->ndm_type), colorize_end()); tprintf(" ]\n"); for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) { switch (attr->rta_type) { case NDA_DST: attr_fmt(attr, "Address %s", addr2str(ndm->ndm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case NDA_LLADDR: attr_fmt(attr, "HW Address %s", device_addr2str(RTA_DATA(attr), RTA_LEN(attr), 0, hw_addr, sizeof(hw_addr))); break; case NDA_PROBES: attr_fmt(attr, "Probes %d", RTA_UINT32(attr)); break; case NDA_CACHEINFO: ci = RTA_DATA(attr); tprintf("\tA: Cache ("); tprintf("confirmed(%ds)", ci->ndm_confirmed / hz); tprintf(", used(%ds)", ci->ndm_used / hz); tprintf(", updated(%ds)", ci->ndm_updated / hz); tprintf(", refcnt(%d))", ci->ndm_refcnt); tprintf(", Len %lu\n", RTA_LEN(attr)); break; } } }
/** * @brief This function parses for IWEVENT events * * @param h Pointer to Netlink message header * @param left Number of bytes to be read * @param evt_conn A pointer to a output buffer. It sets TRUE when it gets * the event CUS_EVT_OBSS_SCAN_PARAM, otherwise FALSE * @return Number of bytes left to be read */ static int drv_iwevt_handler(struct nlmsghdr *h, int left, int *evt_conn) { int len, plen, attrlen, nlmsg_len, rta_len; struct ifinfomsg *ifi; struct rtattr *attr; *evt_conn = FALSE; while (left >= sizeof(*h)) { len = h->nlmsg_len; plen = len - sizeof(*h); if (len > left || plen < 0) { /* malformed netlink message */ break; } if (plen < sizeof(*ifi)) { break; } ifi = NLMSG_DATA(h); nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); attrlen = h->nlmsg_len - nlmsg_len; if (attrlen < 0) { break; } attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_WIRELESS) { struct iw_event *iwe; char *pos = ((char *) attr) + rta_len; char *end = pos + (attr->rta_len - rta_len); unsigned short dlen; while (pos + IW_EV_LCP_LEN <= end) { iwe = (struct iw_event *) pos; if (iwe->len <= IW_EV_LCP_LEN) break; switch (iwe->cmd) { case SIOCGIWAP: { struct ether_addr *wap; struct ether_addr etherzero = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; char buf[32]; wap = (struct ether_addr *) ((struct sockaddr *) (&iwe->u.ap_addr))-> sa_data; if (!memcmp (wap, ðerzero, sizeof(struct ether_addr))) { printf("---< Disconnected from AP >---\n"); memset(&cur_obss_scan_param, 0, sizeof(cur_obss_scan_param)); assoc_flag = FALSE; is_ht_ap = FALSE; } else { memset(buf, 0, sizeof(buf)); sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", wap->ether_addr_octet[0], wap->ether_addr_octet[1], wap->ether_addr_octet[2], wap->ether_addr_octet[3], wap->ether_addr_octet[4], wap->ether_addr_octet[5]); printf("---< Connected to AP: %s >---\n", buf); /** set TRUE, if connected */ assoc_flag = TRUE; } pos += iwe->len; } break; case IWEVCUSTOM: { char *custom; custom = pos + IW_EV_POINT_LEN; if (IW_EV_POINT_LEN == IW_EV_LCP_LEN + sizeof(struct iw_point)) { dlen = iwe->u.data.length; } else { /* WIRELESS_EXT >= 19 */ dlen = *((unsigned short *) (pos + IW_EV_LCP_LEN)); } if (custom + dlen > end) break; printf("---< %s >---\n", custom); if (!strncmp (CUS_EVT_OBSS_SCAN_PARAM, custom, strlen(CUS_EVT_OBSS_SCAN_PARAM))) { memset(&cur_obss_scan_param, 0, sizeof(cur_obss_scan_param)); memcpy(&cur_obss_scan_param, (custom + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1), sizeof(cur_obss_scan_param)); /** set TRUE, since it is an HT AP */ is_ht_ap = TRUE; *evt_conn = TRUE; } pos += iwe->len; } break; default: pos += iwe->len; break; } } } attr = RTA_NEXT(attr, attrlen); } len = NLMSG_ALIGN(len); left -= len; h = (struct nlmsghdr *) ((char *) h + len); } return left; }
rtnetlink::if_link& rtnetlink::if_link::operator=(message& msg) { static_cast<data&>(*this) = msg; std::pair<const void*, size_t> pl = msg.payload(); if (msg.type() < 16 || msg.type() > 19 || pl.second < sizeof(::ifinfomsg)) throw "bad msg type"; const ::ifinfomsg* ifi = reinterpret_cast<const ifinfomsg*>(pl.first); _type = ifi->ifi_type; _index = ifi->ifi_index; _flags = ifi->ifi_flags; const ::rtattr* rta = IFLA_RTA(ifi); size_t attrlen = IFLA_PAYLOAD(reinterpret_cast<const ::nlmsghdr*>(_msg->header())); for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) { switch (rta->rta_type) { case IFLA_ADDRESS: _address = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFLA_BROADCAST: _bcast_addr = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFLA_IFNAME: _name = attr<char>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFLA_MTU: ODTONE_ASSERT(sizeof(odtone::uint) == RTA_PAYLOAD(rta)); _mtu = reinterpret_cast<odtone::uint*>(RTA_DATA(rta)); break; case IFLA_LINK: ODTONE_ASSERT(sizeof(odtone::sint) == RTA_PAYLOAD(rta)); _link_type = reinterpret_cast<odtone::sint*>(RTA_DATA(rta)); break; case IFLA_QDISC: _qdisc = attr<char>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; case IFLA_STATS: ODTONE_ASSERT(sizeof(::rtnl_link_stats) == RTA_PAYLOAD(rta)); _stats = RTA_DATA(rta); break; case IFLA_WIRELESS: std::cout << "IFLA_WIRELESS(" << rta->rta_type << ", " << RTA_PAYLOAD(rta) << ")\n"; // std::cout << "\tcmd: " // << reinterpret_cast<iw_event*>(RTA_DATA(rta))->cmd // << " len: " // << reinterpret_cast<iw_event*>(RTA_DATA(rta))->len // << std::endl; _wifi = attr<void>(RTA_DATA(rta), RTA_PAYLOAD(rta)); break; default: std::cout << "IFLA_UNSPEC(" << rta->rta_type << ", " << RTA_PAYLOAD(rta) << ")\n"; } } return *this; }
int netlink_input_packet(struct rproto *netlink, void *buf, unsigned int len, struct sockaddr *from, int fromlen) { // struct rtable *learn_table,*unlearn_table; // struct sockaddr_nl *origin = (struct sockaddr_nl *)from; struct nlmsghdr *nh; char content[128] = ""; struct ifinfomsg *ifinfo; /* struct ifaddrmsg *addrinfo; struct rtmsg *rtinfo;*/ nh = (struct nlmsghdr *)buf; switch(nh->nlmsg_type) { case RTM_NEWLINK: ifinfo = (struct ifinfomsg *)NLMSG_DATA(nh); #ifdef DEBUG { int rtlen; struct rtattr *rta; rtlen=RTM_PAYLOAD(nh); rta=RTM_RTA(ifinfo); /* little hack.. UNSPEC has len==1. This doesn't go well with * RTA_OK macro.. */ if (rta->rta_type == IFLA_UNSPEC) rta->rta_len=4; while (RTA_OK(rta, rtlen)) { if (rta->rta_type == IFLA_IFNAME) log_msg("Netlink interface: %s", RTA_DATA(rta)); rta=RTA_NEXT(rta,rtlen); } } #endif if((ifinfo->ifi_flags & IFF_UP) && (ifinfo->ifi_flags & IFF_RUNNING)) { linklist_update(); snprintf(content,sizeof(content),"Iface %d is going up",ifinfo->ifi_index); }else{ linklist_update(); snprintf(content,sizeof(content),"Iface %d is going down",ifinfo->ifi_index); } break; default: return 0; } log_msg("Netlink: %s",content); /* learn_table = new_rtable(); unlearn_table = new_rtable(); if(learn_table->num_routes != 0) learn_routes(netlink,learn_table); if(unlearn_table->num_routes != 0) unlearn_routes(netlink,unlearn_table); free_rtable(learn_table); free_rtable(unlearn_table);*/ return 0; }
static void __handle_netlink_response(ifaddrs** out, nlmsghdr* hdr) { if (hdr->nlmsg_type == RTM_NEWLINK) { ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr)); // Create a new ifaddr entry, and set the interface index and flags. ifaddrs_storage* new_addr = new ifaddrs_storage(out); new_addr->interface_index = ifi->ifi_index; new_addr->ifa.ifa_flags = ifi->ifi_flags; // Go through the various bits of information and find the name. rtattr* rta = IFLA_RTA(ifi); size_t rta_len = IFLA_PAYLOAD(hdr); while (RTA_OK(rta, rta_len)) { if (rta->rta_type == IFLA_ADDRESS) { if (RTA_PAYLOAD(rta) < sizeof(new_addr->addr)) { new_addr->SetAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); } } else if (rta->rta_type == IFLA_BROADCAST) { if (RTA_PAYLOAD(rta) < sizeof(new_addr->ifa_ifu)) { new_addr->SetBroadcastAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); } } else if (rta->rta_type == IFLA_IFNAME) { if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) { memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta)); new_addr->ifa.ifa_name = new_addr->name; } } rta = RTA_NEXT(rta, rta_len); } } else if (hdr->nlmsg_type == RTM_NEWADDR) { ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr)); // We should already know about this from an RTM_NEWLINK message. const ifaddrs_storage* addr = reinterpret_cast<const ifaddrs_storage*>(*out); while (addr != nullptr && addr->interface_index != static_cast<int>(msg->ifa_index)) { addr = reinterpret_cast<const ifaddrs_storage*>(addr->ifa.ifa_next); } // If this is an unknown interface, ignore whatever we're being told about it. if (addr == nullptr) return; // Create a new ifaddr entry and copy what we already know. ifaddrs_storage* new_addr = new ifaddrs_storage(out); // We can just copy the name rather than look for IFA_LABEL. strcpy(new_addr->name, addr->name); new_addr->ifa.ifa_name = new_addr->name; new_addr->ifa.ifa_flags = addr->ifa.ifa_flags; new_addr->interface_index = addr->interface_index; // Go through the various bits of information and find the address // and any broadcast/destination address. rtattr* rta = IFA_RTA(msg); size_t rta_len = IFA_PAYLOAD(hdr); while (RTA_OK(rta, rta_len)) { if (rta->rta_type == IFA_ADDRESS) { if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { new_addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); new_addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen); } } else if (rta->rta_type == IFA_BROADCAST) { if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { new_addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); } } rta = RTA_NEXT(rta, rta_len); } } }
static int aead_authenc_setkey(struct crypto_aead *aead, const u8 *key, unsigned int keylen) { /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *dev = ctx->dev; struct rtattr *rta = (void *)key; struct crypto_authenc_key_param *param; unsigned int authkeylen; unsigned int enckeylen; int ret = 0; if (!RTA_OK(rta, keylen)) goto badkey; if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) goto badkey; if (RTA_PAYLOAD(rta) < sizeof(*param)) goto badkey; param = RTA_DATA(rta); enckeylen = be32_to_cpu(param->enckeylen); key += RTA_ALIGN(rta->rta_len); keylen -= RTA_ALIGN(rta->rta_len); if (keylen < enckeylen) goto badkey; authkeylen = keylen - enckeylen; if (keylen > CAAM_MAX_KEY_SIZE) goto badkey; /* Pick class 2 key length from algorithm submask */ ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT] * 2; ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); #ifdef DEBUG printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", keylen, enckeylen, authkeylen); printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", ctx->split_key_len, ctx->split_key_pad_len); print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, CAAM_MAX_KEY_SIZE, 1); #endif ctx->key = kzalloc(ctx->split_key_pad_len + enckeylen, GFP_KERNEL | GFP_DMA); if (!ctx->key) { dev_err(ctx->dev, "could not allocate key output memory\n"); return -ENOMEM; } ret = gen_split_key(dev, ctx, key, authkeylen); if (ret) goto badkey; /* postpend encryption key to auth split key */ memcpy(ctx->key + ctx->split_key_pad_len, key + authkeylen, enckeylen); ctx->key_phys = dma_map_single(dev, ctx->key, ctx->split_key_pad_len + enckeylen, DMA_TO_DEVICE); if (dma_mapping_error(dev, ctx->key_phys)) { dev_err(dev, "unable to map key i/o memory\n"); return -ENOMEM; } #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, CAAM_MAX_KEY_SIZE, 1); #endif ctx->keylen = keylen; ctx->enckeylen = enckeylen; ctx->authkeylen = authkeylen; return ret; badkey: crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; }
/** * Scan netlink message in the buffer for IPv6 default route changes. */ static int rtmon_check_defaults(const void *buf, size_t len) { struct nlmsghdr *nh; int dfltdiff = 0; for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { struct rtmsg *rtm; struct rtattr *rta; int attrlen; int delta = 0; const void *gwbuf; size_t gwlen; int oif; DPRINTF2(("nlmsg type %d flags 0x%x\n", nh->nlmsg_seq, nh->nlmsg_type, nh->nlmsg_flags)); if (nh->nlmsg_type == NLMSG_DONE) { break; } if (nh->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh); DPRINTF2(("> error %d\n", ne->error)); LWIP_UNUSED_ARG(ne); break; } if (nh->nlmsg_type < RTM_BASE || RTM_MAX <= nh->nlmsg_type) { /* shouldn't happen */ DPRINTF2(("> not an RTM message!\n")); continue; } rtm = (struct rtmsg *)NLMSG_DATA(nh); attrlen = RTM_PAYLOAD(nh); if (nh->nlmsg_type == RTM_NEWROUTE) { delta = +1; } else if (nh->nlmsg_type == RTM_DELROUTE) { delta = -1; } else { /* shouldn't happen */ continue; } /* * Is this an IPv6 default route in the main table? (Local * table always has ::/0 reject route, hence the last check). */ if (rtm->rtm_family == AF_INET6 /* should always be true */ && rtm->rtm_dst_len == 0 && rtm->rtm_table == RT_TABLE_MAIN) { dfltdiff += delta; } else { /* some other route change */ continue; } gwbuf = NULL; gwlen = 0; oif = -1; for (rta = RTM_RTA(rtm); RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) { if (rta->rta_type == RTA_GATEWAY) { gwbuf = RTA_DATA(rta); gwlen = RTA_PAYLOAD(rta); } else if (rta->rta_type == RTA_OIF) { /* assert RTA_PAYLOAD(rta) == 4 */ memcpy(&oif, RTA_DATA(rta), sizeof(oif)); } } /* XXX: TODO: note that { oif, gw } was added/removed */ LWIP_UNUSED_ARG(gwbuf); LWIP_UNUSED_ARG(gwlen); LWIP_UNUSED_ARG(oif); } return dfltdiff; }
static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) { struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); size_t l_nameSize = 0; size_t l_addrSize = 0; size_t l_dataSize = 0; size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); struct rtattr *l_rta; for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFLA_ADDRESS: case IFLA_BROADCAST: l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); break; case IFLA_IFNAME: l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); break; case IFLA_STATS: l_dataSize += NLMSG_ALIGN(l_rtaSize); break; default: break; } } struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize); memset(l_entry, 0, sizeof(struct ifaddrs)); l_entry->ifa_name = ""; char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); char *l_addr = l_name + l_nameSize; char *l_data = l_addr + l_addrSize; l_entry->ifa_flags = l_info->ifi_flags; l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { void *l_rtaData = RTA_DATA(l_rta); size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFLA_ADDRESS: case IFLA_BROADCAST: { size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; if(l_rta->rta_type == IFLA_ADDRESS) { l_entry->ifa_addr = (struct sockaddr *)l_addr; } else { l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; } l_addr += NLMSG_ALIGN(l_addrLen); break; } case IFLA_IFNAME: strncpy(l_name, l_rtaData, l_rtaDataSize); l_name[l_rtaDataSize] = '\0'; l_entry->ifa_name = l_name; break; case IFLA_STATS: memcpy(l_data, l_rtaData, l_rtaDataSize); l_entry->ifa_data = l_data; break; default: break; } } addToEnd(p_resultList, l_entry); p_links[l_info->ifi_index - 1] = l_entry; }
// Detect an IPV6-address currently assigned to the given interface ssize_t relayd_get_interface_addresses(int ifindex, struct relayd_ipaddr *addrs, size_t cnt) { struct { struct nlmsghdr nhm; struct ifaddrmsg ifa; } req = {{sizeof(req), RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP, ++rtnl_seq, 0}, {AF_INET6, 0, 0, 0, ifindex}}; if (send(rtnl_socket, &req, sizeof(req), 0) < (ssize_t)sizeof(req)) return 0; uint8_t buf[8192]; ssize_t len = 0, ret = 0; for (struct nlmsghdr *nhm = NULL; ; nhm = NLMSG_NEXT(nhm, len)) { while (len < 0 || !NLMSG_OK(nhm, (size_t)len)) { len = recv(rtnl_socket, buf, sizeof(buf), 0); nhm = (struct nlmsghdr*)buf; if (len < 0 || !NLMSG_OK(nhm, (size_t)len)) { if (errno == EINTR) continue; else return ret; } } if (nhm->nlmsg_type != RTM_NEWADDR) break; // Skip address but keep clearing socket buffer if (ret >= (ssize_t)cnt) continue; struct ifaddrmsg *ifa = NLMSG_DATA(nhm); if (ifa->ifa_scope != RT_SCOPE_UNIVERSE || ifa->ifa_index != (unsigned)ifindex) continue; struct rtattr *rta = (struct rtattr*)&ifa[1]; size_t alen = NLMSG_PAYLOAD(nhm, sizeof(*ifa)); memset(&addrs[ret], 0, sizeof(addrs[ret])); addrs[ret].prefix = ifa->ifa_prefixlen; while (RTA_OK(rta, alen)) { if (rta->rta_type == IFA_ADDRESS) { memcpy(&addrs[ret].addr, RTA_DATA(rta), sizeof(struct in6_addr)); } else if (rta->rta_type == IFA_CACHEINFO) { struct ifa_cacheinfo *ifc = RTA_DATA(rta); addrs[ret].preferred = ifc->ifa_prefered; addrs[ret].valid = ifc->ifa_valid; } rta = RTA_NEXT(rta, alen); } if (ifa->ifa_flags & IFA_F_DEPRECATED) addrs[ret].preferred = 0; ++ret; } return ret; }
static bool receive_responses(struct tcb *tcp, const int fd, const unsigned long inode, const unsigned long expected_msg_type, int (*parser)(const void *, int, unsigned long, void *), void *opaque_data) { static union { struct nlmsghdr hdr; long buf[8192 / sizeof(long)]; } hdr_buf; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct iovec iov = { .iov_base = hdr_buf.buf, .iov_len = sizeof(hdr_buf.buf) }; int flags = 0; for (;;) { struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1 }; ssize_t ret = recvmsg(fd, &msg, flags); if (ret < 0) { if (errno == EINTR) continue; return false; } const struct nlmsghdr *h = &hdr_buf.hdr; if (!NLMSG_OK(h, ret)) return false; for (; NLMSG_OK(h, ret); h = NLMSG_NEXT(h, ret)) { if (h->nlmsg_type != expected_msg_type) return false; const int rc = parser(NLMSG_DATA(h), h->nlmsg_len, inode, opaque_data); if (rc > 0) return true; if (rc < 0) return false; } flags = MSG_DONTWAIT; } } static bool unix_send_query(struct tcb *tcp, const int fd, const unsigned long inode) { /* * The kernel bug was fixed in mainline by commit v4.5-rc6~35^2~11 * and backported to stable/linux-4.4.y by commit v4.4.4~297. */ const uint16_t dump_flag = os_release < KERNEL_VERSION(4, 4, 4) ? NLM_F_DUMP : 0; struct { const struct nlmsghdr nlh; const struct unix_diag_req udr; } req = { .nlh = { .nlmsg_len = sizeof(req), .nlmsg_type = SOCK_DIAG_BY_FAMILY, .nlmsg_flags = NLM_F_REQUEST | dump_flag }, .udr = { .sdiag_family = AF_UNIX, .udiag_ino = inode, .udiag_states = -1, .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER, .udiag_cookie = { ~0U, ~0U } } }; return send_query(tcp, fd, &req, sizeof(req)); } static int unix_parse_response(const void *data, const int data_len, const unsigned long inode, void *opaque_data) { const char *proto_name = opaque_data; const struct unix_diag_msg *diag_msg = data; struct rtattr *attr; int rta_len = data_len - NLMSG_LENGTH(sizeof(*diag_msg)); uint32_t peer = 0; size_t path_len = 0; char path[UNIX_PATH_MAX + 1]; if (rta_len < 0) return -1; if (diag_msg->udiag_ino != inode) return 0; if (diag_msg->udiag_family != AF_UNIX) return -1; for (attr = (struct rtattr *) (diag_msg + 1); RTA_OK(attr, rta_len); attr = RTA_NEXT(attr, rta_len)) { switch (attr->rta_type) { case UNIX_DIAG_NAME: if (!path_len) { path_len = RTA_PAYLOAD(attr); if (path_len > UNIX_PATH_MAX) path_len = UNIX_PATH_MAX; memcpy(path, RTA_DATA(attr), path_len); path[path_len] = '\0'; } break; case UNIX_DIAG_PEER: if (RTA_PAYLOAD(attr) >= 4) peer = *(uint32_t *) RTA_DATA(attr); break; } } /* * print obtained information in the following format: * "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]" */ if (!peer && !path_len) return -1; char peer_str[3 + sizeof(peer) * 3]; if (peer) xsprintf(peer_str, "->%u", peer); else peer_str[0] = '\0'; const char *path_str; if (path_len) { char *outstr = alloca(4 * path_len + 4); outstr[0] = ','; if (path[0] == '\0') { outstr[1] = '@'; string_quote(path + 1, outstr + 2, path_len - 1, QUOTE_0_TERMINATED, NULL); } else { string_quote(path, outstr + 1, path_len, QUOTE_0_TERMINATED, NULL); } path_str = outstr; } else { path_str = ""; } char *details; if (asprintf(&details, "%s:[%lu%s%s]", proto_name, inode, peer_str, path_str) < 0) return -1; return cache_inode_details(inode, details); } static bool netlink_send_query(struct tcb *tcp, const int fd, const unsigned long inode) { struct { const struct nlmsghdr nlh; const struct netlink_diag_req ndr; } req = { .nlh = { .nlmsg_len = sizeof(req), .nlmsg_type = SOCK_DIAG_BY_FAMILY, .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST }, .ndr = { .sdiag_family = AF_NETLINK, .sdiag_protocol = NDIAG_PROTO_ALL } }; return send_query(tcp, fd, &req, sizeof(req)); }
static void rtsock_parsemsg(uint8_t *buf, size_t len) { struct nlmsghdr *nlmsg; struct nlmsgerr *nlerr; struct rtmsg *rtmsg; struct rtattr *rta; void *gwa = NULL; int ifindex = -1; scamper_addr_t *gw = NULL; rtsock_pair_t *pair = NULL; scamper_route_t *route = NULL; if(len < sizeof(struct nlmsghdr)) { scamper_debug(__func__, "len %d != %d", len, sizeof(struct nlmsghdr)); return; } nlmsg = (struct nlmsghdr *)buf; /* if the message isn't addressed to this pid, drop it */ if(nlmsg->nlmsg_pid != pid) return; if((pair = rtsock_pair_get(nlmsg->nlmsg_seq)) == NULL) return; route = pair->route; rtsock_pair_free(pair); if(nlmsg->nlmsg_type == RTM_NEWROUTE) { rtmsg = NLMSG_DATA(nlmsg); /* this is the payload length of the response packet */ len = nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); /* hunt through the payload for the RTA_OIF entry */ rta = RTM_RTA(rtmsg); while(RTA_OK(rta, len)) { switch(rta->rta_type) { case RTA_OIF: ifindex = *(unsigned *)RTA_DATA(rta); break; case RTA_GATEWAY: gwa = RTA_DATA(rta); break; } rta = RTA_NEXT(rta, len); } if(gwa != NULL) { if(rtmsg->rtm_family == AF_INET) gw = scamper_addrcache_get_ipv4(addrcache, gwa); else if(rtmsg->rtm_family == AF_INET6) gw = scamper_addrcache_get_ipv6(addrcache, gwa); else route->error = EINVAL; } } else if(nlmsg->nlmsg_type == NLMSG_ERROR) { nlerr = NLMSG_DATA(nlmsg); route->error = nlerr->error; } else goto skip; route->gw = gw; route->ifindex = ifindex; route->cb(route); return; skip: if(route != NULL) scamper_route_free(route); return; }
/** * Process the message and add/drop multicast membership if needed */ int ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6) { struct lan_addr_s * lan_addr; ssize_t len; char buffer[4096]; #ifdef __linux__ struct iovec iov; struct msghdr hdr; struct nlmsghdr *nlhdr; struct ifaddrmsg *ifa; struct rtattr *rta; int ifa_len; iov.iov_base = buffer; iov.iov_len = sizeof(buffer); memset(&hdr, 0, sizeof(hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; len = recvmsg(s, &hdr, 0); if(len < 0) { syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m"); return -1; } for(nlhdr = (struct nlmsghdr *)buffer; NLMSG_OK(nlhdr, len); nlhdr = NLMSG_NEXT(nlhdr, len)) { int is_del = 0; char address[48]; char ifname[IFNAMSIZ]; address[0] = '\0'; ifname[0] = '\0'; if(nlhdr->nlmsg_type == NLMSG_DONE) break; switch(nlhdr->nlmsg_type) { /* case RTM_NEWLINK: */ /* case RTM_DELLINK: */ case RTM_DELADDR: is_del = 1; case RTM_NEWADDR: /* http://linux-hacks.blogspot.fr/2009/01/sample-code-to-learn-netlink.html */ ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr); rta = (struct rtattr *)IFA_RTA(ifa); ifa_len = IFA_PAYLOAD(nlhdr); syslog(LOG_DEBUG, "%s %s index=%d fam=%d prefixlen=%d flags=%d scope=%d", "ProcessInterfaceWatchNotify", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", ifa->ifa_index, ifa->ifa_family, ifa->ifa_prefixlen, ifa->ifa_flags, ifa->ifa_scope); for(;RTA_OK(rta, ifa_len); rta = RTA_NEXT(rta, ifa_len)) { /*RTA_DATA(rta)*/ /*rta_type : IFA_ADDRESS, IFA_LOCAL, etc. */ char tmp[128]; memset(tmp, 0, sizeof(tmp)); switch(rta->rta_type) { case IFA_ADDRESS: case IFA_LOCAL: case IFA_BROADCAST: case IFA_ANYCAST: inet_ntop(ifa->ifa_family, RTA_DATA(rta), tmp, sizeof(tmp)); if(rta->rta_type == IFA_ADDRESS) strncpy(address, tmp, sizeof(address)); break; case IFA_LABEL: strncpy(tmp, RTA_DATA(rta), sizeof(tmp)); strncpy(ifname, tmp, sizeof(ifname)); break; case IFA_CACHEINFO: { struct ifa_cacheinfo *cache_info; cache_info = RTA_DATA(rta); snprintf(tmp, sizeof(tmp), "valid=%u prefered=%u", cache_info->ifa_valid, cache_info->ifa_prefered); } break; default: strncpy(tmp, "*unknown*", sizeof(tmp)); } syslog(LOG_DEBUG, " rta_len=%d rta_type=%d '%s'", rta->rta_len, rta->rta_type, tmp); } syslog(LOG_INFO, "%s: %s/%d %s", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", address, ifa->ifa_prefixlen, ifname); for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) { if((0 == strcmp(address, lan_addr->str)) || (0 == strcmp(ifname, lan_addr->ifname)) || (ifa->ifa_index == lan_addr->index)) { if(ifa->ifa_family == AF_INET) AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del); else if(ifa->ifa_family == AF_INET6) AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del); break; } } break; default: syslog(LOG_DEBUG, "unknown nlmsg_type=%d", nlhdr->nlmsg_type); } } #else /* __linux__ */ struct rt_msghdr * rtm; struct ifa_msghdr * ifam; int is_del = 0; char tmp[64]; char * p; struct sockaddr * sa; int addr; char address[48]; char ifname[IFNAMSIZ]; int family = AF_UNSPEC; int prefixlen = 0; address[0] = '\0'; ifname[0] = '\0'; len = recv(s, buffer, sizeof(buffer), 0); if(len < 0) { syslog(LOG_ERR, "%s recv: %m", "ProcessInterfaceWatchNotify"); return -1; } rtm = (struct rt_msghdr *)buffer; switch(rtm->rtm_type) { case RTM_DELADDR: is_del = 1; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)buffer; syslog(LOG_DEBUG, "%s %s len=%d/%hu index=%hu addrs=%x flags=%x", "ProcessInterfaceWatchNotify", is_del?"RTM_DELADDR":"RTM_NEWADDR", (int)len, ifam->ifam_msglen, ifam->ifam_index, ifam->ifam_addrs, ifam->ifam_flags); p = buffer + sizeof(struct ifa_msghdr); addr = 1; while(p < buffer + len) { sa = (struct sockaddr *)p; while(!(addr & ifam->ifam_addrs) && (addr <= ifam->ifam_addrs)) addr = addr << 1; sockaddr_to_string(sa, tmp, sizeof(tmp)); syslog(LOG_DEBUG, " %s", tmp); switch(addr) { case RTA_DST: case RTA_GATEWAY: break; case RTA_NETMASK: if(sa->sa_family == AF_INET #if defined(__OpenBSD__) || (sa->sa_family == 0 && sa->sa_len <= sizeof(struct sockaddr_in)) #endif ) { uint32_t sin_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); while((prefixlen < 32) && ((sin_addr & (1 << (31 - prefixlen))) != 0)) prefixlen++; } else if(sa->sa_family == AF_INET6 #if defined(__OpenBSD__) || (sa->sa_family == 0 && sa->sa_len == sizeof(struct sockaddr_in6)) #endif ) { int i = 0; uint8_t * q = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; while((*q == 0xff) && (i < 16)) { prefixlen += 8; q++; i++; } if(i < 16) { i = 0; while((i < 8) && ((*q & (1 << (7 - i))) != 0)) i++; prefixlen += i; } } break; case RTA_GENMASK: break; case RTA_IFP: #ifdef AF_LINK if(sa->sa_family == AF_LINK) { struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa; memset(ifname, 0, sizeof(ifname)); memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen); } #endif break; case RTA_IFA: family = sa->sa_family; if(sa->sa_family == AF_INET) { inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, address, sizeof(address)); } else if(sa->sa_family == AF_INET6) { inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, address, sizeof(address)); } break; case RTA_AUTHOR: break; case RTA_BRD: break; } #if 0 syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x", (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3], (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]); syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x", (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7], (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7]); #endif p += SA_RLEN(sa); addr = addr << 1; } syslog(LOG_INFO, "%s: %s/%d %s", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", address, prefixlen, ifname); for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) { if((0 == strcmp(address, lan_addr->str)) || (0 == strcmp(ifname, lan_addr->ifname)) || (ifam->ifam_index == lan_addr->index)) { if(family == AF_INET) AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del); else if(family == AF_INET6) AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del); break; } } break; default: syslog(LOG_DEBUG, "Unknown RTM message : rtm->rtm_type=%d len=%d", rtm->rtm_type, (int)len); } #endif return 0; }
/* ====================================================================== */ int getifaddrs_local (struct ifaddrs **ifap) { int sd; struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; /* - - - - - - - - - - - - - - - */ int icnt; size_t dlen, xlen, nlen; uint32_t max_ifindex = 0; pid_t pid = getpid (); int seq; int result; int build; /* 0 or 1 */ /* ---------------------------------- */ /* initialize */ icnt = dlen = xlen = nlen = 0; nlmsg_list = nlmsg_end = NULL; if (ifap) *ifap = NULL; /* ---------------------------------- */ /* open socket and bind */ sd = nl_open (); if (sd < 0) return -1; /* ---------------------------------- */ /* gather info */ if ((seq = nl_getlist (sd, 0, RTM_GETLINK, &nlmsg_list, &nlmsg_end)) < 0) { free_nlmsglist (nlmsg_list); nl_close (sd); return -1; } if ((seq = nl_getlist (sd, seq + 1, RTM_GETADDR, &nlmsg_list, &nlmsg_end)) < 0) { free_nlmsglist (nlmsg_list); nl_close (sd); return -1; } /* ---------------------------------- */ /* Estimate size of result buffer and fill it */ for (build = 0; build <= 1; build++) { struct ifaddrs *ifl = NULL, *ifa = NULL; struct nlmsghdr *nlh, *nlh0; void *data = NULL, *xdata = NULL, *ifdata = NULL; char *ifname = NULL, **iflist = NULL; uint16_t *ifflist = NULL; struct rtmaddr_ifamap ifamap; if (build) { ifa = data = calloc (1, NLMSG_ALIGN (sizeof (struct ifaddrs[icnt])) + dlen + xlen + nlen); ifdata = calloc (1, NLMSG_ALIGN (sizeof (char *[max_ifindex + 1])) + NLMSG_ALIGN (sizeof (uint16_t[max_ifindex + 1]))); if (ifap != NULL) *ifap = (ifdata != NULL) ? ifa : NULL; else { free_data (data, ifdata); result = 0; break; } if (data == NULL || ifdata == NULL) { free_data (data, ifdata); result = -1; break; } ifl = NULL; data += NLMSG_ALIGN (sizeof (struct ifaddrs)) * icnt; xdata = data + dlen; ifname = xdata + xlen; iflist = ifdata; ifflist = ((void *) iflist) + NLMSG_ALIGN (sizeof (char *[max_ifindex + 1])); } for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next) { int nlmlen = nlm->size; if (!(nlh0 = nlm->nlh)) continue; for (nlh = nlh0; NLMSG_OK (nlh, nlmlen); nlh = NLMSG_NEXT (nlh, nlmlen)) { struct ifinfomsg *ifim = NULL; struct ifaddrmsg *ifam = NULL; struct rtattr *rta; size_t nlm_struct_size = 0; sa_family_t nlm_family = 0; uint32_t nlm_scope = 0, nlm_index = 0; #ifndef IFA_NETMASK size_t sockaddr_size = 0; uint32_t nlm_prefixlen = 0; #endif size_t rtasize; memset (&ifamap, 0, sizeof (ifamap)); /* check if the message is what we want */ if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) { break; /* ok */ } switch (nlh->nlmsg_type) { case RTM_NEWLINK: ifim = (struct ifinfomsg *) NLMSG_DATA (nlh); nlm_struct_size = sizeof (*ifim); nlm_family = ifim->ifi_family; nlm_scope = 0; nlm_index = ifim->ifi_index; nlm_prefixlen = 0; if (build) ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags; break; case RTM_NEWADDR: ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh); nlm_struct_size = sizeof (*ifam); nlm_family = ifam->ifa_family; nlm_scope = ifam->ifa_scope; nlm_index = ifam->ifa_index; nlm_prefixlen = ifam->ifa_prefixlen; if (build) ifa->ifa_flags = ifflist[nlm_index]; break; default: continue; } if (!build) { if (max_ifindex < nlm_index) max_ifindex = nlm_index; } else { if (ifl != NULL) ifl->ifa_next = ifa; } rtasize = NLMSG_PAYLOAD (nlh, nlmlen) - NLMSG_ALIGN (nlm_struct_size); for (rta = (struct rtattr *) (((char *) NLMSG_DATA (nlh)) + NLMSG_ALIGN (nlm_struct_size)); RTA_OK (rta, rtasize); rta = RTA_NEXT (rta, rtasize)) { struct sockaddr **sap = NULL; void *rtadata = RTA_DATA (rta); size_t rtapayload = RTA_PAYLOAD (rta); socklen_t sa_len; switch (nlh->nlmsg_type) { case RTM_NEWLINK: switch (rta->rta_type) { case IFLA_ADDRESS: case IFLA_BROADCAST: if (build) { sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa-> ifa_broadaddr; *sap = (struct sockaddr *) data; } sa_len = ifa_sa_len (AF_PACKET, rtapayload); if (rta->rta_type == IFLA_ADDRESS) sockaddr_size = NLMSG_ALIGN (sa_len); if (!build) { dlen += NLMSG_ALIGN (sa_len); } else { memset (*sap, 0, sa_len); ifa_make_sockaddr (AF_PACKET, *sap, rtadata, rtapayload, 0, 0); ((struct sockaddr_ll *) *sap)->sll_ifindex = nlm_index; ((struct sockaddr_ll *) *sap)->sll_hatype = ifim->ifi_type; data += NLMSG_ALIGN (sa_len); } break; case IFLA_IFNAME: /* Name of Interface */ if (!build) nlen += NLMSG_ALIGN (rtapayload + 1); else { ifa->ifa_name = ifname; if (iflist[nlm_index] == NULL) iflist[nlm_index] = ifa->ifa_name; strncpy (ifa->ifa_name, rtadata, rtapayload); ifa->ifa_name[rtapayload] = '\0'; ifname += NLMSG_ALIGN (rtapayload + 1); } break; case IFLA_STATS: /* Statistics of Interface */ if (!build) xlen += NLMSG_ALIGN (rtapayload); else { ifa->ifa_data = xdata; memcpy (ifa->ifa_data, rtadata, rtapayload); xdata += NLMSG_ALIGN (rtapayload); } break; case IFLA_UNSPEC: break; case IFLA_MTU: break; case IFLA_LINK: break; case IFLA_QDISC: break; default: ; } break; case RTM_NEWADDR: if (nlm_family == AF_PACKET) break; switch (rta->rta_type) { case IFA_ADDRESS: ifamap.address = rtadata; ifamap.address_len = rtapayload; break; case IFA_LOCAL: ifamap.local = rtadata; ifamap.local_len = rtapayload; break; case IFA_BROADCAST: ifamap.broadcast = rtadata; ifamap.broadcast_len = rtapayload; break; #ifdef HAVE_IFADDRS_IFA_ANYCAST case IFA_ANYCAST: ifamap.anycast = rtadata; ifamap.anycast_len = rtapayload; break; #endif case IFA_LABEL: if (!build) nlen += NLMSG_ALIGN (rtapayload + 1); else { ifa->ifa_name = ifname; if (iflist[nlm_index] == NULL) iflist[nlm_index] = ifname; strncpy (ifa->ifa_name, rtadata, rtapayload); ifa->ifa_name[rtapayload] = '\0'; ifname += NLMSG_ALIGN (rtapayload + 1); } break; case IFA_UNSPEC: break; case IFA_CACHEINFO: break; default: ; } } } if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET) { if (!ifamap.local) { ifamap.local = ifamap.address; ifamap.local_len = ifamap.address_len; } if (!ifamap.address) { ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address_len != ifamap.local_len || (ifamap.address != NULL && memcmp (ifamap.address, ifamap.local, ifamap.address_len))) { /* p2p; address is peer and local is ours */ ifamap.broadcast = ifamap.address; ifamap.broadcast_len = ifamap.address_len; ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address) { #ifndef IFA_NETMASK sockaddr_size = NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.address_len)); #endif if (!build) dlen += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.address_len)); else { ifa->ifa_addr = (struct sockaddr *) data; ifa_make_sockaddr (nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len, nlm_scope, nlm_index); data += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.address_len)); } } #ifdef IFA_NETMASK if (ifamap.netmask) { if (!build) dlen += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.netmask_len)); else { ifa->ifa_netmask = (struct sockaddr *) data; ifa_make_sockaddr (nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len, nlm_scope, nlm_index); data += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.netmask_len)); } } #endif if (ifamap.broadcast) { if (!build) dlen += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.broadcast_len)); else { ifa->ifa_broadaddr = (struct sockaddr *) data; ifa_make_sockaddr (nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len, nlm_scope, nlm_index); data += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.broadcast_len)); } } #ifdef HAVE_IFADDRS_IFA_ANYCAST if (ifamap.anycast) { if (!build) dlen += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.anycast_len)); else { ifa->ifa_anycast = (struct sockaddr *) data; ifa_make_sockaddr (nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len, nlm_scope, nlm_index); data += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.anycast_len)); } } #endif } if (!build) { #ifndef IFA_NETMASK dlen += sockaddr_size; #endif icnt++; } else { if (ifa->ifa_name == NULL) ifa->ifa_name = iflist[nlm_index]; #ifndef IFA_NETMASK if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_UNSPEC && ifa->ifa_addr->sa_family != AF_PACKET) { ifa->ifa_netmask = (struct sockaddr *) data; ifa_make_sockaddr_mask (ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen); } data += sockaddr_size; #endif ifl = ifa++; } } } if (!build) { if (icnt == 0 && (dlen + nlen + xlen == 0)) { if (ifap != NULL) *ifap = NULL; break; /* cannot found any addresses */ } } else free_data (NULL, ifdata); } /* ---------------------------------- */ /* Finalize */ free_nlmsglist (nlmsg_list); nl_close (sd); return 0; }
int get_ifconf(int index, struct addrinfo *ba) { int s; struct { struct nlmsghdr n; struct rtgenmsg g; } rreq; struct sockaddr_nl nladdr; char buf[8192]; struct iovec iov; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; pid_t pid; unsigned seq; int len; struct rtattr * rta; struct rtattr * tb[IFA_MAX+1]; struct nlmsghdr *h; struct ifaddrmsg *ifa; int status; struct sockaddr_in *sin; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; rreq.n.nlmsg_len = sizeof(rreq); rreq.n.nlmsg_type = RTM_GETADDR; rreq.n.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; rreq.n.nlmsg_pid = 0; rreq.n.nlmsg_seq = seq = 9998; rreq.g.rtgen_family = AF_INET; s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); sendto(s, (void*)&rreq, sizeof(rreq), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); pid = getpid(); iov.iov_base = buf; do { iov.iov_len = sizeof(buf); status = recvmsg(s, &msg, 0); h = (struct nlmsghdr*)buf; } while (h->nlmsg_pid != pid || h->nlmsg_seq != seq); close(s); /* msg_out(norm,"nlmsg_pid: %d, nlmsg_seq: %d", h->nlmsg_pid, h->nlmsg_seq); */ while (NLMSG_OK(h, status)) { memset(&tb, 0, sizeof(tb)); len = h->nlmsg_len; ifa = NLMSG_DATA(h); rta = IFA_RTA(ifa); if (ifa->ifa_index == index) { while (RTA_OK(rta, len)) { if (rta->rta_type <= IFA_MAX) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta,len); } if (tb[IFA_ADDRESS]) { /* char str[128]; inet_ntop(AF_INET, RTA_DATA(tb[IFA_ADDRESS]), str, sizeof(str)); msg_out(norm, "ADDRESS %s", str); */ ba->ai_family = AF_INET; /* IPv4 */ ba->ai_socktype = SOCK_STREAM; ba->ai_protocol = IPPROTO_IP; ba->ai_addrlen = sizeof(struct sockaddr_in); sin = (struct sockaddr_in *)ba->ai_addr; sin->sin_family = AF_INET; memcpy(&(sin->sin_addr), RTA_DATA(tb[IFA_ADDRESS]), 4); return(0); } /* if (tb[IFA_LOCAL]) { unsigned *d = RTA_DATA(tb[IFA_LOCAL]); msg_out(norm, "LOCAL %08x", *d); } */ } h = NLMSG_NEXT(h, status); } return(-1); }
/** * In case one binds to 0.0.0.0/INADDR_ANY and wants to know which source * address will be used when sending a message this function can be used. * It will ask the routing code of the kernel for the PREFSRC */ int source_for_dest(const struct in_addr *dest, struct in_addr *loc_source) { int fd, rc; struct rtmsg *r; struct rtattr *rta; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof(req)); fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE); if (fd < 0) { perror("nl socket"); return -1; } /* Send a rtmsg and ask for a response */ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.n.nlmsg_type = RTM_GETROUTE; req.n.nlmsg_seq = 1; /* Prepare the routing request */ req.r.rtm_family = AF_INET; /* set the dest */ rta = NLMSG_TAIL(&req.n); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(sizeof(*dest)); memcpy(RTA_DATA(rta), dest, sizeof(*dest)); /* update sizes for dest */ req.r.rtm_dst_len = sizeof(*dest) * 8; req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_ALIGN(rta->rta_len); rc = send(fd, &req, req.n.nlmsg_len, 0); if (rc != req.n.nlmsg_len) { perror("short write"); close(fd); return -2; } /* now receive a response and parse it */ rc = recv(fd, &req, sizeof(req), 0); if (rc <= 0) { perror("short read"); close(fd); return -3; } if (!NLMSG_OK(&req.n, rc) || req.n.nlmsg_type != RTM_NEWROUTE) { close(fd); return -4; } r = NLMSG_DATA(&req.n); rc -= NLMSG_LENGTH(sizeof(*r)); rta = RTM_RTA(r); while (RTA_OK(rta, rc)) { if (rta->rta_type != RTA_PREFSRC) { rta = RTA_NEXT(rta, rc); continue; } /* we are done */ memcpy(loc_source, RTA_DATA(rta), RTA_PAYLOAD(rta)); close(fd); return 0; } close(fd); return -5; }
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList) { struct ifaddrs *l_entry; char *l_index; char *l_name; char *l_addr; char *l_data; struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); size_t l_nameSize = 0; size_t l_addrSize = 0; size_t l_dataSize = 0; size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); struct rtattr *l_rta; for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFLA_ADDRESS: case IFLA_BROADCAST: l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); break; case IFLA_IFNAME: l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); break; case IFLA_STATS: l_dataSize += NLMSG_ALIGN(l_rtaSize); break; default: break; } } l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize); if (l_entry == NULL) { return -1; } memset(l_entry, 0, sizeof(struct ifaddrs)); l_entry->ifa_name = ""; l_index = ((char *)l_entry) + sizeof(struct ifaddrs); l_name = l_index + sizeof(int); l_addr = l_name + l_nameSize; l_data = l_addr + l_addrSize; /* Save the interface index so we can look it up when handling the * addresses. */ memcpy(l_index, &l_info->ifi_index, sizeof(int)); l_entry->ifa_flags = l_info->ifi_flags; l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { void *l_rtaData = RTA_DATA(l_rta); size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); switch(l_rta->rta_type) { case IFLA_ADDRESS: case IFLA_BROADCAST: { size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; if(l_rta->rta_type == IFLA_ADDRESS) { l_entry->ifa_addr = (struct sockaddr *)l_addr; } else { l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; } l_addr += NLMSG_ALIGN(l_addrLen); break; } case IFLA_IFNAME: strncpy(l_name, l_rtaData, l_rtaDataSize); l_name[l_rtaDataSize] = '\0'; l_entry->ifa_name = l_name; break; case IFLA_STATS: memcpy(l_data, l_rtaData, l_rtaDataSize); l_entry->ifa_data = l_data; break; default: break; } } addToEnd(p_resultList, l_entry); return 0; }
static void rtnl_print_ifaddr(struct nlmsghdr *hdr) { struct ifaddrmsg *ifa = NLMSG_DATA(hdr); uint32_t attrs_len = IFA_PAYLOAD(hdr); struct rtattr *attr = IFA_RTA(ifa); struct ifa_cacheinfo *ci; char addr_str[256]; char flags[256]; tprintf(" [ Address Family %d (%s%s%s)", ifa->ifa_family, colorize_start(bold), addr_family2str(ifa->ifa_family), colorize_end()); tprintf(", Prefix Len %d", ifa->ifa_prefixlen); tprintf(", Flags %d (%s%s%s)", ifa->ifa_flags, colorize_start(bold), rtnl_addr_flags2str(ifa->ifa_flags, flags, sizeof(flags)), colorize_end()); tprintf(", Scope %d (%s%s%s)", ifa->ifa_scope, colorize_start(bold), scope2str(ifa->ifa_scope), colorize_end()); tprintf(", Link Index %d ]\n", ifa->ifa_index); for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) { switch (attr->rta_type) { case IFA_LOCAL: attr_fmt(attr, "Local %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case IFA_ADDRESS: attr_fmt(attr, "Address %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case IFA_BROADCAST: attr_fmt(attr, "Broadcast %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case IFA_MULTICAST: attr_fmt(attr, "Multicast %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case IFA_ANYCAST: attr_fmt(attr, "Anycast %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; #ifdef IFA_FLAGS case IFA_FLAGS: attr_fmt(attr, "Flags %d (%s%s%s)", RTA_INT(attr), colorize_start(bold), rtnl_addr_flags2str(RTA_INT(attr), flags, sizeof(flags)), colorize_end()); break; #endif case IFA_LABEL: attr_fmt(attr, "Label %s", RTA_STR(attr)); break; case IFA_CACHEINFO: ci = RTA_DATA(attr); tprintf("\tA: Cache ("); if (ci->ifa_valid == INFINITY) tprintf("valid lft(forever)"); else tprintf("valid lft(%us)", ci->ifa_valid); if (ci->ifa_prefered == INFINITY) tprintf(", prefrd lft(forever)"); else tprintf(", prefrd lft(%us)", ci->ifa_prefered); tprintf(", created on(%.2fs)", (double)ci->cstamp / 100); tprintf(", updated on(%.2fs))", (double)ci->cstamp / 100); tprintf(", Len %lu\n", RTA_LEN(attr)); break; } } }