static void netlink_receive_link(struct netlink_data *netlink, void (*cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len), struct nlmsghdr *h) { if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg)) return; cb(netlink->cfg->ctx, NLMSG_DATA(h), (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)), NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg))); }
static void genl_print_ctrl_family(struct nlmsghdr *hdr) { struct genlmsghdr *genl = NLMSG_DATA(hdr); struct nlattr *attr = GEN_NLA(genl); uint32_t attrs_len = NLMSG_PAYLOAD(hdr, sizeof(struct genlmsghdr)); for (; NLA_OK(attr, attrs_len); attr = NLA_NEXT(attr, attrs_len)) { switch (attr->nla_type) { case CTRL_ATTR_FAMILY_ID: nla_fmt(attr, "Family Id 0x%x", NLA_UINT16(attr)); break; case CTRL_ATTR_FAMILY_NAME: nla_fmt(attr, "Family Name %s", NLA_STR(attr)); break; case CTRL_ATTR_VERSION: nla_fmt(attr, "Version %u", NLA_UINT32(attr)); break; case CTRL_ATTR_HDRSIZE: nla_fmt(attr, "Header size %u", NLA_UINT32(attr)); break; case CTRL_ATTR_MAXATTR: nla_fmt(attr, "Max attr value 0x%x", NLA_UINT32(attr)); break; default: nla_fmt(attr, "0x%x", attr->nla_type); break; } } }
int connection_process(struct connection *conn, struct sk_buff *skb) { int ret = 0; do { if (mutex_lock_interruptible(&(conn->data_lock))) { MCDRV_DBG_ERROR("Interrupted getting data semaphore!"); ret = -1; break; } kfree_skb(conn->skb); /* Get a reference to the incomming skb */ conn->skb = skb_get(skb); if (conn->skb) { conn->data_msg = nlmsg_hdr(conn->skb); conn->data_len = NLMSG_PAYLOAD(conn->data_msg, 0); conn->data_start = NLMSG_DATA(conn->data_msg); up(&(conn->data_available_sem)); } mutex_unlock(&(conn->data_lock)); ret = 0; } while (0); return ret; }
static int handle_cmd(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *rep_buf; struct nlmsghdr *rep_nlh; struct nlmsghdr *req_nlh = info->nlhdr; struct tipc_genlmsghdr *req_userhdr = info->userhdr; int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN); u16 cmd; if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN))) cmd = TIPC_CMD_NOT_NET_ADMIN; else cmd = req_userhdr->cmd; rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd, NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN, NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN), hdr_space); if (rep_buf) { skb_push(rep_buf, hdr_space); rep_nlh = nlmsg_hdr(rep_buf); memcpy(rep_nlh, req_nlh, hdr_space); rep_nlh->nlmsg_len = rep_buf->len; genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).pid); } return 0; }
static void handle_message(const struct nlmsghdr *message, ssize_t len) { uint8_t *payload; ssize_t length; struct nlattr *nlattr; struct ifaddrmsg *ifaddr; struct addrchange change; if (!NLMSG_OK(message, len)) { ERR("%s", "Got damaged message\n"); } if (message->nlmsg_type != RTM_NEWADDR && message->nlmsg_type != RTM_DELADDR) { INFO("%s", "Got unexpected message type"); return; } ifaddr = (struct ifaddrmsg *)NLMSG_DATA(message); change.family = ifaddr->ifa_family; change.action = message->nlmsg_type; payload = (uint8_t *)(ifaddr + 1); length = NLMSG_PAYLOAD(message, sizeof(struct ifaddrmsg)); for_each_nl(payload, nlattr, length) { handle_attr(nlattr, &change); }
static void get_if_flags(struct nlmsghdr *nlm, int nlm_len, int request, struct dhcp6_if *ifp) { struct ifinfomsg *ifim = (struct ifinfomsg *)NLMSG_DATA(nlm); struct rtattr *rta, *rta1; size_t rtasize, rtasize1, rtapayload; void *rtadata; dprintf(LOG_DEBUG, "get_if_flags called"); if (ifim->ifi_family != AF_INET6 || nlm->nlmsg_type != request) return; if (ifim->ifi_index != ifp->ifid) return; rtasize = NLMSG_PAYLOAD(nlm, nlm_len) - NLMSG_ALIGN(sizeof(*ifim)); for (rta = (struct rtattr *) (((char *) NLMSG_DATA(nlm)) + NLMSG_ALIGN(sizeof(*ifim))); RTA_OK(rta, rtasize); rta = RTA_NEXT(rta, rtasize)) { rtadata = RTA_DATA(rta); rtapayload = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFLA_IFNAME: break; #ifdef IFLA_PROTINFO case IFLA_PROTINFO: rtasize1 = rta->rta_len; for (rta1 = (struct rtattr *)rtadata; RTA_OK(rta1, rtasize1); rta1 = RTA_NEXT(rta1, rtasize1)) { void *rtadata1 = RTA_DATA(rta1); size_t rtapayload1= RTA_PAYLOAD(rta1); switch(rta1->rta_type) { case IFLA_INET6_CACHEINFO: break; case IFLA_INET6_FLAGS: /* flags for IF_RA_MANAGED/IF_RA_OTHERCONF */ ifp->ra_flag = *((u_int32_t *)rtadata1); if (*((u_int32_t *)rtadata1) & IF_RA_MANAGED) dprintf(LOG_DEBUG, "interface managed flags set"); if (*((u_int32_t *)rtadata1) & IF_RA_OTHERCONF) dprintf(LOG_DEBUG, "interface otherconf flags set"); break; default: break; } } break; #endif default: break; } } return; }
static void nl_link(struct nlmsghdr *nlmsg) { int la; char ifname[IFNAMSIZ + 1]; struct rtattr *a; struct ifinfomsg *i; if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) { _e("Packet too small or truncated!"); return; } i = NLMSG_DATA(nlmsg); a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg))); la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg)); while (RTA_OK(a, la)) { if (a->rta_type == IFLA_IFNAME) { strlcpy(ifname, RTA_DATA(a), sizeof(ifname)); switch (nlmsg->nlmsg_type) { case RTM_NEWLINK: /* * New interface has appeared, or interface flags has changed. * Check ifi_flags here to see if the interface is UP/DOWN */ _d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change); net_cond_set(ifname, "exist", 1); net_cond_set(ifname, "up", i->ifi_flags & IFF_UP); net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING); break; case RTM_DELLINK: /* NOTE: Interface has disappeared, not link down ... */ _d("%s: Delete link", ifname); net_cond_set(ifname, "exist", 0); net_cond_set(ifname, "up", 0); net_cond_set(ifname, "running", 0); break; case RTM_NEWADDR: _d("%s: New Address", ifname); break; case RTM_DELADDR: _d("%s: Deconfig Address", ifname); break; default: _d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type); break; } } a = RTA_NEXT(a, la); } }
// recv(fd [, type=0]) static PyObject* py_nl_recv(PyObject *self, PyObject *args, PyObject *keywds) { int fd; int ret; unsigned char type = DEFAULT_RECV_TYPE; char buf[MAX_NL_BUFSIZ]; PyObject *result = NULL; unsigned char *data; struct nlmsghdr *nlh; static char *kwlist[] = {"fd", "type", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|b", kwlist, &fd, &type)) { return None(); //return NULL; } memset(buf, 0, MAX_NL_BUFSIZ); ret = recvfrom(fd, buf, MAX_NL_BUFSIZ, 0, NULL, NULL); if (ret < 0) { return None(); } nlh = (struct nlmsghdr *)buf; data = (unsigned char *)NLMSG_DATA(nlh); if (NLMSG_PAYLOAD(nlh, 0) <= 1) { return None(); } if (*data != type) { return None(); } result = Py_BuildValue("(s#kHHkk)", (char *)(data+1), (unsigned long)NLMSG_PAYLOAD(nlh, 0)-1, (unsigned long)NLMSG_PAYLOAD(nlh, 0)-1, (unsigned short)(nlh->nlmsg_type), (unsigned short)(nlh->nlmsg_flags), (unsigned long)(nlh->nlmsg_seq), (unsigned long)(nlh->nlmsg_pid)); if (result) return result; return None(); }
//------------------------------------------------------------------------------ void NetlinkConnection::handleMessage( struct nlmsghdr *nlh ) { dataMutex.lock(); /* Takeover the buffer */ dataMsg = nlh; dataLen = NLMSG_PAYLOAD(dataMsg, 0); dataStart = static_cast<uint8_t *>(NLMSG_DATA(dataMsg)); dataMutex.unlock(); dataLeft.signal(); }
void parseBinaryNetLinkMessage(struct nlmsghdr *nlh) { int len = nlh->nlmsg_len - sizeof(*nlh); struct ifinfomsg *ifi; if(sizeof(*ifi) > (size_t)len){ printf("Got a short message\n"); return ; } ifi = (struct ifinfomsg*)NLMSG_DATA(nlh); if((ifi->ifi_flags & IFF_LOOPBACK) != 0){ return ; } struct rtattr *rta = (struct rtattr*) ((char*)ifi + NLMSG_ALIGN(sizeof(*ifi))); len = NLMSG_PAYLOAD(nlh,sizeof(*ifi)); while(RTA_OK(rta,len)){ switch(rta->rta_type){ case IFLA_IFNAME: { char ifname[IFNAMSIZ]; int up; int id; snprintf(ifname,sizeof(ifname),"%s", (char*)RTA_DATA(rta)); up = (ifi->ifi_flags & IFF_RUNNING)? 1 : 0; if (up && ((ifname[0] == 'p')&&(ifname[1] == 'p')&& (ifname[2] == 'p'))){ printf("msg from:%s",ifname); sscanf(ifname+3,"%d",&id); if(nic_bitmap[id]) break; start_capture(ifname); nic_bitmap[id] = 1; printf("%s %d\n",ifname,up); } if (!up && ((ifname[0] == 'p')&&(ifname[1] == 'p')&& (ifname[2] == 'p'))){ sscanf(ifname+3,"%d",(int*)&id); nic_bitmap[id] = 0; printf("%s %d\n",ifname,up); } } } rta = RTA_NEXT(rta,len); } }
int sd_rtnl_message_rewind(sd_rtnl_message *m) { const NLType *type; unsigned i; int r; assert_return(m, -EINVAL); /* don't allow appending to message once parsed */ if (!m->sealed) rtnl_message_seal(m); for (i = 1; i <= m->n_containers; i++) { free(m->rta_offset_tb[i]); m->rta_offset_tb[i] = NULL; m->rta_tb_size[i] = 0; m->container_type_system[i] = NULL; } m->n_containers = 0; if (m->rta_offset_tb[0]) { /* top-level attributes have already been parsed */ return 0; } assert(m->hdr); r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type); if (r < 0) return r; if (type->type == NLA_NESTED) { const NLTypeSystem *type_system = type->type_system; assert(type_system); m->container_type_system[0] = type_system; r = rtnl_message_parse(m, &m->rta_offset_tb[m->n_containers], &m->rta_tb_size[m->n_containers], type_system->max, (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(type->size)), NLMSG_PAYLOAD(m->hdr, type->size)); if (r < 0) return r; } return 0; }
int sd_netlink_message_rewind(sd_netlink_message *m) { const NLType *nl_type; uint16_t type; size_t size; unsigned i; int r; assert_return(m, -EINVAL); /* don't allow appending to message once parsed */ if (!m->sealed) rtnl_message_seal(m); for (i = 1; i <= m->n_containers; i++) m->containers[i].attributes = mfree(m->containers[i].attributes); m->n_containers = 0; if (m->containers[0].attributes) /* top-level attributes have already been parsed */ return 0; assert(m->hdr); r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type); if (r < 0) return r; type = type_get_type(nl_type); size = type_get_size(nl_type); if (type == NETLINK_TYPE_NESTED) { const NLTypeSystem *type_system; type_get_type_system(nl_type, &type_system); m->containers[0].type_system = type_system; r = netlink_container_parse(m, &m->containers[m->n_containers], type_system_get_count(type_system), (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)), NLMSG_PAYLOAD(m->hdr, size)); if (r < 0) return r; } return 0; }
/* 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; }
/* * parse traffic control message */ int parse_tcamsg(struct nlmsghdr *nlh) { struct tcamsg *tcam; int tcam_len; struct rtattr *tcaa[TCAA_MAX+1]; char msg[MAX_MSG_SIZE] = ""; char *mp = msg; int log_opts = get_log_opts(); /* debug nlmsghdr */ if(log_opts & L_DEBUG) debug_nlmsg(0, nlh); /* get tcamsg */ tcam_len = NLMSG_PAYLOAD(nlh, 0); if(tcam_len < sizeof(*tcam)) { rec_log("error: %s: length too short", __func__); return(1); } tcam = (struct tcamsg *)NLMSG_DATA(nlh); /* parse traffic control action message attributes */ parse_tca(tcaa, nlh); /* debug tcamsg */ if(log_opts & L_DEBUG) debug_tcamsg(0, tcam, tcaa, tcam_len); /* kind of message */ switch(nlh->nlmsg_type) { case RTM_NEWACTION: mp = add_log(msg, mp, "tc action added: "); break; case RTM_DELACTION: mp = add_log(msg, mp, "tc action deleted: "); break; default: return(1); } if(tcaa[TCA_ACT_TAB]) if(parse_tca_acts(msg, mp, tcaa[TCA_ACT_TAB])) return(1); return(0); }
static int nfct_parse_ct(nfct_msg *ctmsg, struct nlmsghdr *nlh) { struct nfgenmsg *nfmsg = (struct nfgenmsg *)NLMSG_DATA(nlh); conn_entry *e; struct nlattr *nla; int len; if(! instantiate(e)) return 0; BZERO(e); e->l3num = nfmsg->nfgen_family; nla = (struct nlattr *)((char *)NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(struct nfgenmsg))); len = NLMSG_PAYLOAD(nlh, sizeof(struct nfgenmsg)); nla_parse(e->nla, CTA_MAX, nla, len); if(e->nla[CTA_STATUS]) e->status = ntohl(nla_get_be32(e->nla[CTA_STATUS])); ctmsg->entry = e; return 0; }
/* * For routers, this is called from dn_fib_dump, but for endnodes its * called directly from the rtnetlink dispatch table. */ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) { struct dn_route *rt; int h, s_h; int idx, s_idx; if (NLMSG_PAYLOAD(cb->nlh, 0) < sizeof(struct rtmsg)) return -EINVAL; if (!(((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)) return 0; s_h = cb->args[0]; s_idx = idx = cb->args[1]; for(h = 0; h <= dn_rt_hash_mask; h++) { if (h < s_h) continue; if (h > s_h) s_idx = 0; rcu_read_lock_bh(); for(rt = rcu_dereference(dn_rt_hash_table[h].chain), idx = 0; rt; rt = rcu_dereference(rt->u.rt_next), idx++) { if (idx < s_idx) continue; skb->dst = dst_clone(&rt->u.dst); if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1, NLM_F_MULTI) <= 0) { dst_release(xchg(&skb->dst, NULL)); rcu_read_unlock_bh(); goto done; } dst_release(xchg(&skb->dst, NULL)); } rcu_read_unlock_bh(); } done: cb->args[0] = h; cb->args[1] = idx; return skb->len; }
static int link_netlink(struct nlmsghdr *nlm, const char *ifname) { int len; struct rtattr *rta; struct ifinfomsg *ifi; char ifn[IF_NAMESIZE + 1]; if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK) return 0; len = nlm->nlmsg_len - sizeof(*nlm); if ((size_t)len < sizeof(*ifi)) { errno = EBADMSG; return -1; } ifi = NLMSG_DATA(nlm); if (ifi->ifi_flags & IFF_LOOPBACK) return 0; rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi))); len = NLMSG_PAYLOAD(nlm, sizeof(*ifi)); *ifn = '\0'; while (RTA_OK(rta, len)) { switch (rta->rta_type) { case IFLA_WIRELESS: /* Ignore wireless messages */ if (nlm->nlmsg_type == RTM_NEWLINK && ifi->ifi_change == 0) return 0; break; case IFLA_IFNAME: strlcpy(ifn, RTA_DATA(rta), sizeof(ifn)); break; } rta = RTA_NEXT(rta, len); } if (strncmp(ifname, ifn, sizeof(ifn)) == 0) return 1; return 0; }
void nsexec(void) { int pipenum; // If we don't have init pipe, then just return to the go routine, // we'll only have init pipe for start or exec pipenum = get_init_pipe(); if (pipenum == -1) { return; } // Retrieve the netlink header struct nlmsghdr nl_msg_hdr; int len; if ((len = read(pipenum, &nl_msg_hdr, NLMSG_HDRLEN)) != NLMSG_HDRLEN) { pr_perror("Invalid netlink header length %d", len); exit(1); } if (nl_msg_hdr.nlmsg_type == NLMSG_ERROR) { pr_perror("Failed to read netlink message"); exit(1); } if (nl_msg_hdr.nlmsg_type != INIT_MSG) { pr_perror("Unexpected msg type %d", nl_msg_hdr.nlmsg_type); exit(1); } // Retrieve data int nl_total_size = NLMSG_PAYLOAD(&nl_msg_hdr, 0); char data[nl_total_size]; if ((len = read(pipenum, data, nl_total_size)) != nl_total_size) { pr_perror("Failed to read netlink payload, %d != %d", len, nl_total_size); exit(1); } jmp_buf env; int syncpipe[2] = {-1, -1}; struct nsenter_config config = process_nl_attributes(pipenum, data, nl_total_size); // required clone_flags to be passed if (config.cloneflags == -1) { pr_perror("Missing clone_flags"); exit(1); } // prepare sync pipe between parent and child. We need this to let the // child know that the parent has finished setting up if (pipe(syncpipe) != 0) { pr_perror("Failed to setup sync pipe between parent and child"); exit(1); } if (setjmp(env) == 1) { // Child uint8_t s = 0; int consolefd = config.consolefd; // close the writing side of pipe close(syncpipe[1]); // sync with parent if ((read(syncpipe[0], &s, 1) != 1) || (s != 1)) { pr_perror("Failed to read sync byte from parent"); exit(1); } if (setsid() == -1) { pr_perror("setsid failed"); exit(1); } if (setuid(0) == -1) { pr_perror("setuid failed"); exit(1); } if (setgid(0) == -1) { pr_perror("setgid failed"); exit(1); } if (setgroups(0, NULL) == -1) { pr_perror("setgroups failed"); exit(1); } if (consolefd != -1) { if (ioctl(consolefd, TIOCSCTTY, 0) == -1) { pr_perror("ioctl TIOCSCTTY failed"); exit(1); } if (dup3(consolefd, STDIN_FILENO, 0) != STDIN_FILENO) { pr_perror("Failed to dup stdin"); exit(1); } if (dup3(consolefd, STDOUT_FILENO, 0) != STDOUT_FILENO) { pr_perror("Failed to dup stdout"); exit(1); } if (dup3(consolefd, STDERR_FILENO, 0) != STDERR_FILENO) { pr_perror("Failed to dup stderr"); exit(1); } } // Finish executing, let the Go runtime take over. return; } // Parent start_child(pipenum, &env, syncpipe, &config); }
static gboolean read_netlink_messages (GSocket *socket, GIOCondition condition, gpointer user_data) { GNetworkMonitorNetlink *nl = user_data; GInputVector iv; gssize len; GSocketControlMessage **cmsgs = NULL; gint num_cmsgs = 0, i, flags; GError *error = NULL; GCredentials *creds; uid_t sender; struct nlmsghdr *msg; struct rtmsg *rtmsg; struct rtattr *attr; gsize attrlen; guint8 *dest, *gateway; gboolean retval = TRUE; iv.buffer = NULL; iv.size = 0; flags = MSG_PEEK | MSG_TRUNC; len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1, NULL, NULL, &flags, NULL, &error); if (len < 0) { g_warning ("Error on netlink socket: %s", error->message); g_error_free (error); if (nl->priv->dump_networks) finish_dump (nl); return FALSE; } iv.buffer = g_malloc (len); iv.size = len; len = g_socket_receive_message (nl->priv->sock, NULL, &iv, 1, &cmsgs, &num_cmsgs, NULL, NULL, &error); if (len < 0) { g_warning ("Error on netlink socket: %s", error->message); g_error_free (error); if (nl->priv->dump_networks) finish_dump (nl); return FALSE; } if (num_cmsgs != 1 || !G_IS_UNIX_CREDENTIALS_MESSAGE (cmsgs[0])) goto done; creds = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (cmsgs[0])); sender = g_credentials_get_unix_user (creds, NULL); if (sender != 0) goto done; msg = (struct nlmsghdr *) iv.buffer; for (; len > 0; msg = NLMSG_NEXT (msg, len)) { if (!NLMSG_OK (msg, (size_t) len)) { g_warning ("netlink message was truncated; shouldn't happen..."); retval = FALSE; goto done; } switch (msg->nlmsg_type) { case RTM_NEWROUTE: case RTM_DELROUTE: rtmsg = NLMSG_DATA (msg); if (rtmsg->rtm_family != AF_INET && rtmsg->rtm_family != AF_INET6) continue; if (rtmsg->rtm_type == RTN_UNREACHABLE) continue; attrlen = NLMSG_PAYLOAD (msg, sizeof (struct rtmsg)); attr = RTM_RTA (rtmsg); dest = gateway = NULL; while (RTA_OK (attr, attrlen)) { if (attr->rta_type == RTA_DST) dest = RTA_DATA (attr); else if (attr->rta_type == RTA_GATEWAY) gateway = RTA_DATA (attr); attr = RTA_NEXT (attr, attrlen); } if (dest || gateway) { if (msg->nlmsg_type == RTM_NEWROUTE) add_network (nl, rtmsg->rtm_family, rtmsg->rtm_dst_len, dest, gateway); else remove_network (nl, rtmsg->rtm_family, rtmsg->rtm_dst_len, dest, gateway); queue_request_dump (nl); } break; case NLMSG_DONE: finish_dump (nl); goto done; case NLMSG_ERROR: { struct nlmsgerr *e = NLMSG_DATA (msg); g_warning ("netlink error: %s", g_strerror (-e->error)); } retval = FALSE; goto done; default: g_warning ("unexpected netlink message %d", msg->nlmsg_type); retval = FALSE; goto done; } } done: for (i = 0; i < num_cmsgs; i++) g_object_unref (cmsgs[i]); g_free (cmsgs); g_free (iv.buffer); if (!retval && nl->priv->dump_networks) finish_dump (nl); return retval; }
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; }
/* ====================================================================== */ int getifaddrs(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; } 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; } } } 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; }
static int interpretLink(struct nlmsghdr *p_hdr, 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 = 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; } } struct ifaddrs *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 = ""; char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs); char *l_name = l_index + sizeof(int); char *l_addr = l_name + l_nameSize; char *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 int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) { struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks); if(l_info->ifa_family == AF_PACKET) { return 0; } 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 = IFA_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 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); if (l_entry == NULL) { return -1; } memset(l_entry, 0, sizeof(struct ifaddrs)); l_entry->ifa_name = (l_interface ? l_interface->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; if(l_interface) { l_entry->ifa_flags |= l_interface->ifa_flags; } l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); for(l_rta = IFA_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 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; } if(l_prefix % 8) { 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); return 0; }
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; }
// 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; }
/* * parse traffic control filter messages */ int parse_tcmsg_filter(struct nlmsghdr *nlh) { struct tcmsg *tcm; int tcm_len; struct rtattr *tca[__TCA_MAX]; char msg[MAX_MSG_SIZE] = ""; char *mp = msg; char ifname[IFNAMSIZ]; char handle[MAX_STR_SIZE] = ""; char kind[IFNAMSIZ] = "(unknown)"; char proto[MAX_STR_SIZE]; int log_opts = get_log_opts(); /* debug nlmsghdr */ if(log_opts & L_DEBUG) debug_nlmsg(0, nlh); /* get tcmsg */ tcm_len = NLMSG_PAYLOAD(nlh, 0); if(tcm_len < sizeof(*tcm)) { rec_log("error: %s: tcmsg: length too short", __func__); return(1); } tcm = (struct tcmsg *)NLMSG_DATA(nlh); /* parse traffic control message attributes */ parse_tc(tca, nlh); /* debug tcmsg */ if(log_opts & L_DEBUG) debug_tcmsg(0, nlh, tcm, tca, tcm_len); /* kind of message */ switch(nlh->nlmsg_type) { case RTM_NEWTFILTER: mp = add_log(msg, mp, "tc filter added: "); break; case RTM_DELTFILTER: mp = add_log(msg, mp, "tc filter deleted: "); break; default: rec_log("error: %s: nlmsg_type: unknown message", __func__); return(1); } /* get interface name */ if_indextoname_from_lists(tcm->tcm_ifindex, ifname); mp = add_log(msg, mp, "interface=%s ", ifname); /* get qdisc kind */ if(tca[TCA_KIND]) strncpy(kind, (char *)RTA_DATA(tca[TCA_KIND]), sizeof(kind)); /* get filter handle */ if(!strncmp(kind, "u32", sizeof(kind))) parse_u32_handle(handle, sizeof(handle), tcm->tcm_handle); else snprintf(handle, sizeof(handle), "0x%x", tcm->tcm_handle); mp = add_log(msg, mp, "handle=%s ", handle); /* get priority */ mp = add_log(msg, mp, "priority=%u ", TC_H_MAJ(tcm->tcm_info)>>16); /* get priority */ strncpy(proto, conv_eth_p(ntohs(TC_H_MIN(tcm->tcm_info)), 0), sizeof(proto)); if(strlen(proto)) mp = add_log(msg, mp, "protocol=%s ", proto); else mp = add_log(msg, mp, "protocol=0x%04x ", ntohs(TC_H_MIN(tcm->tcm_info))); /* get filter options */ mp = add_log(msg, mp, "filter=%s ", kind); if(tca[TCA_OPTIONS]) { if(!strncmp(kind, "u32", sizeof(kind))) { if(parse_tca_options_u32(msg, &mp, tca[TCA_OPTIONS])) return(1); return(0); } else if(!strncmp(kind, "rsvp", sizeof(kind))) { if(parse_tca_options_rsvp(msg, &mp, tcm, tca[TCA_OPTIONS])) return(1); return(0); } else if(!strncmp(kind, "route", sizeof(kind))) { if(parse_tca_options_route(msg, &mp, tca[TCA_OPTIONS])) return(1); return(0); } else if(!strncmp(kind, "fw", sizeof(kind))) { if(parse_tca_options_fw(msg, &mp, tca[TCA_OPTIONS])) return(1); return(0); } else if(!strncmp(kind, "tcindex", sizeof(kind))) { if(parse_tca_options_tcindex(msg, &mp, tca[TCA_OPTIONS])) return(1); return(0); #if HAVE_DECL_TCA_FLOW_UNSPEC } else if(!strncmp(kind, "flow", sizeof(kind))) { if(parse_tca_options_flow(msg, &mp, tca[TCA_OPTIONS])) return(1); return(0); #endif } else if(!strncmp(kind, "basic", sizeof(kind))) { if(parse_tca_options_basic(msg, &mp, tca[TCA_OPTIONS])) return(1); return(0); #if HAVE_DECL_TCA_CGROUP_UNSPEC } else if(!strncmp(kind, "cgroup", sizeof(kind))) { if(parse_tca_options_cgroup(msg, &mp, tca[TCA_OPTIONS])) return(1); return(0); #endif } } rec_log("%s", msg); return(0); }
/** * * void nl_data_ready(struct sk_buff *skb) * * This function is automatically called when the kernel receives a datagram on the corresponding netlink socket. */ void nl_data_ready(struct sk_buff *skb) { static int message_counter=0; message_counter++; struct nlmsghdr *nlh; u_char *buffer; // Pointer to data in payload u_char *buf; // strcat(buffer, "LOLOLOLOLOLO"); int len; // Payload length int commandValueLength; u_char *commandValue; int pid; // pid of sending process struct nl_userspace80211_to_stub80211_msg *messageToParse; u_int reply_call; // a number corresponding to the type of socketcall this packet is in response to PRINT_DEBUG("Entered: skb=%p", skb); if (skb == NULL) { PRINT_DEBUG("Exiting: skb NULL \n"); return; } nlh = (struct nlmsghdr *) skb->data; pid = nlh->nlmsg_pid; // get pid from the header // Get a pointer to the start of the data in the buffer and the buffer (payload) length buf = (u_char *) (NLMSG_DATA(nlh)); len = NLMSG_PAYLOAD(nlh, 0); PRINT_DEBUG("Core Process ID nl_pid=%d,Payload Length nl_len=%d", pid, len); // **** Remember the LKM must be up first, then the daemon, // but the daemon must make contact before any applications try to use socket() if (pid == -1) { // if the socket daemon hasn't made contact before // Print what we received PRINT_DEBUG("No msg pID, received='%p'", buf); } else { /** if (len >= sizeof(struct nl_FINS_to_stub80211)) { hdr = (struct nl_FINS_to_stub80211 *) buf; len -= sizeof(struct nl_FINS_to_stub80211); */ if (len >= sizeof(struct nl_userspace80211_to_stub80211_msg )) { messageToParse = (struct nl_userspace80211_to_stub80211_msg *) buf; commandValueLength = len - sizeof (struct nl_userspace80211_to_stub80211_msg); if (messageToParse->commandValueLength != messageToParse->commandValueLength ) PRINT_ERROR("THIS IS FATAL PROBLEM. length calcualted, does not equal" "length in the structure"); PRINT_DEBUG("Received Message number = %d call_type=%d, call_valueLength=%d, call_valuePointer=%c", message_counter,messageToParse->command_type, messageToParse->commandValueLength, messageToParse->value); if ( (messageToParse->commandValueLength ==0) && (messageToParse->commandValueLength == messageToParse->commandValueLength )) { switch (messageToParse->command_type) { case STUB80211_CMD_SPECS: PRINT_DEBUG("STUB80211_CMD_SPECS:"); break; case STUB80211_CMD_GETRATE: PRINT_DEBUG("STUB80211_CMD_GETRATE:"); break; case STUB80211_CMD_SETRATE: PRINT_DEBUG("STUB80211_CMD_SETRATE::"); break; case STUB80211_CMD_GETTXPOWER: PRINT_DEBUG("STUB80211_CMD_GETTXPOWER:::"); break; case STUB80211_CMD_SETTXPOWER: PRINT_DEBUG("STUB80211_CMD_SETTXPOWER:::"); break; case STUB80211_CMD_GETCW: PRINT_DEBUG("STUB80211_CMD_GETCW:::"); break; case STUB80211_CMD_SETCW: PRINT_DEBUG("STUB80211_CMD_SETCW:::"); break; case STUB80211_CMD_GETCWMIN: PRINT_DEBUG("STUB80211_CMD_GETCWMIN:::"); break; case STUB80211_CMD_SETCWMIN: PRINT_DEBUG("STUB80211_CMD_SETCWMIN:::"); break; case STUB80211_CMD_GETCWMAX: PRINT_DEBUG("STUB80211_CMD_GETCWMAX:::"); break; case STUB80211_CMD_SETCWMAX: PRINT_DEBUG("STUB80211_CMD_SETCWMAX:::"); break; case STUB80211_CMD_GETRSS: PRINT_DEBUG("STUB80211_CMD_GETRSS:::"); break; case STUB80211_CMD_GETSTAT: PRINT_DEBUG("STUB80211_CMD_GETSTAT:::"); struct ieee80211_low_level_stats toBeCopied; toBeCopied = break; default: PRINT_DEBUG("Command type is not found"); } } else if (messageToParse->commandValueLength !=0) { PRINT_DEBUG("commandValueLength is not zero"); commandValue = (u_char *) kmalloc(commandValueLength , GFP_KERNEL); if (commandValue == NULL) { PRINT_ERROR("buffer allocation error"); return; } memcpy(commandValue, messageToParse->value, commandValueLength); } else { PRINT_DEBUG("\nERROR- should not enter here ever"); } /** * In this segment of code , we parse the message received from the userspace: * According to the list of commands defined between the stub80211 LKM and * the stub80211 userspace thread * */ } //end of IF
/* * Parse a binary message from a NETLINK_ROUTE netlink socket. */ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { const struct nlmsghdr *nh; for (nh = (struct nlmsghdr *) buffer; NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE); nh = NLMSG_NEXT(nh, size)) { if (nh->nlmsg_type == RTM_NEWLINK) { int len = nh->nlmsg_len - sizeof(*nh); struct ifinfomsg *ifi; if (sizeof(*ifi) > (size_t) len) { SLOGE("Got a short RTM_NEWLINK message\n"); continue; } ifi = (ifinfomsg *)NLMSG_DATA(nh); if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) { continue; } struct rtattr *rta = (struct rtattr *) ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi))); len = NLMSG_PAYLOAD(nh, sizeof(*ifi)); while(RTA_OK(rta, len)) { switch(rta->rta_type) { case IFLA_IFNAME: char buffer[16 + IFNAMSIZ]; snprintf(buffer, sizeof(buffer), "INTERFACE=%s", (char *) RTA_DATA(rta)); mParams[0] = strdup(buffer); mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? NlActionLinkUp : NlActionLinkDown; mSubsystem = strdup("net"); break; } rta = RTA_NEXT(rta, len); } } else if (nh->nlmsg_type == QLOG_NL_EVENT) { char *devname; ulog_packet_msg_t *pm; size_t len = nh->nlmsg_len - sizeof(*nh); if (sizeof(*pm) > len) { SLOGE("Got a short QLOG message\n"); continue; } pm = (ulog_packet_msg_t *)NLMSG_DATA(nh); devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name; asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix); asprintf(&mParams[1], "INTERFACE=%s", devname); mSubsystem = strdup("qlog"); mAction = NlActionChange; } else if (nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) { int len = nh->nlmsg_len - sizeof(*nh); struct ifaddrmsg *ifa; if (sizeof(*ifa) > (size_t) len) { SLOGE("Got a short RTM_xxxADDR message\n"); continue; } ifa = (ifaddrmsg *)NLMSG_DATA(nh); size_t rtasize = IFA_PAYLOAD(nh); if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) { continue; } } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) { int len = nh->nlmsg_len - sizeof(*nh); struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh); if (sizeof(*ndmsg) > (size_t) len) { SLOGE("Got a short RTM_NEWNDUSEROPT message\n"); continue; } size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg)); if (!parseNdUserOptMessage(ndmsg, optsize)) { continue; } } else { SLOGD("Unexpected netlink message. type=0x%x\n", nh->nlmsg_type); } } return true; }
int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; struct netconfmsg *ncm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NETCONFA_MAX+1]; int ifindex = 0; if (n->nlmsg_type == NLMSG_ERROR) return -1; if (n->nlmsg_type != RTM_NEWNETCONF) { fprintf(stderr, "Not RTM_NEWNETCONF: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return -1; } len -= NLMSG_SPACE(sizeof(*ncm)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (filter.family && filter.family != ncm->ncm_family) return 0; parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), NLMSG_PAYLOAD(n, sizeof(*ncm))); if (tb[NETCONFA_IFINDEX]) ifindex = rta_getattr_u32(tb[NETCONFA_IFINDEX]); if (filter.ifindex && filter.ifindex != ifindex) return 0; switch (ncm->ncm_family) { case AF_INET: fprintf(fp, "ipv4 "); break; case AF_INET6: fprintf(fp, "ipv6 "); break; case AF_MPLS: fprintf(fp, "mpls "); break; default: fprintf(fp, "unknown "); break; } if (tb[NETCONFA_IFINDEX]) { switch (ifindex) { case NETCONFA_IFINDEX_ALL: fprintf(fp, "all "); break; case NETCONFA_IFINDEX_DEFAULT: fprintf(fp, "default "); break; default: fprintf(fp, "dev %s ", ll_index_to_name(ifindex)); break; } } if (tb[NETCONFA_FORWARDING]) print_onoff(fp, "forwarding", rta_getattr_u32(tb[NETCONFA_FORWARDING])); if (tb[NETCONFA_RP_FILTER]) { __u32 rp_filter = rta_getattr_u32(tb[NETCONFA_RP_FILTER]); if (rp_filter == 0) fprintf(fp, "rp_filter off "); else if (rp_filter == 1) fprintf(fp, "rp_filter strict "); else if (rp_filter == 2) fprintf(fp, "rp_filter loose "); else fprintf(fp, "rp_filter unknown mode "); } if (tb[NETCONFA_MC_FORWARDING]) print_onoff(fp, "mc_forwarding", rta_getattr_u32(tb[NETCONFA_MC_FORWARDING])); if (tb[NETCONFA_PROXY_NEIGH]) print_onoff(fp, "proxy_neigh", rta_getattr_u32(tb[NETCONFA_PROXY_NEIGH])); if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) print_onoff(fp, "ignore_routes_with_linkdown", rta_getattr_u32(tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN])); if (tb[NETCONFA_INPUT]) print_onoff(fp, "input", rta_getattr_u32(tb[NETCONFA_INPUT])); fprintf(fp, "\n"); fflush(fp); return 0; }
Ref<RouteInfoList> RouteInfo::queryTable() { Ref<RouteInfoList> list = RouteInfoList::create(); int fd = ::socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd == -1) FLUX_SYSTEM_DEBUG_ERROR(errno); struct sockaddr_nl src; memclr(&src, sizeof(src)); src.nl_family = AF_NETLINK; src.nl_pid = ::getpid(); if (::bind(fd, (struct sockaddr *)&src, (socklen_t)sizeof(src)) == -1) FLUX_SYSTEM_DEBUG_ERROR(errno); // send request { size_t msgLen = NLMSG_LENGTH(sizeof(struct rtmsg)); struct nlmsghdr *msg = (struct nlmsghdr *)flux::malloc(msgLen); int seq = 0; memclr(msg, msgLen); msg->nlmsg_type = RTM_GETROUTE; msg->nlmsg_len = msgLen; msg->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; msg->nlmsg_pid = src.nl_pid; msg->nlmsg_seq = seq++; struct rtmsg *data = (struct rtmsg *)NLMSG_DATA(msg); data->rtm_table = RT_TABLE_DEFAULT; data->rtm_protocol = RTPROT_UNSPEC; struct sockaddr_nl dst; memclr(&dst, sizeof(dst)); dst.nl_family = AF_NETLINK; struct msghdr hdr; memclr(&hdr, sizeof(hdr)); struct iovec iov = { msg, msgLen }; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_name = (void *)&dst; hdr.msg_namelen = sizeof(dst); if (::sendmsg(fd, &hdr, 0/*flags*/) == -1) FLUX_SYSTEM_DEBUG_ERROR(errno); flux::free(msg); } typedef Map<int, Ref<NetworkInterface> > InterfaceByIndex; Ref<InterfaceByIndex> interfaceByIndex = InterfaceByIndex::create(); // process reply { struct msghdr hdr; memclr(&hdr, sizeof(hdr)); ssize_t bufSize = ::recvmsg(fd, &hdr, MSG_PEEK|MSG_TRUNC); if (bufSize < 0) FLUX_SYSTEM_DEBUG_ERROR(errno); void *buf = flux::malloc(bufSize); if (!buf) FLUX_SYSTEM_DEBUG_ERROR(errno); struct iovec iov = { buf, (size_t)bufSize }; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; ssize_t bufFill = ::recvmsg(fd, &hdr, 0/*flags*/); if (::close(fd) == -1) FLUX_SYSTEM_DEBUG_ERROR(errno); struct nlmsghdr *msg = (struct nlmsghdr *)buf; for (;NLMSG_OK(msg, unsigned(bufFill)); msg = NLMSG_NEXT(msg, bufFill)) { unsigned msgType = msg->nlmsg_type; if (msgType == RTM_NEWROUTE) { struct rtmsg *data = (struct rtmsg *)NLMSG_DATA(msg); struct rtattr *attr = (struct rtattr *)RTM_RTA(data); int attrFill = NLMSG_PAYLOAD(msg, sizeof(struct rtmsg)); Ref<RouteInfo> info = RouteInfo::create(); list->append(info); info->sourceMask_ = data->rtm_src_len; info->destinationMask_ = data->rtm_dst_len; for (;RTA_OK(attr, attrFill); attr = RTA_NEXT(attr, attrFill)) { unsigned attrType = attr->rta_type; if ( attrType == RTA_DST || attrType == RTA_SRC || attrType == RTA_GATEWAY ) { Ref<SocketAddress> address; struct sockaddr_in addr4; struct sockaddr_in6 addr6; if (data->rtm_family == AF_INET) { memclr(&addr4, sizeof(addr4)); // addr.sin_len = sizeof(addr); *(uint8_t *)&addr4 = sizeof(addr4); // uggly, but safe HACK, for BSD4.4 addr4.sin_family = AF_INET; addr4.sin_addr = *(struct in_addr *)RTA_DATA(attr); address = SocketAddress::create(&addr4); } else if (data->rtm_family == AF_INET6) { memclr(&addr6, sizeof(addr6)); #ifdef SIN6_LEN addr.sin6_len = sizeof(addr6); #endif addr6.sin6_family = AF_INET6; addr6.sin6_addr = *(struct in6_addr *)RTA_DATA(attr); // addr6.sin6_scope_id = data->rtm_scope; address = SocketAddress::create(&addr6); } if (attrType == RTA_DST) info->destination_ = address; else if (attrType == RTA_SRC) info->source_ = address; else if (attrType == RTA_GATEWAY) info->gateway_ = address; } else if ( attrType == RTA_IIF || attrType == RTA_OIF ) { int index = *(int *)RTA_DATA(attr); Ref<NetworkInterface> interface; if (!interfaceByIndex->lookup(index, &interface)) { interface = NetworkInterface::getLink(index); interfaceByIndex->insert(index, interface); } if (attrType == RTA_IIF) info->inputInterface_ = interface->name(); else info->outputInterface_ = interface->name(); } else if (attrType == RTA_PRIORITY) { info->priority_ = *(int *)RTA_DATA(attr); } else if (attrType == RTA_METRICS) { info->metric_ = *(int *)RTA_DATA(attr); } } } else if (msgType == NLMSG_DONE) { // paranoid HACK break; } } flux::free(buf); } return list; }