static int netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_netfilter *handlep = handle->priv; const unsigned char *buf; int count = 0; int len; /* ignore interrupt system call error */ do { len = recv(handle->fd, handle->buffer, handle->bufsize, 0); if (handle->break_loop) { handle->break_loop = 0; return -2; } if(errno == ENOBUFS) handlep->packets_nobufs++; } while ((len == -1) && (errno == EINTR || errno == ENOBUFS)); if (len < 0) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", errno, pcap_strerror(errno)); return -1; } buf = (unsigned char *)handle->buffer; while ((u_int)len >= NLMSG_SPACE(0)) { const struct nlmsghdr *nlh = (const struct nlmsghdr *) buf; u_int32_t msg_len; nftype_t type = OTHER; if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len); return -1; } if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) type = NFLOG; else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET) type = NFQUEUE; if (type != OTHER) { const unsigned char *payload = NULL; struct pcap_pkthdr pkth; const struct nfgenmsg *nfg = NULL; int id = 0; if (handle->linktype != DLT_NFLOG) { const struct nfattr *payload_attr = NULL; if (nlh->nlmsg_len < HDR_LENGTH) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); return -1; } nfg = NLMSG_DATA(nlh); if (nlh->nlmsg_len > HDR_LENGTH) { struct nfattr *attr = NFM_NFA(nfg); int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); while (NFA_OK(attr, attr_len)) { if (type == NFQUEUE) { switch (NFA_TYPE(attr)) { case NFQA_PACKET_HDR: { const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr); id = ntohl(pkt_hdr->packet_id); break; } case NFQA_PAYLOAD: payload_attr = attr; break; } } else if (type == NFLOG) { switch (NFA_TYPE(attr)) { case NFULA_PAYLOAD: payload_attr = attr; break; } } attr = NFA_NEXT(attr, attr_len); } } if (payload_attr) { payload = NFA_DATA(payload_attr); pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); } } else { payload = NLMSG_DATA(nlh); pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); } if (payload) { /* pkth.caplen = min (payload_len, handle->snapshot); */ gettimeofday(&pkth.ts, NULL); if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, payload); count++; } } if (type == NFQUEUE) { /* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */ /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG, so nfg is always initialized to NLMSG_DATA(nlh). */ if (nfg != NULL) nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT); } } msg_len = NLMSG_ALIGN(nlh->nlmsg_len); if (msg_len > (u_int)len) msg_len = (u_int)len; len -= msg_len; buf += msg_len; } return count; }
/* * --------------------------------------------------------------------------- * Returns next netlink message in the stream. * --------------------------------------------------------------------------- */ PNL_MSG_HDR NlMsgNext(const PNL_MSG_HDR nlh) { return (PNL_MSG_HDR)((PCHAR)nlh + NLMSG_ALIGN(nlh->nlmsgLen)); }
int get_src_for_route_to(const struct sockaddr * dst, void * src, size_t * src_len, int * index) { int fd = -1; struct nlmsghdr *h; int status; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*) &req.n, }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; const struct sockaddr_in * dst4; const struct sockaddr_in6 * dst6; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = dst->sa_family; req.r.rtm_table = 0; req.r.rtm_protocol = 0; req.r.rtm_scope = 0; req.r.rtm_type = 0; req.r.rtm_src_len = 0; req.r.rtm_dst_len = 0; req.r.rtm_tos = 0; { char dst_str[128]; sockaddr_to_string(dst, dst_str, sizeof(dst_str)); syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str); } /* add address */ if(dst->sa_family == AF_INET) { dst4 = (const struct sockaddr_in *)dst; nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4); req.r.rtm_dst_len = 32; } else { dst6 = (const struct sockaddr_in6 *)dst; nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16); req.r.rtm_dst_len = 128; } fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m"); return -1; } memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req.n.nlmsg_seq = 1; iov.iov_len = req.n.nlmsg_len; status = sendmsg(fd, &msg, 0); if (status < 0) { syslog(LOG_ERR, "sendmsg(rtnetlink) : %m"); goto error; } memset(&req, 0, sizeof(req)); for(;;) { iov.iov_len = sizeof(req); status = recvmsg(fd, &msg, 0); if(status < 0) { if (errno == EINTR || errno == EAGAIN) continue; syslog(LOG_ERR, "recvmsg(rtnetlink) %m"); goto error; } if(status == 0) { syslog(LOG_ERR, "recvmsg(rtnetlink) EOF"); goto error; } for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) { int len = h->nlmsg_len; int l = len - sizeof(*h); if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { syslog(LOG_ERR, "Truncated message"); } syslog(LOG_ERR, "malformed message: len=%d", len); goto error; } if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) { syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq); /* Don't forget to skip that message. */ status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); continue; } if(h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error)); goto error; } if(h->nlmsg_type == RTM_NEWROUTE) { struct rtattr * rta; int len = h->nlmsg_len; len -= NLMSG_LENGTH(sizeof(struct rtmsg)); for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) { unsigned char * data = RTA_DATA(rta); if(rta->rta_type == RTA_PREFSRC) { if(src_len && src) { if(*src_len < RTA_PAYLOAD(rta)) { syslog(LOG_WARNING, "cannot copy src: %u<%u", (unsigned)*src_len, RTA_PAYLOAD(rta)); goto error; } *src_len = RTA_PAYLOAD(rta); memcpy(src, data, RTA_PAYLOAD(rta)); } } else if(rta->rta_type == RTA_OIF) { if(index) memcpy(index, data, sizeof(int)); } } close(fd); return 0; } status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } } syslog(LOG_WARNING, "get_src_for_route_to() : src not found"); error: if(fd >= 0) close(fd); return -1; }
/* * debug route message */ void debug_rtmsg(int lev, struct rtmsg *rtm, struct rtattr *rta[], int rtm_len) { /* debug rtmsg */ char flags_list[MAX_STR_SIZE] = ""; conv_rtm_flags(rtm->rtm_flags, flags_list, sizeof(flags_list)); rec_dbg(lev, "*********************************************************************"); rec_dbg(lev, "[ rtmsg(%d) ]", NLMSG_ALIGN(sizeof(struct rtmsg))); rec_dbg(lev, " rtm_family(%d): %d(%s)", sizeof(rtm->rtm_family), rtm->rtm_family, conv_af_type(rtm->rtm_family, 1)); rec_dbg(lev, " rtm_dst_len(%d): %d", sizeof(rtm->rtm_dst_len), rtm->rtm_dst_len); rec_dbg(lev, " rtm_src_len(%d): %d", sizeof(rtm->rtm_src_len), rtm->rtm_src_len); rec_dbg(lev, " rtm_tos(%d): %d", sizeof(rtm->rtm_tos), rtm->rtm_tos); rec_dbg(lev, " rtm_table(%d): %d(%s)", sizeof(rtm->rtm_table), rtm->rtm_table, conv_rt_table(rtm->rtm_table, 1)); rec_dbg(lev, " rtm_protocol(%d): %d(%s)", sizeof(rtm->rtm_protocol), rtm->rtm_protocol, conv_rtprot(rtm->rtm_protocol, 1)); rec_dbg(lev, " rtm_scope(%d): %d(%s)", sizeof(rtm->rtm_scope), rtm->rtm_scope, conv_rt_scope(rtm->rtm_scope)); rec_dbg(lev, " rtm_type(%d): %d(%s)", sizeof(rtm->rtm_type), rtm->rtm_type, conv_rtn_type(rtm->rtm_type, 1)); rec_dbg(lev, " rtm_flags(%d): %d(%s)", sizeof(rtm->rtm_flags), rtm->rtm_flags, flags_list); /* debug route attributes */ rec_dbg(lev, "*********************************************************************"); rec_dbg(lev, "[ rtmsg attributes(%d) ]", NLMSG_ALIGN(rtm_len - NLMSG_ALIGN(sizeof(struct rtmsg)))); if(rta[RTA_DST]) debug_rta_af(lev+1, rta[RTA_DST], "RTA_DST", rtm->rtm_family); if(rta[RTA_SRC]) debug_rta_af(lev+1, rta[RTA_SRC], "RTA_SRC", rtm->rtm_family); if(rta[RTA_IIF]) debug_rta_ifindex(lev+1, rta[RTA_IIF], "RTA_IIF"); if(rta[RTA_OIF]) debug_rta_ifindex(lev+1, rta[RTA_OIF], "RTA_OIF"); if(rta[RTA_GATEWAY]) debug_rta_af(lev+1, rta[RTA_GATEWAY], "RTA_GATEWAY", rtm->rtm_family); if(rta[RTA_PRIORITY]) debug_rta_s32(lev+1, rta[RTA_PRIORITY], "RTA_PRIORITY", NULL); if(rta[RTA_PREFSRC]) debug_rta_af(lev+1, rta[RTA_PREFSRC], "RTA_PREFSRC", rtm->rtm_family); if(rta[RTA_METRICS]) debug_rta_metrics(lev+1, rta[RTA_METRICS], "RTA_METRICS"); if(rta[RTA_MULTIPATH]) debug_rta_multipath(lev+1, rtm, rta[RTA_MULTIPATH], "RTA_MULTIPATH"); if(rta[RTA_FLOW]) debug_rta_u32(lev+1, rta[RTA_FLOW], "RTA_FLOW", NULL); if(rta[RTA_CACHEINFO]) debug_rta_cacheinfo(lev+1, rta[RTA_CACHEINFO], "RTA_CACHEINFO"); if(rta[RTA_TABLE]) debug_rta_s32(lev+1, rta[RTA_TABLE], "RTA_TABLE", conv_rt_table); #if HAVE_DECL_RTA_MARK if(rta[RTA_MARK]) debug_rta_u32(lev+1, rta[RTA_MARK], "RTA_MARK", NULL); #endif rec_dbg(lev, ""); return; }
static int send_probe(int ifindex, __u32 addr) { struct ifreq ifr = { .ifr_ifindex = ifindex }; struct sockaddr_in dst = { .sin_family = AF_INET, .sin_port = htons(1025), .sin_addr.s_addr = addr, }; socklen_t len; unsigned char buf[256]; struct arphdr *ah = (struct arphdr *)buf; unsigned char *p = (unsigned char *)(ah+1); struct sockaddr_ll sll = { .sll_family = AF_PACKET, .sll_ifindex = ifindex, .sll_protocol = htons(ETH_P_ARP), }; if (ioctl(udp_sock, SIOCGIFNAME, &ifr)) return -1; if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr)) return -1; if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) return -1; if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0) return -1; if (connect(udp_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) return -1; len = sizeof(dst); if (getsockname(udp_sock, (struct sockaddr *)&dst, &len) < 0) return -1; ah->ar_hrd = htons(ifr.ifr_hwaddr.sa_family); ah->ar_pro = htons(ETH_P_IP); ah->ar_hln = 6; ah->ar_pln = 4; ah->ar_op = htons(ARPOP_REQUEST); memcpy(p, ifr.ifr_hwaddr.sa_data, ah->ar_hln); p += ah->ar_hln; memcpy(p, &dst.sin_addr, 4); p += 4; memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr)); memcpy(p, &sll.sll_addr, ah->ar_hln); p += ah->ar_hln; memcpy(p, &addr, 4); p += 4; if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr *)&sll, sizeof(sll)) < 0) return -1; stats.probes_sent++; return 0; } /* Be very tough on sending probes: 1 per second with burst of 3. */ static int queue_active_probe(int ifindex, __u32 addr) { static struct timeval prev; static int buckets; struct timeval now; gettimeofday(&now, NULL); if (prev.tv_sec) { int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000; buckets += diff; } else { buckets = broadcast_burst; } if (buckets > broadcast_burst) buckets = broadcast_burst; if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) { buckets -= broadcast_rate; prev = now; return 0; } stats.probes_suppressed++; return -1; } static int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen) { struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), .n.nlmsg_flags = NLM_F_REQUEST, .n.nlmsg_type = RTM_NEWNEIGH, .ndm.ndm_family = AF_INET, .ndm.ndm_state = NUD_STALE, .ndm.ndm_ifindex = ifindex, .ndm.ndm_type = RTN_UNICAST, }; addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0; } static void prepare_neg_entry(__u8 *ndata, __u32 stamp) { ndata[0] = 0xFF; ndata[1] = 0; ndata[2] = stamp>>24; ndata[3] = stamp>>16; ndata[4] = stamp>>8; ndata[5] = stamp; } static int do_one_request(struct nlmsghdr *n) { struct ndmsg *ndm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NDA_MAX+1]; struct dbkey key; DBT dbkey, dbdat; int do_acct = 0; if (n->nlmsg_type == NLMSG_DONE) { dbase->sync(dbase, 0); /* Now we have at least mirror of kernel db, so that * may start real resolution. */ do_sysctl_adjustments(); return 0; } if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH) return 0; len -= NLMSG_LENGTH(sizeof(*ndm)); if (len < 0) return -1; if (ndm->ndm_family != AF_INET || (ifnum && !handle_if(ndm->ndm_ifindex)) || ndm->ndm_flags || ndm->ndm_type != RTN_UNICAST || !(ndm->ndm_state&~NUD_NOARP)) return 0; parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); if (!tb[NDA_DST]) return 0; key.iface = ndm->ndm_ifindex; memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4); dbkey.data = &key; dbkey.size = sizeof(key); if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) { dbdat.data = 0; dbdat.size = 0; } if (n->nlmsg_type == RTM_GETNEIGH) { if (!(n->nlmsg_flags&NLM_F_REQUEST)) return 0; if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) { stats.app_bad++; return 0; } if (ndm->ndm_state&NUD_PROBE) { /* If we get this, kernel still has some valid * address, but unicast probing failed and host * is either dead or changed its mac address. * Kernel is going to initiate broadcast resolution. * OK, we invalidate our information as well. */ if (dbdat.data && !IS_NEG(dbdat.data)) stats.app_neg++; dbase->del(dbase, &dbkey, 0); } else { /* If we get this kernel does not have any information. * If we have something tell this to kernel. */ stats.app_recv++; if (dbdat.data && !IS_NEG(dbdat.data)) { stats.app_success++; respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size); return 0; } /* Sheeit! We have nothing to tell. */ /* If we have recent negative entry, be silent. */ if (dbdat.data && NEG_VALID(dbdat.data)) { if (NEG_CNT(dbdat.data) >= active_probing) { stats.app_suppressed++; return 0; } do_acct = 1; } } if (active_probing && queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 && do_acct) { NEG_CNT(dbdat.data)++; dbase->put(dbase, &dbkey, &dbdat, 0); } } else if (n->nlmsg_type == RTM_NEWNEIGH) { if (n->nlmsg_flags&NLM_F_REQUEST) return 0; if (ndm->ndm_state&NUD_FAILED) { /* Kernel was not able to resolve. Host is dead. * Create negative entry if it is not present * or renew it if it is too old. */ if (!dbdat.data || !IS_NEG(dbdat.data) || !NEG_VALID(dbdat.data)) { __u8 ndata[6]; stats.kern_neg++; prepare_neg_entry(ndata, time(NULL)); dbdat.data = ndata; dbdat.size = sizeof(ndata); dbase->put(dbase, &dbkey, &dbdat, 0); } } else if (tb[NDA_LLADDR]) { if (dbdat.data && !IS_NEG(dbdat.data)) { if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0) return 0; stats.kern_change++; } else { stats.kern_new++; } dbdat.data = RTA_DATA(tb[NDA_LLADDR]); dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]); dbase->put(dbase, &dbkey, &dbdat, 0); } } return 0; } static void load_initial_table(void) { if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH) < 0) { perror("dump request failed"); exit(1); } } static void get_kern_msg(void) { int status; 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 }; iov.iov_base = buf; iov.iov_len = sizeof(buf); status = recvmsg(rth.fd, &msg, MSG_DONTWAIT); if (status <= 0) return; if (msg.msg_namelen != sizeof(nladdr)) return; if (nladdr.nl_pid) return; for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) { int len = h->nlmsg_len; int l = len - sizeof(*h); if (l < 0 || len > status) return; if (do_one_request(h) < 0) return; status -= NLMSG_ALIGN(len); h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); } }
int tc_act_list_or_flush(int argc, char **argv, int event) { int ret = 0, prio = 0, msg_size = 0; char k[16]; struct rtattr *tail,*tail2; struct action_util *a = NULL; struct { struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; } req; req.t.tca_family = AF_UNSPEC; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); tail = NLMSG_TAIL(&req.n); addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0); tail2 = NLMSG_TAIL(&req.n); strncpy(k, *argv, sizeof (k) - 1); #ifdef CONFIG_GACT if (!gact_ld) { get_action_kind("gact"); } #endif a = get_action_kind(k); if (NULL == a) { fprintf(stderr,"bad action %s\n",k); goto bad_val; } if (strcmp(a->id, k) != 0) { fprintf(stderr,"bad action %s\n",k); goto bad_val; } strncpy(k, *argv, sizeof (k) - 1); addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0); addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1); tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2; tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail; msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr)); if (event == RTM_GETACTION) { if (rtnl_dump_request(&rth, event, (void *)&req.t, msg_size) < 0) { perror("Cannot send dump request"); return 1; } ret = rtnl_dump_filter(&rth, print_action, stdout, NULL, NULL); } if (event == RTM_DELACTION) { req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len); req.n.nlmsg_type = RTM_DELACTION; req.n.nlmsg_flags |= NLM_F_ROOT; req.n.nlmsg_flags |= NLM_F_REQUEST; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { fprintf(stderr, "We have an error flushing\n"); return 1; } } bad_val: return ret; }
int checkIpAddrTableChanges(PMIB_IPADDRTABLE pNew, PMIB_IPADDRTABLE pOld) { enum { IP_ADD, IP_DEL, IP_CHG, }; int i, max, ret = 0; if (!pNew || !pOld) { return(0); } max = (pNew->dwNumEntries > pOld->dwNumEntries) ? pNew->dwNumEntries : pOld->dwNumEntries; /* printf("IP table: ["); */ for (i = 0; i < max; i++) { /* printf("%u.%u.%u.%u(%d) ", NIPQUAD(pNew->table[i].dwAddr), */ /* (int)pNew->table[i].dwIndex); */ #ifdef __WIN32__ if ((pNew->table[i].dwAddr != pOld->table[i].dwAddr) || (pNew->table[i].wType != pOld->table[i].wType)) { if ((pNew->table[i].wType & MIB_IPADDR_DELETED) || ((pNew->table[i].wType & MIB_IPADDR_DISCONNECTED))) { netlink_send_addr(1, pOld->table[i].dwAddr, pOld->table[i].dwIndex); } #else if ((pNew->table[i].dwAddr != pOld->table[i].dwAddr) || (pNew->table[i].unused2 != pOld->table[i].unused2)) { /* unused2 is wType */ /* Address deleted due to flags */ if ((pNew->table[i].unused2 & MIB_IPADDR_DELETED) || ((pNew->table[i].unused2 & MIB_IPADDR_DISCONNECTED))) { netlink_send_addr(1, pOld->table[i].dwAddr, pOld->table[i].dwIndex); } #endif /* Address deleted, replaced by 0.0.0.0 */ else if ((pNew->table[i].dwAddr == 0) && (pOld->table[i].dwAddr) && (pOld->table[i].dwIndex == pNew->table[i].dwIndex)) { netlink_send_addr(1, pOld->table[i].dwAddr, pOld->table[i].dwIndex); } /* New address */ else { /* first delete old address, if any */ if ((pOld->table[i].dwAddr) && (pOld->table[i].dwIndex == pNew->table[i].dwIndex)) { netlink_send_addr( 1, pOld->table[i].dwAddr, pOld->table[i]. dwIndex); } /* send new address */ netlink_send_addr(0, pNew->table[i].dwAddr, pNew->table[i].dwIndex); } ret = 1; } } /* printf("]\n"); */ return(ret); } /* * 0 = add, 1 = deleted */ int netlink_send_addr(int add_del, DWORD addr, DWORD ifindex) { char buff[512]; int len; struct nlmsghdr *msg; struct ifaddrmsg *ifa; struct rtattr *rta; __u32 *p_addr; /* ignore 0.0.0.0 and 1.x.x.x */ if ((addr == 0) || (addr == g_tap_lsi)) { return(0); } /* printf("Address %u.%u.%u.%u has been ", NIPQUAD(addr)); * printf("%s.\n", add_del ? "deleted" : "added"); */ /* netlink message header */ memset(buff, 0, sizeof(buff)); msg = (struct nlmsghdr*) &buff[0]; len = NLMSG_LENGTH( sizeof(struct ifaddrmsg) + sizeof(struct rtattr) + sizeof(__u32)); msg->nlmsg_len = NLMSG_ALIGN(len); msg->nlmsg_type = add_del ? RTM_DELADDR : RTM_NEWADDR; msg->nlmsg_flags = 0; msg->nlmsg_seq = 0; msg->nlmsg_pid = 0; /* interface address message */ ifa = (struct ifaddrmsg*) NLMSG_DATA(msg); ifa->ifa_family = AF_INET; ifa->ifa_prefixlen = 32; ifa->ifa_flags = IFA_F_PERMANENT; ifa->ifa_scope = IFA_LOCAL; ifa->ifa_index = ifindex; /* route attributes */ rta = IFA_RTA(ifa); rta->rta_len = RTA_LENGTH(sizeof(__u32)); rta->rta_type = IFA_LOCAL; p_addr = (__u32*)(rta + 1); *p_addr = addr; /* host byte order */ #ifdef __WIN32__ if (send(netlsp[0], buff, len, 0) < 0) { #else if (write(netlsp[0], buff, len) < 0) { #endif printf("netlink_send_addr() write error: %s", strerror(errno)); return(-1); } return(0); } int sendIpAddrTable(PMIB_IPADDRTABLE pTable) { char buff[1024]; int len, total_len = 0, status, i; struct nlmsghdr *msg; struct ifaddrmsg *ifa; struct rtattr *rta; __u32 *p_addr; if (!pTable) { return(-1); } memset(buff, 0, sizeof(buff)); status = sizeof(buff); len = NLMSG_LENGTH( sizeof(struct ifaddrmsg) + sizeof(struct rtattr) + sizeof(__u32)); msg = (struct nlmsghdr *) buff; /* due to timing, LSI is not in Window's IP table yet, * but is needed by hipd for the ACQUIRE, so here we add * it manually */ msg->nlmsg_len = NLMSG_ALIGN(len); total_len += len; msg->nlmsg_type = NLMSG_NOOP; msg->nlmsg_flags = 0; msg->nlmsg_seq = 0; msg->nlmsg_pid = 0; ifa = (struct ifaddrmsg*) NLMSG_DATA(msg); ifa->ifa_family = AF_INET; ifa->ifa_prefixlen = 32; ifa->ifa_flags = IFA_F_PERMANENT; ifa->ifa_scope = IFA_LOCAL; ifa->ifa_index = 65542; rta = IFA_RTA(ifa); rta->rta_len = RTA_LENGTH(sizeof(__u32)); rta->rta_type = IFA_LOCAL; p_addr = (__u32*)(rta + 1); *p_addr = g_tap_lsi; msg = NLMSG_NEXT(msg, status); /* step through IP address table and add to netlink dump message */ for (i = 0; i < (int)pTable->dwNumEntries; i++) { /* omit 0.0.0.0; (LSI is needed for ACQUIRE mechanism) */ if (pTable->table[i].dwAddr == 0) { continue; } msg->nlmsg_len = NLMSG_ALIGN(len); total_len += len; msg->nlmsg_type = NLMSG_NOOP; msg->nlmsg_flags = 0; msg->nlmsg_seq = 0; msg->nlmsg_pid = 0; /* interface address message */ ifa = (struct ifaddrmsg*) NLMSG_DATA(msg); ifa->ifa_family = AF_INET; ifa->ifa_prefixlen = 32; ifa->ifa_flags = IFA_F_PERMANENT; ifa->ifa_scope = IFA_LOCAL; ifa->ifa_index = pTable->table[i].dwIndex; /* route attributes */ rta = IFA_RTA(ifa); rta->rta_len = RTA_LENGTH(sizeof(__u32)); rta->rta_type = IFA_LOCAL; p_addr = (__u32*)(rta + 1); *p_addr = pTable->table[i].dwAddr; msg = NLMSG_NEXT(msg, status); } /* finish with a done message */ msg->nlmsg_len = NLMSG_LENGTH(0); msg->nlmsg_type = NLMSG_DONE; msg->nlmsg_flags = 0; msg->nlmsg_seq = 0; msg->nlmsg_pid = 0; total_len += msg->nlmsg_len; #ifdef __WIN32__ send(netlsp[0], buff, total_len, 0); #else write(netlsp[0], buff, total_len); #endif return(total_len); }
/* * --------------------------------------------------------------------------- * memsets length 'len' at head of NL_BUF. * Refer nl_msg_push_uninit for more details. * --------------------------------------------------------------------------- */ PCHAR NlMsgPutHeadUninit(PNL_BUFFER buf, UINT32 len) { len = NLMSG_ALIGN(len); return NlBufCopyAtHeadUninit(buf, len); }
static int netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { struct pcap_netfilter *handlep = handle->priv; register u_char *bp, *ep; int count = 0; int len; /* * Has "pcap_breakloop()" been called? */ if (handle->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return PCAP_ERROR_BREAK to indicate * that we were told to break out of the loop. */ handle->break_loop = 0; return PCAP_ERROR_BREAK; } len = handle->cc; if (len == 0) { /* * The buffer is empty; refill it. * * We ignore EINTR, as that might just be due to a signal * being delivered - if the signal should interrupt the * loop, the signal handler should call pcap_breakloop() * to set handle->break_loop (we ignore it on other * platforms as well). */ do { len = recv(handle->fd, handle->buffer, handle->bufsize, 0); if (handle->break_loop) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } if (errno == ENOBUFS) handlep->packets_nobufs++; } while ((len == -1) && (errno == EINTR || errno == ENOBUFS)); if (len < 0) { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't receive packet"); return PCAP_ERROR; } bp = (unsigned char *)handle->buffer; } else bp = handle->bp; ep = bp + len; while (bp < ep) { const struct nlmsghdr *nlh = (const struct nlmsghdr *) bp; uint32_t msg_len; nftype_t type = OTHER; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return PCAP_ERROR_BREAK * to indicate that we were told to break out of the loop, * otherwise leave the flag set, so that the *next* call * will break out of the loop without having read any * packets, and return the number of packets we've * processed so far. */ if (handle->break_loop) { handle->bp = bp; handle->cc = ep - bp; if (count == 0) { handle->break_loop = 0; return PCAP_ERROR_BREAK; } else return count; } if (ep - bp < NLMSG_SPACE(0)) { /* * There's less than one netlink message left * in the buffer. Give up. */ break; } if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len); return -1; } if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) type = NFLOG; else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET) type = NFQUEUE; if (type != OTHER) { const unsigned char *payload = NULL; struct pcap_pkthdr pkth; const struct nfgenmsg *nfg = NULL; int id = 0; if (handle->linktype != DLT_NFLOG) { const struct nfattr *payload_attr = NULL; if (nlh->nlmsg_len < HDR_LENGTH) { pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); return -1; } nfg = NLMSG_DATA(nlh); if (nlh->nlmsg_len > HDR_LENGTH) { struct nfattr *attr = NFM_NFA(nfg); int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); while (NFA_OK(attr, attr_len)) { if (type == NFQUEUE) { switch (NFA_TYPE(attr)) { case NFQA_PACKET_HDR: { const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr); id = ntohl(pkt_hdr->packet_id); break; } case NFQA_PAYLOAD: payload_attr = attr; break; } } else if (type == NFLOG) { switch (NFA_TYPE(attr)) { case NFULA_PAYLOAD: payload_attr = attr; break; } } attr = NFA_NEXT(attr, attr_len); } } if (payload_attr) { payload = NFA_DATA(payload_attr); pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); } } else { payload = NLMSG_DATA(nlh); pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); } if (payload) { /* pkth.caplen = min (payload_len, handle->snapshot); */ gettimeofday(&pkth.ts, NULL); if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) { handlep->packets_read++; callback(user, &pkth, payload); count++; } } if (type == NFQUEUE) { /* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */ /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG, so nfg is always initialized to NLMSG_DATA(nlh). */ if (nfg != NULL) nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT); } } msg_len = NLMSG_ALIGN(nlh->nlmsg_len); /* * If the message length would run past the end of the * buffer, truncate it to the remaining space in the * buffer. */ if (msg_len > ep - bp) msg_len = ep - bp; bp += msg_len; if (count >= max_packets && !PACKET_COUNT_IS_UNLIMITED(max_packets)) { handle->bp = bp; handle->cc = ep - bp; if (handle->cc < 0) handle->cc = 0; return count; } } handle->cc = 0; return count; }
int main(void) { nl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); if (nl_fd < 0) { perror("socket()"); return -1; } memset(&nl_address, 0, sizeof(nl_address)); nl_address.nl_family = AF_NETLINK; nl_address.nl_groups = 0; if (bind(nl_fd, (struct sockaddr *) &nl_address, sizeof(nl_address)) < 0) { perror("bind()"); close(nl_fd); return -1; } nl_request_msg.n.nlmsg_type = GENL_ID_CTRL;//这是内核中genl_ctl的id nl_request_msg.n.nlmsg_flags = NLM_F_REQUEST; nl_request_msg.n.nlmsg_seq = 0; nl_request_msg.n.nlmsg_pid = getpid(); nl_request_msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); //Populate the payload's "family header" : which in our case is genlmsghdr nl_request_msg.g.cmd = CTRL_CMD_GETFAMILY; nl_request_msg.g.version = 0x1; //Populate the payload's "netlink attributes" nl_na = (struct nlattr *) GENLMSG_DATA(&nl_request_msg);//其实就相当于在nl_request_msg 的buf域中构造一个nla nl_na->nla_type = CTRL_ATTR_FAMILY_NAME; nl_na->nla_len = strlen("CONTROL_EXMPL") + 1 + NLA_HDRLEN; strcpy(NLA_DATA(nl_na), "CONTROL_EXMPL"); //Family name length can be upto 16 chars including \0 nl_request_msg.n.nlmsg_len += NLMSG_ALIGN(nl_na->nla_len); memset(&nl_address, 0, sizeof(nl_address)); nl_address.nl_family = AF_NETLINK; len= sendto(nl_fd, (char *) &nl_request_msg, nl_request_msg.n.nlmsg_len, 0, (struct sockaddr *) &nl_address, sizeof(nl_address)); if (len != nl_request_msg.n.nlmsg_len) { perror("sendto()"); close(nl_fd); return -1; } len= recv(nl_fd, &nl_response_msg, sizeof(nl_response_msg), 0); if (len < 0) { perror("recv()"); return -1; } if (!NLMSG_OK((&nl_response_msg.n), len)) { fprintf(stderr, "family ID request : invalid message\n"); return -1; } if (nl_response_msg.n.nlmsg_type == NLMSG_ERROR) { //error fprintf(stderr, "family ID request : receive error\n"); return -1; } //解析出attribute中的family id nl_na = (struct nlattr *) GENLMSG_DATA(&nl_response_msg); nl_na = (struct nlattr *) ((char *) nl_na + NLA_ALIGN(nl_na->nla_len)); if (nl_na->nla_type == CTRL_ATTR_FAMILY_ID) { nl_family_id = *(__u16 *) NLA_DATA(nl_na);//第一次通信就是为了得到需要的family ID } memset(&nl_request_msg, 0, sizeof(nl_request_msg)); memset(&nl_response_msg, 0, sizeof(nl_response_msg)); nl_request_msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); nl_request_msg.n.nlmsg_type = nl_family_id; nl_request_msg.n.nlmsg_flags = NLM_F_REQUEST; nl_request_msg.n.nlmsg_seq = 60; nl_request_msg.n.nlmsg_pid = getpid(); nl_request_msg.g.cmd = 1; //corresponds to DOC_EXMPL_C_ECHO; nl_na = (struct nlattr *) GENLMSG_DATA(&nl_request_msg); nl_na->nla_type = 1; // corresponds to DOC_EXMPL_A_MSG nl_na->nla_len = sizeof(MESSAGE_TO_KERNEL)+NLA_HDRLEN; //Message length memcpy(NLA_DATA(nl_na), MESSAGE_TO_KERNEL, sizeof(MESSAGE_TO_KERNEL)); nl_request_msg.n.nlmsg_len += NLMSG_ALIGN(nl_na->nla_len); memset(&nl_address, 0, sizeof(nl_address)); nl_address.nl_family = AF_NETLINK; len = sendto(nl_fd, (char *) &nl_request_msg, nl_request_msg.n.nlmsg_len, 0, (struct sockaddr *) &nl_address, sizeof(nl_address)); if (len != nl_request_msg.n.nlmsg_len) { perror("sendto()"); close(nl_fd); return -1; } printf("Sent to kernel: %s\n",MESSAGE_TO_KERNEL); len = recv(nl_fd, &nl_response_msg, sizeof(nl_response_msg), 0); if (len < 0) { perror("recv()"); return -1; } //异常处理 if (nl_response_msg.n.nlmsg_type == NLMSG_ERROR) { //Error printf("Error while receiving reply from kernel: NACK Received\n"); close(nl_fd); return -1; } if (len < 0) { printf("Error while receiving reply from kernel\n"); close(nl_fd); return -1; } if (!NLMSG_OK((&nl_response_msg.n), len)) { printf("Error while receiving reply from kernel: Invalid Message\n"); close(nl_fd); return -1; } //解析收到的来自内核的reply len = GENLMSG_PAYLOAD(&nl_response_msg.n); nl_na = (struct nlattr *) GENLMSG_DATA(&nl_response_msg); printf("Kernel replied: %s\n",(char *)NLA_DATA(nl_na)); close(nl_fd); return 0; }
/** * Get length of attribute data * @arg gnlh generic netlink message header * @arg hdrlen length of family specific header */ int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen) { return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen); }
/** * Get head of attribute data * @arg gnlh generic netlink message header * @arg hdrlen length of family specific header */ struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen) { return genlmsg_data(gnlh) + NLMSG_ALIGN(hdrlen); }
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)) { *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; } 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; }
/* If successful the updated message will be correctly aligned, if unsuccessful the old message is untouched. */ static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) { uint32_t rta_length; size_t message_length, padding_length; struct nlmsghdr *new_hdr; struct rtattr *rta; char *padding; unsigned i; int offset; assert(m); assert(m->hdr); assert(!m->sealed); assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len); assert(!data || data_length); /* get offset of the new attribute */ offset = m->hdr->nlmsg_len; /* get the size of the new rta attribute (with padding at the end) */ rta_length = RTA_LENGTH(data_length); /* get the new message size (with padding at the end) */ message_length = offset + RTA_ALIGN(rta_length); /* realloc to fit the new attribute */ new_hdr = realloc(m->hdr, message_length); if (!new_hdr) return -ENOMEM; m->hdr = new_hdr; /* get pointer to the attribute we are about to add */ rta = (struct rtattr *) ((uint8_t *) m->hdr + offset); /* if we are inside containers, extend them */ for (i = 0; i < m->n_containers; i++) GET_CONTAINER(m, i)->rta_len += message_length - offset; /* fill in the attribute */ rta->rta_type = type; rta->rta_len = rta_length; if (data) /* we don't deal with the case where the user lies about the type * and gives us too little data (so don't do that) */ padding = mempcpy(RTA_DATA(rta), data, data_length); else { /* if no data was passed, make sure we still initialize the padding note that we can have data_length > 0 (used by some containers) */ padding = RTA_DATA(rta); data_length = 0; } /* make sure also the padding at the end of the message is initialized */ padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding; memzero(padding, padding_length); /* update message size */ m->hdr->nlmsg_len = message_length; return offset; }
struct address_flag_info netsnmp_access_other_info_get(int index, int family) { struct { struct nlmsghdr n; struct ifaddrmsg r; char buf[1024]; } req; struct address_flag_info addr; struct rtattr *rta; int status; char buf[16384]; struct nlmsghdr *nlmp; struct ifaddrmsg *rtmp; struct rtattr *rtatp; int rtattrlen; int sd; memset(&addr, 0, sizeof(struct address_flag_info)); sd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if(sd < 0) { snmp_log(LOG_ERR, "could not open netlink socket\n"); return addr; } memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; req.n.nlmsg_type = RTM_GETADDR; req.r.ifa_family = family; rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len)); if(family == AF_INET) rta->rta_len = RTA_LENGTH(4); else rta->rta_len = RTA_LENGTH(16); status = send(sd, &req, req.n.nlmsg_len, 0); if (status < 0) { snmp_log(LOG_ERR, "could not send netlink request\n"); return addr; } status = recv(sd, buf, sizeof(buf), 0); if (status < 0) { snmp_log (LOG_ERR, "could not recieve netlink request\n"); return addr; } if(status == 0) { snmp_log (LOG_ERR, "nothing to read\n"); return addr; } for(nlmp = (struct nlmsghdr *)buf; status > sizeof(*nlmp);) { int len = nlmp->nlmsg_len; int req_len = len - sizeof(*nlmp); if (req_len < 0 || len > status) { snmp_log (LOG_ERR, "invalid netlink message\n"); return addr; } if (!NLMSG_OK(nlmp, status)) { snmp_log (LOG_ERR, "invalid NLMSG message\n"); return addr; } rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp); rtatp = (struct rtattr *)IFA_RTA(rtmp); rtattrlen = IFA_PAYLOAD(nlmp); if(index == rtmp->ifa_index){ for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) { if(rtatp->rta_type == IFA_BROADCAST){ addr.addr = ((struct in_addr *)RTA_DATA(rtatp))->s_addr; addr.bcastflg = 1; } if(rtatp->rta_type == IFA_ANYCAST){ addr.addr = ((struct in_addr *)RTA_DATA(rtatp))->s_addr; addr.anycastflg = 1; } } } status -= NLMSG_ALIGN(len); nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len)); } close(sd); return addr; #endif }
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[RTA_MAX+1]; char abuf[256]; int host_len = -1; __u32 table; SPRINT_BUF(b1); static int hz; if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } host_len = calc_host_len(r); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); table = rtm_get_table(r, tb); if (!filter_nlmsg(n, tb, host_len)) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); if (r->rtm_type != RTN_UNICAST && !filter.type) fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "%s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)) ); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); } else { fprintf(fp, "default "); } if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); } if (r->rtm_tos && filter.tosmask != -1) { SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { fprintf(fp, "via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } if (tb[RTA_OIF] && filter.oifmask != -1) fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); if (!(r->rtm_flags&RTM_F_CLONED)) { if (table != RT_TABLE_MAIN && !filter.tb) fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1) fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1) fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); } if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. */ fprintf(fp, " src %s ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]), abuf, sizeof(abuf))); } if (tb[RTA_PRIORITY]) fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY])); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) fprintf(fp, "onlink "); if (r->rtm_flags & RTNH_F_PERVASIVE) fprintf(fp, "pervasive "); if (r->rtm_flags & RTM_F_NOTIFY) fprintf(fp, "notify "); if (tb[RTA_MARK]) { unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]); if (mark) { if (mark >= 16) fprintf(fp, " mark 0x%x", mark); else fprintf(fp, " mark %u", mark); } } if (tb[RTA_FLOW] && filter.realmmask != ~0U) { __u32 to = rta_getattr_u32(tb[RTA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; fprintf(fp, "realm%s ", from ? "s" : ""); if (from) { fprintf(fp, "%s/", rtnl_rtrealm_n2a(from, b1, sizeof(b1))); } fprintf(fp, "%s ", rtnl_rtrealm_n2a(to, b1, sizeof(b1))); }
int netsnmp_access_ipaddress_extra_prefix_info(int index, u_long *preferedlt, ulong *validlt, char *addr) { struct { struct nlmsghdr nlhdr; struct ifaddrmsg ifaceinfo; char buf[1024]; } req; struct rtattr *rta; int status; char buf[16384]; char tmpaddr[40]; struct nlmsghdr *nlmp; struct ifaddrmsg *rtmp; struct rtattr *rtatp; struct ifa_cacheinfo *cache_info; struct in6_addr *in6p; int rtattrlen; int sd; int reqaddr = 0; sd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if(sd < 0) { snmp_log(LOG_ERR, "could not open netlink socket\n"); return -1; } memset(&req, 0, sizeof(req)); req.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; req.nlhdr.nlmsg_type = RTM_GETADDR; req.ifaceinfo.ifa_family = AF_INET6; rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nlhdr.nlmsg_len)); rta->rta_len = RTA_LENGTH(16); /*For ipv6*/ status = send (sd, &req, req.nlhdr.nlmsg_len, 0); if (status < 0) { snmp_log(LOG_ERR, "could not send netlink request\n"); return -1; } status = recv (sd, buf, sizeof(buf), 0); if (status < 0) { snmp_log (LOG_ERR, "could not recieve netlink request\n"); return -1; } if (status == 0) { snmp_log (LOG_ERR, "nothing to read\n"); return -1; } for (nlmp = (struct nlmsghdr *)buf; status > sizeof(*nlmp); ){ int len = nlmp->nlmsg_len; int req_len = len - sizeof(*nlmp); if (req_len < 0 || len > status) { snmp_log (LOG_ERR, "invalid netlink message\n"); return -1; } if (!NLMSG_OK (nlmp, status)) { snmp_log (LOG_ERR, "invalid NLMSG message\n"); return -1; } rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp); rtatp = (struct rtattr *)IFA_RTA(rtmp); rtattrlen = IFA_PAYLOAD(nlmp); if(index == rtmp->ifa_index) { for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) { if(rtatp->rta_type == IFA_ADDRESS) { in6p = (struct in6_addr *)RTA_DATA(rtatp); sprintf(tmpaddr, "%04x%04x%04x%04x%04x%04x%04x%04x", NIP6(*in6p)); if(!strcmp(tmpaddr ,addr)) reqaddr = 1; } if(rtatp->rta_type == IFA_CACHEINFO) { cache_info = (struct ifa_cacheinfo *)RTA_DATA(rtatp); if(reqaddr) { reqaddr = 0; *validlt = cache_info->ifa_valid; *preferedlt = cache_info->ifa_prefered; } } } } status -= NLMSG_ALIGN(len); nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len)); } close(sd); return 0; }
/* * --------------------------------------------------------------------------- * Aligns the size of Netlink message. * --------------------------------------------------------------------------- */ VOID NlMsgAlignSize(const PNL_MSG_HDR nlh) { nlh->nlmsgLen = NLMSG_ALIGN(nlh->nlmsgLen); return; }
static int nflog_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { const unsigned char *buf; int count = 0; int len; /* ignore interrupt system call error */ do { len = recv(handle->fd, handle->buffer, handle->bufsize, 0); if (handle->break_loop) { handle->break_loop = 0; return -2; } } while ((len == -1) && (errno == EINTR)); if (len < 0) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", errno, pcap_strerror(errno)); return -1; } buf = handle->buffer; while (len >= NLMSG_SPACE(0)) { const struct nlmsghdr *nlh = (const struct nlmsghdr *) buf; u_int32_t msg_len; if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || len < nlh->nlmsg_len) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len); return -1; } if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) { const unsigned char *payload = NULL; struct pcap_pkthdr pkth; if (handle->linktype != DLT_NFLOG) { const struct nfattr *payload_attr = NULL; if (nlh->nlmsg_len < HDR_LENGTH) { snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); return -1; } if (nlh->nlmsg_len > HDR_LENGTH) { struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); while (NFA_OK(attr, attr_len)) { switch (NFA_TYPE(attr)) { case NFULA_PAYLOAD: payload_attr = attr; break; } attr = NFA_NEXT(attr, attr_len); } } if (payload_attr) { payload = NFA_DATA(payload_attr); pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); } } else { payload = NLMSG_DATA(nlh); pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); } if (payload) { /* pkth.caplen = min (payload_len, handle->snapshot); */ gettimeofday(&pkth.ts, NULL); if (handle->fcode.bf_insns == NULL || bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) { handle->md.packets_read++; callback(user, &pkth, payload); count++; } } } msg_len = NLMSG_ALIGN(nlh->nlmsg_len); if (msg_len > len) msg_len = len; len -= msg_len; buf += msg_len; } return count; }