static NMIP6Device * process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) { NMIP6Device *device; struct nduseroptmsg *ndmsg; struct nd_opt_hdr *opt; guint opts_len; gboolean changed = FALSE; nm_log_dbg (LOGD_IP6, "processing netlink nduseropt message"); ndmsg = (struct nduseroptmsg *) NLMSG_DATA (nlmsg_hdr (msg)); if (!nlmsg_valid_hdr (nlmsg_hdr (msg), sizeof (*ndmsg)) || nlmsg_datalen (nlmsg_hdr (msg)) < (ndmsg->nduseropt_opts_len + sizeof (*ndmsg))) { nm_log_dbg (LOGD_IP6, "ignoring invalid nduseropt message"); return NULL; } if (ndmsg->nduseropt_family != AF_INET6 || ndmsg->nduseropt_icmp_type != ND_ROUTER_ADVERT || ndmsg->nduseropt_icmp_code != 0) { nm_log_dbg (LOGD_IP6, "ignoring non-Router Advertisement message"); return NULL; } device = nm_ip6_manager_get_device (manager, ndmsg->nduseropt_ifindex); if (!device) { nm_log_dbg (LOGD_IP6, "ignoring message for unknown device"); return NULL; } opt = (struct nd_opt_hdr *) (ndmsg + 1); opts_len = ndmsg->nduseropt_opts_len; while (opts_len >= sizeof (struct nd_opt_hdr)) { size_t nd_opt_len = opt->nd_opt_len; if (nd_opt_len == 0 || opts_len < (nd_opt_len << 3)) break; switch (opt->nd_opt_type) { case ND_OPT_RDNSS: changed = process_nduseropt_rdnss (device, opt); break; case ND_OPT_DNSSL: changed = process_nduseropt_dnssl (device, opt); break; } opts_len -= opt->nd_opt_len << 3; opt = (struct nd_opt_hdr *) ((uint8_t *) opt + (opt->nd_opt_len << 3)); } if (changed) return device; else return NULL; }
static NMIP6Device * process_prefix (NMIP6Manager *manager, struct nl_msg *msg) { struct prefixmsg *pmsg; NMIP6Device *device; /* We don't care about the prefix itself, but if we receive a * router advertisement telling us to use DHCP, we might not * get any RTM_NEWADDRs or RTM_NEWROUTEs, so this is our only * way to notice immediately that an RA was received. */ nm_log_dbg (LOGD_IP6, "processing netlink new prefix message"); if (!nlmsg_valid_hdr (nlmsg_hdr (msg), sizeof(*pmsg))) { nm_log_dbg (LOGD_IP6, "ignoring invalid prefix message"); return NULL; } pmsg = (struct prefixmsg *) NLMSG_DATA (nlmsg_hdr (msg)); device = nm_ip6_manager_get_device (manager, pmsg->prefix_ifindex); if (!device || device->addrconf_complete) { nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device", device ? device->iface : "(none)"); return NULL; } return device; }
static int parse_reply (struct nl_msg *msg, void *arg) { struct nlmsghdr *n = nlmsg_hdr (msg); struct nlattr *tb[XFRMA_MAX + 1]; struct xfrm_userpolicy_info *xpinfo = NULL; if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) { g_warning ("msg type %d not NEWPOLICY", n->nlmsg_type); return NL_SKIP; } /* Netlink message header is followed by 'struct xfrm_userpolicy_info' and * then the attributes. */ if (!nlmsg_valid_hdr (n, sizeof (struct xfrm_userpolicy_info))) { g_warning ("msg too short"); return -NLE_MSG_TOOSHORT; } xpinfo = nlmsg_data (n); if (nla_parse (tb, XFRMA_MAX, nlmsg_attrdata (n, sizeof (struct xfrm_userpolicy_info)), nlmsg_attrlen (n, sizeof (struct xfrm_userpolicy_info)), NULL) < 0) { g_warning ("failed to parse attributes"); return NL_SKIP; } if (tb[XFRMA_TMPL]) { int attrlen = nla_len (tb[XFRMA_TMPL]); struct xfrm_user_tmpl *list = nla_data (tb[XFRMA_TMPL]); int i; xfrm_selector_print (&xpinfo->sel); for (i = 0; i < attrlen / sizeof (struct xfrm_user_tmpl); i++) { struct xfrm_user_tmpl *tmpl = &list[i]; char buf[INET6_ADDRSTRLEN]; g_print (" tmpl "); inet_ntop (tmpl->family, (gpointer) &tmpl->saddr, buf, sizeof (buf)); g_print ("src %s ", buf); inet_ntop (tmpl->family, &tmpl->id.daddr, buf, sizeof (buf)); g_print ("dst %s\n", buf); } } return NL_OK; }
/** * Validate Generic Netlink message headers * @arg nlh Pointer to Netlink message header * @arg hdrlen Length of user header * * Verifies the integrity of the Netlink and Generic Netlink headers by * enforcing the following requirements: * - Valid Netlink message header (nlmsg_valid_hdr()) * - Presence of a complete Generic Netlink header * - At least \c hdrlen bytes of payload included after the generic * netlink header. * * @return A positive integer (true) if the headers are valid or * 0 (false) if not. */ int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen) { struct genlmsghdr *ghdr; if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN)) return 0; ghdr = nlmsg_data(nlh); if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen)) return 0; return 1; }
static int __ni_rtevent_nduseropt(ni_netconfig_t *nc, const struct sockaddr_nl *nladdr, struct nlmsghdr *h) { struct nduseroptmsg *msg; struct nd_opt_hdr *opt; ni_netdev_t *dev; if (!(msg = ni_rtnl_nduseroptmsg(h, RTM_NEWNDUSEROPT))) return -1; dev = ni_netdev_by_index(nc, msg->nduseropt_ifindex); if (!dev) { ni_debug_events("ipv6 nd user option event for unknown device index: %u", msg->nduseropt_ifindex); return 0; } if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT || msg->nduseropt_icmp_code != 0 || msg->nduseropt_family != AF_INET6) { ni_debug_events("%s: unknown rtnetlink nd user option message" " type %d, code %d, family %d", dev->name, msg->nduseropt_icmp_type, msg->nduseropt_icmp_code, msg->nduseropt_family); return 0; } if (!nlmsg_valid_hdr(h, sizeof(struct nduseroptmsg) + msg->nduseropt_opts_len)) { ni_debug_events("%s: invalid rtnetlink nd user radv option length %d", dev->name, msg->nduseropt_opts_len); return -1; } opt = (struct nd_opt_hdr *)(msg + 1); return __ni_rtevent_process_nd_radv_opts(dev, opt, msg->nduseropt_opts_len); }