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;
}
Example #2
0
/*
 * ---------------------------------------------------------------------------
 * 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));
}
Example #3
0
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;
}
Example #4
0
File: rtmsg.c Project: t2mune/nield
/*
 * 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;
}
Example #5
0
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));
	}
}
Example #6
0
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;
}
Example #7
0
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);
}
Example #8
0
/*
 * ---------------------------------------------------------------------------
 * 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);
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
0
File: genl.c Project: DINKIN/tuo
/**
 * 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);
}
Example #12
0
File: genl.c Project: DINKIN/tuo
/**
 * 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);
}
Example #13
0
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;
}
Example #14
0
/* 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;
}
Example #15
0
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
}
Example #16
0
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)));
	}
Example #17
0
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;
}
Example #18
0
/*
 * ---------------------------------------------------------------------------
 * Aligns the size of Netlink message.
 * ---------------------------------------------------------------------------
 */
VOID
NlMsgAlignSize(const PNL_MSG_HDR nlh)
{
    nlh->nlmsgLen = NLMSG_ALIGN(nlh->nlmsgLen);
    return;
}
Example #19
0
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;
}