1 /* libnfnetlink.c: generic library for communication with netfilter
2  *
3  * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
4  * (C) 2006-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
5  *
6  * Based on some original ideas from Jay Schulist <jschlst@samba.org>
7  *
8  * Development of this code funded by Astaro AG (http://www.astaro.com)
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published
12  * by the Free Software Foundation.
13  *
14  * 2005-09-14 Pablo Neira Ayuso <pablo@netfilter.org>:
15  * 	Define structure nfnlhdr
16  * 	Added __be64_to_cpu function
17  *	Use NFA_TYPE macro to get the attribute type
18  *
19  * 2006-01-14 Harald Welte <laforge@netfilter.org>:
20  * 	introduce nfnl_subsys_handle
21  *
22  * 2006-01-15 Pablo Neira Ayuso <pablo@netfilter.org>:
23  * 	set missing subsys_id in nfnl_subsys_open
24  * 	set missing nfnlh->local.nl_pid in nfnl_open
25  *
26  * 2006-01-26 Harald Welte <laforge@netfilter.org>:
27  * 	remove bogus nfnlh->local.nl_pid from nfnl_open ;)
28  * 	add 16bit attribute functions
29  *
30  * 2006-07-03 Pablo Neira Ayuso <pablo@netfilter.org>:
31  * 	add iterator API
32  * 	add replacements for nfnl_listen and nfnl_talk
33  * 	fix error handling
34  * 	add assertions
35  * 	add documentation
36  * 	minor cleanups
37  */
38 
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <string.h>
44 #include <time.h>
45 #include <netinet/in.h>
46 #include <assert.h>
47 #include <linux/types.h>
48 #include <sys/socket.h>
49 #include <sys/uio.h>
50 
51 #include <linux/netlink.h>
52 
53 #include <libnfnetlink/libnfnetlink.h>
54 
55 #ifndef NETLINK_ADD_MEMBERSHIP
56 #define NETLINK_ADD_MEMBERSHIP 1
57 #endif
58 
59 #ifndef SOL_NETLINK
60 #define SOL_NETLINK 270
61 #endif
62 
63 
64 #define nfnl_error(format, args...) \
65 	fprintf(stderr, "%s: " format "\n", __FUNCTION__, ## args)
66 
67 #ifdef _NFNL_DEBUG
68 #define nfnl_debug_dump_packet nfnl_dump_packet
69 #else
70 #define nfnl_debug_dump_packet(a, b, ...)
71 #endif
72 
73 struct nfnl_subsys_handle {
74 	struct nfnl_handle 	*nfnlh;
75 	u_int32_t		subscriptions;
76 	u_int8_t		subsys_id;
77 	u_int8_t		cb_count;
78 	struct nfnl_callback 	*cb;	/* array of callbacks */
79 };
80 
81 #define		NFNL_MAX_SUBSYS			16 /* enough for now */
82 
83 #define NFNL_F_SEQTRACK_ENABLED		(1 << 0)
84 
85 struct nfnl_handle {
86 	int			fd;
87 	struct sockaddr_nl	local;
88 	struct sockaddr_nl	peer;
89 	u_int32_t		subscriptions;
90 	u_int32_t		seq;
91 	u_int32_t		dump;
92 	u_int32_t		rcv_buffer_size;	/* for nfnl_catch */
93 	u_int32_t		flags;
94 	struct nlmsghdr 	*last_nlhdr;
95 	struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1];
96 };
97 
nfnl_dump_packet(struct nlmsghdr * nlh,int received_len,char * desc)98 void nfnl_dump_packet(struct nlmsghdr *nlh, int received_len, char *desc)
99 {
100 	void *nlmsg_data = NLMSG_DATA(nlh);
101 	struct nfattr *nfa = NFM_NFA(NLMSG_DATA(nlh));
102 	int len = NFM_PAYLOAD(nlh);
103 
104 	printf("%s called from %s\n", __FUNCTION__, desc);
105 	printf("  nlmsghdr = %p, received_len = %u\n", nlh, received_len);
106 	printf("  NLMSG_DATA(nlh) = %p (+%td bytes)\n", nlmsg_data,
107 	       (nlmsg_data - (void *)nlh));
108 	printf("  NFM_NFA(NLMSG_DATA(nlh)) = %p (+%td bytes)\n",
109 		nfa, ((void *)nfa - (void *)nlh));
110 	printf("  NFM_PAYLOAD(nlh) = %u\n", len);
111 	printf("  nlmsg_type = %u, nlmsg_len = %u, nlmsg_seq = %u "
112 		"nlmsg_flags = 0x%x\n", nlh->nlmsg_type, nlh->nlmsg_len,
113 		nlh->nlmsg_seq, nlh->nlmsg_flags);
114 
115 	while (NFA_OK(nfa, len)) {
116 		printf("    nfa@%p: nfa_type=%u, nfa_len=%u\n",
117 			nfa, NFA_TYPE(nfa), nfa->nfa_len);
118 		nfa = NFA_NEXT(nfa,len);
119 	}
120 }
121 
122 /**
123  * nfnl_fd - returns the descriptor that identifies the socket
124  * @nfnlh: nfnetlink handler
125  *
126  * Use this function if you need to interact with the socket. Common
127  * scenarios are the use of poll()/select() to achieve multiplexation.
128  */
nfnl_fd(struct nfnl_handle * h)129 int nfnl_fd(struct nfnl_handle *h)
130 {
131 	assert(h);
132 	return h->fd;
133 }
134 
135 /**
136  * nfnl_portid - returns the Netlink port ID of this socket
137  * @h: nfnetlink handler
138  */
nfnl_portid(const struct nfnl_handle * h)139 unsigned int nfnl_portid(const struct nfnl_handle *h)
140 {
141 	assert(h);
142 	return h->local.nl_pid;
143 }
144 
recalc_rebind_subscriptions(struct nfnl_handle * nfnlh)145 static int recalc_rebind_subscriptions(struct nfnl_handle *nfnlh)
146 {
147 	int i, err;
148 	u_int32_t new_subscriptions = nfnlh->subscriptions;
149 
150 	for (i = 0; i < NFNL_MAX_SUBSYS; i++)
151 		new_subscriptions |= nfnlh->subsys[i].subscriptions;
152 
153 	nfnlh->local.nl_groups = new_subscriptions;
154 	err = bind(nfnlh->fd, (struct sockaddr *)&nfnlh->local,
155 		   sizeof(nfnlh->local));
156 	if (err == -1)
157 		return -1;
158 
159 	nfnlh->subscriptions = new_subscriptions;
160 
161 	return 0;
162 }
163 
recalc_subscriptions(struct nfnl_handle * nfnlh)164 static void recalc_subscriptions(struct nfnl_handle *nfnlh)
165 {
166 	int i;
167 	u_int32_t new_subscriptions = nfnlh->subscriptions;
168 
169 	for (i = 0; i < NFNL_MAX_SUBSYS; i++)
170 		new_subscriptions |= nfnlh->subsys[i].subscriptions;
171 
172 	nfnlh->local.nl_groups = new_subscriptions;
173 	nfnlh->subscriptions = new_subscriptions;
174 }
175 
176 /**
177  * nfnl_open - open a nfnetlink handler
178  *
179  * This function creates a nfnetlink handler, this is required to establish
180  * a communication between the userspace and the nfnetlink system.
181  *
182  * On success, a valid address that points to a nfnl_handle structure
183  * is returned. On error, NULL is returned and errno is set approapiately.
184  */
nfnl_open(void)185 struct nfnl_handle *nfnl_open(void)
186 {
187 	struct nfnl_handle *nfnlh;
188 	int fd;
189 
190 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
191 	if (fd == -1)
192 		return NULL;
193 	nfnlh = nfnl_open2(fd, true);
194 	if (nfnlh == NULL)
195 		close(fd);
196 	return nfnlh;
197 }
198 
199 /**
200  * nfnl_open2 - open a nfnetlink handler
201  * @fd: passing file descriptor
202  * @bind:  indicate the passing fd needs to be binded or not
203  *
204  * This function creates a nfnetlink handler, this is required to establish
205  * a communication between the userspace and the nfnetlink system.
206  *
207  * On success, a valid address that points to a nfnl_handle structure
208  * is returned. On error, NULL is returned and errno is set approapiately.
209  */
nfnl_open2(int fd,bool bind)210 struct nfnl_handle *nfnl_open2(int fd, bool bind)
211 {
212 	struct nfnl_handle *nfnlh;
213 	unsigned int addr_len;
214 
215 	if (fd < 0)
216 		goto err;
217 
218 	nfnlh = malloc(sizeof(*nfnlh));
219 	if (!nfnlh)
220 		return NULL;
221 
222 	memset(nfnlh, 0, sizeof(*nfnlh));
223 	nfnlh->fd = fd;
224 
225 	nfnlh->local.nl_family = AF_NETLINK;
226 	nfnlh->peer.nl_family = AF_NETLINK;
227 
228 	addr_len = sizeof(nfnlh->local);
229 	getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len);
230 	if (addr_len != sizeof(nfnlh->local)) {
231 		errno = EINVAL;
232 		goto err_free;
233 	}
234 	if (nfnlh->local.nl_family != AF_NETLINK) {
235 		errno = EINVAL;
236 		goto err_free;
237 	}
238 	nfnlh->seq = time(NULL);
239 	nfnlh->rcv_buffer_size = NFNL_BUFFSIZE;
240 
241 	/* don't set pid here, only first socket of process has real pid !!!
242 	 * binding to pid '0' will default */
243 
244 	/* let us do the initial bind */
245 	if (bind) {
246 		if (recalc_rebind_subscriptions(nfnlh) < 0)
247 			goto err_free;
248 	} else {
249 		recalc_subscriptions(nfnlh);
250 	}
251 
252 	/* use getsockname to get the netlink pid that the kernel assigned us */
253 	addr_len = sizeof(nfnlh->local);
254 	getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len);
255 	if (addr_len != sizeof(nfnlh->local)) {
256 		errno = EINVAL;
257 		goto err_free;
258 	}
259 	/* sequence tracking enabled by default */
260 	nfnlh->flags |= NFNL_F_SEQTRACK_ENABLED;
261 
262 	return nfnlh;
263 
264 err_free:
265 	free(nfnlh);
266 err:
267 	return NULL;
268 }
269 
270 /**
271  * nfnl_set_sequence_tracking - set netlink sequence tracking
272  * @h: nfnetlink handler
273  */
nfnl_set_sequence_tracking(struct nfnl_handle * h)274 void nfnl_set_sequence_tracking(struct nfnl_handle *h)
275 {
276 	h->flags |= NFNL_F_SEQTRACK_ENABLED;
277 }
278 
279 /**
280  * nfnl_unset_sequence_tracking - set netlink sequence tracking
281  * @h: nfnetlink handler
282  */
nfnl_unset_sequence_tracking(struct nfnl_handle * h)283 void nfnl_unset_sequence_tracking(struct nfnl_handle *h)
284 {
285 	h->flags &= ~NFNL_F_SEQTRACK_ENABLED;
286 }
287 
288 /**
289  * nfnl_set_rcv_buffer_size - set the size of the receive buffer
290  * @h: libnfnetlink handler
291  * @size: buffer size
292  *
293  * This function sets the size of the receive buffer size, i.e. the size
294  * of the buffer used by nfnl_recv. Default value is 4096 bytes.
295  */
nfnl_set_rcv_buffer_size(struct nfnl_handle * h,unsigned int size)296 void nfnl_set_rcv_buffer_size(struct nfnl_handle *h, unsigned int size)
297 {
298 	h->rcv_buffer_size = size;
299 }
300 
301 /**
302  * nfnl_subsys_open - open a netlink subsystem
303  * @nfnlh: libnfnetlink handle
304  * @subsys_id: which nfnetlink subsystem we are interested in
305  * @cb_count: number of callbacks that are used maximum.
306  * @subscriptions: netlink groups we want to be subscribed to
307  *
308  * This function creates a subsystem handler that contains the set of
309  * callbacks that handle certain types of messages coming from a netfilter
310  * subsystem. Initially the callback set is empty, you can register callbacks
311  * via nfnl_callback_register().
312  *
313  * On error, NULL is returned and errno is set appropiately. On success,
314  * a valid address that points to a nfnl_subsys_handle structure is returned.
315  */
316 struct nfnl_subsys_handle *
nfnl_subsys_open(struct nfnl_handle * nfnlh,u_int8_t subsys_id,u_int8_t cb_count,u_int32_t subscriptions)317 nfnl_subsys_open(struct nfnl_handle *nfnlh, u_int8_t subsys_id,
318 		 u_int8_t cb_count, u_int32_t subscriptions)
319 {
320 	return nfnl_subsys_open2 (nfnlh, subsys_id, cb_count, subscriptions, true);
321 }
322 
323 /**
324  * nfnl_subsys_open2 - open a netlink subsystem
325  * @nfnlh: libnfnetlink handle
326  * @subsys_id: which nfnetlink subsystem we are interested in
327  * @cb_count: number of callbacks that are used maximum.
328  * @subscriptions: netlink groups we want to be subscribed to
329  * @bind: indicate the passing fd needs to be binded or not
330  *
331  * This function creates a subsystem handler that contains the set of
332  * callbacks that handle certain types of messages coming from a netfilter
333  * subsystem. Initially the callback set is empty, you can register callbacks
334  * via nfnl_callback_register().
335  *
336  * On error, NULL is returned and errno is set appropiately. On success,
337  * a valid address that points to a nfnl_subsys_handle structure is returned.
338  */
339 struct nfnl_subsys_handle *
nfnl_subsys_open2(struct nfnl_handle * nfnlh,u_int8_t subsys_id,u_int8_t cb_count,u_int32_t subscriptions,bool bind)340 nfnl_subsys_open2(struct nfnl_handle *nfnlh, u_int8_t subsys_id,
341 		 u_int8_t cb_count, u_int32_t subscriptions, bool bind)
342 {
343 	struct nfnl_subsys_handle *ssh;
344 	int err = 0;
345 
346 	assert(nfnlh);
347 
348 	if (subsys_id > NFNL_MAX_SUBSYS) {
349 		errno = ENOENT;
350 		return NULL;
351 	}
352 
353 	ssh = &nfnlh->subsys[subsys_id];
354 	if (ssh->cb) {
355 		errno = EBUSY;
356 		return NULL;
357 	}
358 
359 	ssh->cb = calloc(cb_count, sizeof(*(ssh->cb)));
360 	if (!ssh->cb)
361 		return NULL;
362 
363 	ssh->nfnlh = nfnlh;
364 	ssh->cb_count = cb_count;
365 	ssh->subscriptions = subscriptions;
366 	ssh->subsys_id = subsys_id;
367 
368 	/* although now we have nfnl_join to subscribe to certain
369 	 * groups, just keep this to ensure compatibility */
370 	if (bind)
371 		err = recalc_rebind_subscriptions(nfnlh);
372 	else
373 		recalc_subscriptions(nfnlh);
374 	if (err < 0) {
375 		free(ssh->cb);
376 		ssh->cb = NULL;
377 		return NULL;
378 	}
379 	return ssh;
380 }
381 
382 /**
383  * nfnl_subsys_close - close a nfnetlink subsys handler
384  * @ssh: nfnetlink subsystem handler
385  *
386  * Release all the callbacks registered in a subsystem handler.
387  */
nfnl_subsys_close(struct nfnl_subsys_handle * ssh)388 void nfnl_subsys_close(struct nfnl_subsys_handle *ssh)
389 {
390 	assert(ssh);
391 
392 	ssh->subscriptions = 0;
393 	ssh->cb_count = 0;
394 	if (ssh->cb) {
395 		free(ssh->cb);
396 		ssh->cb = NULL;
397 	}
398 }
399 
400 /**
401  * nfnl_close - close a nfnetlink handler
402  * @nfnlh: nfnetlink handler
403  *
404  * This function closes the nfnetlink handler. On success, 0 is returned.
405  * On error, -1 is returned and errno is set appropiately.
406  */
nfnl_close(struct nfnl_handle * nfnlh)407 int nfnl_close(struct nfnl_handle *nfnlh)
408 {
409 	int ret;
410 
411 	assert(nfnlh);
412 	ret = close(nfnlh->fd);
413 	if (ret < 0)
414 		return ret;
415 	return nfnl_close2(nfnlh);
416 }
417 
418 /**
419  * nfnl_close2 - close a nfnetlink handler but keep fd
420  * @nfnlh: nfnetlink handler
421  *
422  * This function closes the nfnetlink handler. On success, 0 is returned.
423  * On error, -1 is returned and errno is set appropiately.
424  */
nfnl_close2(struct nfnl_handle * nfnlh)425 int nfnl_close2(struct nfnl_handle *nfnlh)
426 {
427 	int i;
428 
429 	assert(nfnlh);
430 
431 	for (i = 0; i < NFNL_MAX_SUBSYS; i++)
432 		nfnl_subsys_close(&nfnlh->subsys[i]);
433 
434 	free(nfnlh);
435 
436 	return 0;
437 }
438 
439 /**
440  * nfnl_join - join a nfnetlink multicast group
441  * @nfnlh: nfnetlink handler
442  * @group: group we want to join
443  *
444  * This function is used to join a certain multicast group. It must be
445  * called once the nfnetlink handler has been created. If any doubt,
446  * just use it if you have to listen to nfnetlink events.
447  *
448  * On success, 0 is returned. On error, -1 is returned and errno is set
449  * approapiately.
450  */
nfnl_join(const struct nfnl_handle * nfnlh,unsigned int group)451 int nfnl_join(const struct nfnl_handle *nfnlh, unsigned int group)
452 {
453 	assert(nfnlh);
454 	return setsockopt(nfnlh->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
455 			  &group, sizeof(group));
456 }
457 
458 /**
459  * nfnl_send - send a nfnetlink message through netlink socket
460  * @nfnlh: nfnetlink handler
461  * @n: netlink message
462  *
463  * On success, the number of bytes is returned. On error, -1 is returned
464  * and errno is set appropiately.
465  */
nfnl_send(struct nfnl_handle * nfnlh,struct nlmsghdr * n)466 int nfnl_send(struct nfnl_handle *nfnlh, struct nlmsghdr *n)
467 {
468 	assert(nfnlh);
469 	assert(n);
470 
471 	nfnl_debug_dump_packet(n, n->nlmsg_len+sizeof(*n), "nfnl_send");
472 
473 	return sendto(nfnlh->fd, n, n->nlmsg_len, 0,
474 		      (struct sockaddr *)&nfnlh->peer, sizeof(nfnlh->peer));
475 }
476 
nfnl_sendmsg(const struct nfnl_handle * nfnlh,const struct msghdr * msg,unsigned int flags)477 int nfnl_sendmsg(const struct nfnl_handle *nfnlh, const struct msghdr *msg,
478 		 unsigned int flags)
479 {
480 	assert(nfnlh);
481 	assert(msg);
482 
483 	return sendmsg(nfnlh->fd, msg, flags);
484 }
485 
nfnl_sendiov(const struct nfnl_handle * nfnlh,const struct iovec * iov,unsigned int num,unsigned int flags)486 int nfnl_sendiov(const struct nfnl_handle *nfnlh, const struct iovec *iov,
487 		 unsigned int num, unsigned int flags)
488 {
489 	struct msghdr msg;
490 
491 	assert(nfnlh);
492 
493 	msg.msg_name = (struct sockaddr *) &nfnlh->peer;
494 	msg.msg_namelen = sizeof(nfnlh->peer);
495 	msg.msg_iov = (struct iovec *) iov;
496 	msg.msg_iovlen = num;
497 	msg.msg_control = NULL;
498 	msg.msg_controllen = 0;
499 	msg.msg_flags = 0;
500 
501 	return nfnl_sendmsg(nfnlh, &msg, flags);
502 }
503 
504 /**
505  * nfnl_fill_hdr - fill in netlink and nfnetlink header
506  * @nfnlh: nfnetlink handle
507  * @nlh: netlink message to be filled in
508  * @len: length of _payload_ bytes (not including nfgenmsg)
509  * @family: AF_INET / ...
510  * @res_id: resource id
511  * @msg_type: nfnetlink message type (without subsystem)
512  * @msg_flags: netlink message flags
513  *
514  * This function sets up appropiately the nfnetlink header. See that the
515  * pointer to the netlink message passed must point to a memory region of
516  * at least the size of struct nlmsghdr + struct nfgenmsg.
517  */
nfnl_fill_hdr(struct nfnl_subsys_handle * ssh,struct nlmsghdr * nlh,unsigned int len,u_int8_t family,u_int16_t res_id,u_int16_t msg_type,u_int16_t msg_flags)518 void nfnl_fill_hdr(struct nfnl_subsys_handle *ssh,
519 		    struct nlmsghdr *nlh, unsigned int len,
520 		    u_int8_t family,
521 		    u_int16_t res_id,
522 		    u_int16_t msg_type,
523 		    u_int16_t msg_flags)
524 {
525 	assert(ssh);
526 	assert(nlh);
527 
528 	struct nfgenmsg *nfg = (void *)nlh + sizeof(*nlh);
529 
530 	nlh->nlmsg_len = NLMSG_LENGTH(len+sizeof(*nfg));
531 	nlh->nlmsg_type = (ssh->subsys_id<<8)|msg_type;
532 	nlh->nlmsg_flags = msg_flags;
533 	nlh->nlmsg_pid = 0;
534 
535 	if (ssh->nfnlh->flags & NFNL_F_SEQTRACK_ENABLED) {
536 		nlh->nlmsg_seq = ++ssh->nfnlh->seq;
537 		/* kernel uses sequence number zero for events */
538 		if (!ssh->nfnlh->seq)
539 			nlh->nlmsg_seq = ssh->nfnlh->seq = time(NULL);
540 	} else {
541 		/* unset sequence number, ignore it */
542 		nlh->nlmsg_seq = 0;
543 	}
544 
545 	nfg->nfgen_family = family;
546 	nfg->version = NFNETLINK_V0;
547 	nfg->res_id = htons(res_id);
548 }
549 
550 struct nfattr *
nfnl_parse_hdr(const struct nfnl_handle * nfnlh,const struct nlmsghdr * nlh,struct nfgenmsg ** genmsg)551 nfnl_parse_hdr(const struct nfnl_handle *nfnlh,
552 		const struct nlmsghdr *nlh,
553 		struct nfgenmsg **genmsg)
554 {
555 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg)))
556 		return NULL;
557 
558 	if (nlh->nlmsg_len == NLMSG_LENGTH(sizeof(struct nfgenmsg))) {
559 		if (genmsg)
560 			*genmsg = (void *)nlh + sizeof(*nlh);
561 		return NULL;
562 	}
563 
564 	if (genmsg)
565 		*genmsg = (void *)nlh + sizeof(*nlh);
566 
567 	return (void *)nlh + NLMSG_LENGTH(sizeof(struct nfgenmsg));
568 }
569 
570 /**
571  * nfnl_recv - receive data from a nfnetlink subsystem
572  * @h: nfnetlink handler
573  * @buf: buffer where the data will be stored
574  * @len: size of the buffer
575  *
576  * This function doesn't perform any sanity checking. So do no expect
577  * that the data is well-formed. Such checkings are done by the parsing
578  * functions.
579  *
580  * On success, 0 is returned. On error, -1 is returned and errno is set
581  * appropiately.
582  *
583  * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
584  * that case is possible that the information requested is incomplete.
585  */
586 ssize_t
nfnl_recv(const struct nfnl_handle * h,unsigned char * buf,size_t len)587 nfnl_recv(const struct nfnl_handle *h, unsigned char *buf, size_t len)
588 {
589 	socklen_t addrlen;
590 	int status;
591 	struct sockaddr_nl peer;
592 
593 	assert(h);
594 	assert(buf);
595 	assert(len > 0);
596 
597 	if (len < sizeof(struct nlmsgerr)
598 	    || len < sizeof(struct nlmsghdr)) {
599 	    	errno = EBADMSG;
600 		return -1;
601 	}
602 
603 	addrlen = sizeof(h->peer);
604 	status = recvfrom(h->fd, buf, len, 0, (struct sockaddr *)&peer,
605 			&addrlen);
606 	if (status <= 0)
607 		return status;
608 
609 	if (addrlen != sizeof(peer)) {
610 		errno = EINVAL;
611 		return -1;
612 	}
613 
614 	if (peer.nl_pid != 0) {
615 		errno = ENOMSG;
616 		return -1;
617 	}
618 
619 	return status;
620 }
621 /**
622  * nfnl_listen: listen for one or more netlink messages
623  * @nfnhl: libnfnetlink handle
624  * @handler: callback function to be called for every netlink message
625  *          - the callback handler should normally return 0
626  *          - but may return a negative error code which will cause
627  *            nfnl_listen to return immediately with the same error code
628  *          - or return a postivie error code which will cause
629  *            nfnl_listen to return after it has finished processing all
630  *            the netlink messages in the current packet
631  *          Thus a positive error code will terminate nfnl_listen "soon"
632  *          without any loss of data, a negative error code will terminate
633  *          nfnl_listen "very soon" and throw away data already read from
634  *          the netlink socket.
635  * @jarg: opaque argument passed on to callback
636  *
637  * This function is used to receive and process messages coming from an open
638  * nfnetlink handler like events or information request via nfnl_send().
639  *
640  * On error, -1 is returned, unfortunately errno is not always set
641  * appropiately. For that reason, the use of this function is DEPRECATED.
642  * Please, use nfnl_receive_process() instead.
643  */
nfnl_listen(struct nfnl_handle * nfnlh,int (* handler)(struct sockaddr_nl *,struct nlmsghdr * n,void *),void * jarg)644 int nfnl_listen(struct nfnl_handle *nfnlh,
645 		int (*handler)(struct sockaddr_nl *, struct nlmsghdr *n,
646 			       void *), void *jarg)
647 {
648 	struct sockaddr_nl nladdr;
649 	char buf[NFNL_BUFFSIZE] __attribute__ ((aligned));
650 	struct iovec iov;
651 	int remain;
652 	struct nlmsghdr *h;
653 	struct nlmsgerr *msgerr;
654 	int quit=0;
655 
656 	struct msghdr msg = {
657 		.msg_name    = &nladdr,
658 		.msg_namelen = sizeof(nladdr),
659 		.msg_iov     = &iov,
660 		.msg_iovlen  = 1,
661 	};
662 
663 	memset(&nladdr, 0, sizeof(nladdr));
664 	nladdr.nl_family = AF_NETLINK;
665 	iov.iov_base = buf;
666 	iov.iov_len = sizeof(buf);
667 
668 	while (! quit) {
669 		remain = recvmsg(nfnlh->fd, &msg, 0);
670 		if (remain < 0) {
671 			if (errno == EINTR)
672 				continue;
673 			/* Bad file descriptor */
674 			else if (errno == EBADF)
675 				break;
676 			else if (errno == EAGAIN)
677 				break;
678 			nfnl_error("recvmsg overrun: %s", strerror(errno));
679 			continue;
680 		}
681 		if (remain == 0) {
682 			nfnl_error("EOF on netlink");
683 			return -1;
684 		}
685 		if (msg.msg_namelen != sizeof(nladdr)) {
686 			nfnl_error("Bad sender address len (%d)",
687 				   msg.msg_namelen);
688 			return -1;
689 		}
690 
691 		for (h = (struct nlmsghdr *)buf; remain >= sizeof(*h);) {
692 			int err;
693 			int len = h->nlmsg_len;
694 			int l = len - sizeof(*h);
695 
696 			if (l < 0 || len > remain) {
697 				if (msg.msg_flags & MSG_TRUNC) {
698 					nfnl_error("MSG_TRUNC");
699 					return -1;
700 				}
701 				nfnl_error("Malformed msg (len=%d)", len);
702 				return -1;
703 			}
704 
705 			/* end of messages reached, let's return */
706 			if (h->nlmsg_type == NLMSG_DONE)
707 				return 0;
708 
709 			/* Break the loop if success is explicitely
710 			 * reported via NLM_F_ACK flag set */
711 			if (h->nlmsg_type == NLMSG_ERROR) {
712 				msgerr = NLMSG_DATA(h);
713 				return msgerr->error;
714 			}
715 
716 			err = handler(&nladdr, h, jarg);
717 			if (err < 0)
718 				return err;
719 			quit |= err;
720 
721 			/* FIXME: why not _NEXT macros, etc.? */
722 			//h = NLMSG_NEXT(h, remain);
723 			remain -= NLMSG_ALIGN(len);
724 			h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
725 		}
726 		if (msg.msg_flags & MSG_TRUNC) {
727 			nfnl_error("MSG_TRUNC");
728 			continue;
729 		}
730 		if (remain) {
731 			nfnl_error("remnant size %d", remain);
732 			return -1;
733 		}
734 	}
735 
736 	return quit;
737 }
738 
739 /**
740  * nfnl_talk - send a request and then receive and process messages returned
741  * @nfnlh: nfnetelink handler
742  * @n: netlink message that contains the request
743  * @peer: peer PID
744  * @groups: netlink groups
745  * @junk: callback called if out-of-sequence messages were received
746  * @jarg: data for the junk callback
747  *
748  * This function is used to request an action that does not returns any
749  * information. On error, a negative value is returned, errno could be
750  * set appropiately. For that reason, the use of this function is DEPRECATED.
751  * Please, use nfnl_query() instead.
752  */
nfnl_talk(struct nfnl_handle * nfnlh,struct nlmsghdr * n,pid_t peer,unsigned groups,struct nlmsghdr * answer,int (* junk)(struct sockaddr_nl *,struct nlmsghdr * n,void *),void * jarg)753 int nfnl_talk(struct nfnl_handle *nfnlh, struct nlmsghdr *n, pid_t peer,
754 	      unsigned groups, struct nlmsghdr *answer,
755 	      int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
756 	      void *jarg)
757 {
758 	char buf[NFNL_BUFFSIZE] __attribute__ ((aligned));
759 	struct sockaddr_nl nladdr;
760 	struct nlmsghdr *h;
761 	unsigned int seq;
762 	int status;
763 	struct iovec iov = {
764 		n, n->nlmsg_len
765 	};
766 	struct msghdr msg = {
767 		.msg_name    = &nladdr,
768 		.msg_namelen = sizeof(nladdr),
769 		.msg_iov     = &iov,
770 		.msg_iovlen  = 1,
771 	};
772 
773 	memset(&nladdr, 0, sizeof(nladdr));
774 	nladdr.nl_family = AF_NETLINK;
775 	nladdr.nl_pid = peer;
776 	nladdr.nl_groups = groups;
777 
778 	n->nlmsg_seq = seq = ++nfnlh->seq;
779 	/* FIXME: why ? */
780 	if (!answer)
781 		n->nlmsg_flags |= NLM_F_ACK;
782 
783 	status = sendmsg(nfnlh->fd, &msg, 0);
784 	if (status < 0) {
785 		nfnl_error("sendmsg(netlink) %s", strerror(errno));
786 		return -1;
787 	}
788 	iov.iov_base = buf;
789 	iov.iov_len = sizeof(buf);
790 
791 	while (1) {
792 		status = recvmsg(nfnlh->fd, &msg, 0);
793 		if (status < 0) {
794 			if (errno == EINTR)
795 				continue;
796 			nfnl_error("recvmsg over-run");
797 			continue;
798 		}
799 		if (status == 0) {
800 			nfnl_error("EOF on netlink");
801 			return -1;
802 		}
803 		if (msg.msg_namelen != sizeof(nladdr)) {
804 			nfnl_error("Bad sender address len %d",
805 				   msg.msg_namelen);
806 			return -1;
807 		}
808 
809 		for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
810 			int len = h->nlmsg_len;
811 			int l = len - sizeof(*h);
812 			int err;
813 
814 			if (l < 0 || len > status) {
815 				if (msg.msg_flags & MSG_TRUNC) {
816 					nfnl_error("Truncated message\n");
817 					return -1;
818 				}
819 				nfnl_error("Malformed message: len=%d\n", len);
820 				return -1; /* FIXME: libnetlink exits here */
821 			}
822 
823 			if (h->nlmsg_pid != nfnlh->local.nl_pid ||
824 			    h->nlmsg_seq != seq) {
825 				if (junk) {
826 					err = junk(&nladdr, h, jarg);
827 					if (err < 0)
828 						return err;
829 				}
830 				goto cont;
831 			}
832 
833 			if (h->nlmsg_type == NLMSG_ERROR) {
834 				struct nlmsgerr *err = NLMSG_DATA(h);
835 				if (l < sizeof(struct nlmsgerr))
836 					nfnl_error("ERROR truncated\n");
837 				else {
838 					errno = -err->error;
839 					if (errno == 0) {
840 						if (answer)
841 							memcpy(answer, h, h->nlmsg_len);
842 						return 0;
843 					}
844 					perror("NFNETLINK answers");
845 				}
846 				return err->error;
847 			}
848 			if (answer) {
849 				memcpy(answer, h, h->nlmsg_len);
850 				return 0;
851 			}
852 
853 			nfnl_error("Unexpected reply!\n");
854 cont:
855 			status -= NLMSG_ALIGN(len);
856 			h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
857 		}
858 		if (msg.msg_flags & MSG_TRUNC) {
859 			nfnl_error("Messages truncated\n");
860 			continue;
861 		}
862 		if (status)
863 			nfnl_error("Remnant of size %d\n", status);
864 	}
865 }
866 
867 /**
868  * nfnl_addattr_l - Add variable length attribute to nlmsghdr
869  * @n: netlink message header to which attribute is to be added
870  * @maxlen: maximum length of netlink message header
871  * @type: type of new attribute
872  * @data: content of new attribute
873  * @len: attribute length
874  */
nfnl_addattr_l(struct nlmsghdr * n,int maxlen,int type,const void * data,int alen)875 int nfnl_addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
876 		   int alen)
877 {
878 	int len = NFA_LENGTH(alen);
879 	struct nfattr *nfa;
880 
881 	assert(n);
882 	assert(maxlen > 0);
883 	assert(type >= 0);
884 
885 	if ((NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
886 		errno = ENOSPC;
887 		return -1;
888 	}
889 
890 	nfa = NLMSG_TAIL(n);
891 	nfa->nfa_type = type;
892 	nfa->nfa_len = len;
893 	memcpy(NFA_DATA(nfa), data, alen);
894 	n->nlmsg_len = (NLMSG_ALIGN(n->nlmsg_len) + NFA_ALIGN(len));
895 	return 0;
896 }
897 
898 /**
899  * nfnl_nfa_addattr_l - Add variable length attribute to struct nfattr
900  *
901  * @nfa: struct nfattr
902  * @maxlen: maximal length of nfattr buffer
903  * @type: type for new attribute
904  * @data: content of new attribute
905  * @alen: length of new attribute
906  *
907  */
nfnl_nfa_addattr_l(struct nfattr * nfa,int maxlen,int type,const void * data,int alen)908 int nfnl_nfa_addattr_l(struct nfattr *nfa, int maxlen, int type,
909 		       const void *data, int alen)
910 {
911 	struct nfattr *subnfa;
912 	int len = NFA_LENGTH(alen);
913 
914 	assert(nfa);
915 	assert(maxlen > 0);
916 	assert(type >= 0);
917 
918 	if (NFA_ALIGN(nfa->nfa_len) + len > maxlen) {
919 		errno = ENOSPC;
920 		return -1;
921 	}
922 
923 	subnfa = (struct nfattr *)(((char *)nfa) + NFA_ALIGN(nfa->nfa_len));
924 	subnfa->nfa_type = type;
925 	subnfa->nfa_len = len;
926 	memcpy(NFA_DATA(subnfa), data, alen);
927 	nfa->nfa_len = NFA_ALIGN(nfa->nfa_len) + len;
928 
929 	return 0;
930 }
931 
932 /**
933  * nfnl_addattr8 - Add u_int8_t attribute to nlmsghdr
934  *
935  * @n: netlink message header to which attribute is to be added
936  * @maxlen: maximum length of netlink message header
937  * @type: type of new attribute
938  * @data: content of new attribute
939  */
nfnl_addattr8(struct nlmsghdr * n,int maxlen,int type,u_int8_t data)940 int nfnl_addattr8(struct nlmsghdr *n, int maxlen, int type, u_int8_t data)
941 {
942 	assert(n);
943 	assert(maxlen > 0);
944 	assert(type >= 0);
945 
946 	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
947 }
948 
949 /**
950  * nfnl_nfa_addattr16 - Add u_int16_t attribute to struct nfattr
951  *
952  * @nfa: struct nfattr
953  * @maxlen: maximal length of nfattr buffer
954  * @type: type for new attribute
955  * @data: content of new attribute
956  *
957  */
nfnl_nfa_addattr16(struct nfattr * nfa,int maxlen,int type,u_int16_t data)958 int nfnl_nfa_addattr16(struct nfattr *nfa, int maxlen, int type,
959 		       u_int16_t data)
960 {
961 	assert(nfa);
962 	assert(maxlen > 0);
963 	assert(type >= 0);
964 
965 	return nfnl_nfa_addattr_l(nfa, maxlen, type, &data, sizeof(data));
966 }
967 
968 /**
969  * nfnl_addattr16 - Add u_int16_t attribute to nlmsghdr
970  *
971  * @n: netlink message header to which attribute is to be added
972  * @maxlen: maximum length of netlink message header
973  * @type: type of new attribute
974  * @data: content of new attribute
975  *
976  */
nfnl_addattr16(struct nlmsghdr * n,int maxlen,int type,u_int16_t data)977 int nfnl_addattr16(struct nlmsghdr *n, int maxlen, int type,
978 		   u_int16_t data)
979 {
980 	assert(n);
981 	assert(maxlen > 0);
982 	assert(type >= 0);
983 
984 	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
985 }
986 
987 /**
988  * nfnl_nfa_addattr32 - Add u_int32_t attribute to struct nfattr
989  *
990  * @nfa: struct nfattr
991  * @maxlen: maximal length of nfattr buffer
992  * @type: type for new attribute
993  * @data: content of new attribute
994  *
995  */
nfnl_nfa_addattr32(struct nfattr * nfa,int maxlen,int type,u_int32_t data)996 int nfnl_nfa_addattr32(struct nfattr *nfa, int maxlen, int type,
997 		       u_int32_t data)
998 {
999 	assert(nfa);
1000 	assert(maxlen > 0);
1001 	assert(type >= 0);
1002 
1003 	return nfnl_nfa_addattr_l(nfa, maxlen, type, &data, sizeof(data));
1004 }
1005 
1006 /**
1007  * nfnl_addattr32 - Add u_int32_t attribute to nlmsghdr
1008  *
1009  * @n: netlink message header to which attribute is to be added
1010  * @maxlen: maximum length of netlink message header
1011  * @type: type of new attribute
1012  * @data: content of new attribute
1013  *
1014  */
nfnl_addattr32(struct nlmsghdr * n,int maxlen,int type,u_int32_t data)1015 int nfnl_addattr32(struct nlmsghdr *n, int maxlen, int type,
1016 		   u_int32_t data)
1017 {
1018 	assert(n);
1019 	assert(maxlen > 0);
1020 	assert(type >= 0);
1021 
1022 	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
1023 }
1024 
1025 /**
1026  * nfnl_parse_attr - Parse a list of nfattrs into a pointer array
1027  *
1028  * @tb: pointer array, will be filled in (output)
1029  * @max: size of pointer array
1030  * @nfa: pointer to list of nfattrs
1031  * @len: length of 'nfa'
1032  *
1033  * The returned value is equal to the number of remaining bytes of the netlink
1034  * message that cannot be parsed.
1035  */
nfnl_parse_attr(struct nfattr * tb[],int max,struct nfattr * nfa,int len)1036 int nfnl_parse_attr(struct nfattr *tb[], int max, struct nfattr *nfa, int len)
1037 {
1038 	assert(tb);
1039 	assert(max > 0);
1040 	assert(nfa);
1041 
1042 	memset(tb, 0, sizeof(struct nfattr *) * max);
1043 
1044 	while (NFA_OK(nfa, len)) {
1045 		if (NFA_TYPE(nfa) <= max)
1046 			tb[NFA_TYPE(nfa)-1] = nfa;
1047                 nfa = NFA_NEXT(nfa,len);
1048 	}
1049 
1050 	return len;
1051 }
1052 
1053 /**
1054  * nfnl_build_nfa_iovec - Build two iovec's from tag, length and value
1055  *
1056  * @iov: pointer to array of two 'struct iovec' (caller-allocated)
1057  * @nfa: pointer to 'struct nfattr' (caller-allocated)
1058  * @type: type (tag) of attribute
1059  * @len: length of value
1060  * @val: pointer to buffer containing 'value'
1061  *
1062  */
nfnl_build_nfa_iovec(struct iovec * iov,struct nfattr * nfa,u_int16_t type,u_int32_t len,unsigned char * val)1063 void nfnl_build_nfa_iovec(struct iovec *iov, struct nfattr *nfa,
1064 			  u_int16_t type, u_int32_t len, unsigned char *val)
1065 {
1066 	assert(iov);
1067 	assert(nfa);
1068 
1069         /* Set the attribut values */
1070         nfa->nfa_len = sizeof(struct nfattr) + len;
1071         nfa->nfa_type = type;
1072 
1073 	iov[0].iov_base = nfa;
1074 	iov[0].iov_len = sizeof(*nfa);
1075 	iov[1].iov_base = val;
1076 	iov[1].iov_len = NFA_ALIGN(len);
1077 }
1078 
1079 #ifndef SO_RCVBUFFORCE
1080 #define SO_RCVBUFFORCE	(33)
1081 #endif
1082 
1083 /**
1084  * nfnl_rcvbufsiz - set the socket buffer size
1085  * @h: nfnetlink handler
1086  * @size: size of the buffer we want to set
1087  *
1088  * This function sets the new size of the socket buffer. Use this setting
1089  * to increase the socket buffer size if your system is reporting ENOBUFS
1090  * errors.
1091  *
1092  * This function returns the new size of the socket buffer.
1093  */
nfnl_rcvbufsiz(const struct nfnl_handle * h,unsigned int size)1094 unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h, unsigned int size)
1095 {
1096 	int status;
1097 	socklen_t socklen = sizeof(size);
1098 	unsigned int read_size = 0;
1099 
1100 	assert(h);
1101 
1102 	/* first we try the FORCE option, which is introduced in kernel
1103 	 * 2.6.14 to give "root" the ability to override the system wide
1104 	 * maximum */
1105 	status = setsockopt(h->fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, socklen);
1106 	if (status < 0) {
1107 		/* if this didn't work, we try at least to get the system
1108 		 * wide maximum (or whatever the user requested) */
1109 		setsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &size, socklen);
1110 	}
1111 	getsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &read_size, &socklen);
1112 
1113 	return read_size;
1114 }
1115 
1116 /**
1117  * nfnl_get_msg_first - get the first message of a multipart netlink message
1118  * @h: nfnetlink handle
1119  * @buf: data received that we want to process
1120  * @len: size of the data received
1121  *
1122  * This function returns a pointer to the first netlink message contained
1123  * in the chunk of data received from certain nfnetlink subsystem.
1124  *
1125  * On success, a valid address that points to the netlink message is returned.
1126  * On error, NULL is returned.
1127  */
nfnl_get_msg_first(struct nfnl_handle * h,const unsigned char * buf,size_t len)1128 struct nlmsghdr *nfnl_get_msg_first(struct nfnl_handle *h,
1129 				    const unsigned char *buf,
1130 				    size_t len)
1131 {
1132 	struct nlmsghdr *nlh;
1133 
1134 	assert(h);
1135 	assert(buf);
1136 	assert(len > 0);
1137 
1138 	/* first message in buffer */
1139 	nlh = (struct nlmsghdr *)buf;
1140 	if (!NLMSG_OK(nlh, len))
1141 		return NULL;
1142 	h->last_nlhdr = nlh;
1143 
1144 	return nlh;
1145 }
1146 
nfnl_get_msg_next(struct nfnl_handle * h,const unsigned char * buf,size_t len)1147 struct nlmsghdr *nfnl_get_msg_next(struct nfnl_handle *h,
1148 				   const unsigned char *buf,
1149 				   size_t len)
1150 {
1151 	struct nlmsghdr *nlh;
1152 	size_t remain_len;
1153 
1154 	assert(h);
1155 	assert(buf);
1156 	assert(len > 0);
1157 
1158 	/* if last header in handle not inside this buffer,
1159 	 * drop reference to last header */
1160 	if (!h->last_nlhdr ||
1161 	    (unsigned char *)h->last_nlhdr >= (buf + len)  ||
1162 	    (unsigned char *)h->last_nlhdr < buf) {
1163 		h->last_nlhdr = NULL;
1164 		return NULL;
1165 	}
1166 
1167 	/* n-th part of multipart message */
1168 	if (h->last_nlhdr->nlmsg_type == NLMSG_DONE ||
1169 	    h->last_nlhdr->nlmsg_flags & NLM_F_MULTI) {
1170 		/* if last part in multipart message or no
1171 		 * multipart message at all, return */
1172 		h->last_nlhdr = NULL;
1173 		return NULL;
1174 	}
1175 
1176 	remain_len = (len - ((unsigned char *)h->last_nlhdr - buf));
1177 	nlh = NLMSG_NEXT(h->last_nlhdr, remain_len);
1178 
1179 	if (!NLMSG_OK(nlh, remain_len)) {
1180 		h->last_nlhdr = NULL;
1181 		return NULL;
1182 	}
1183 
1184 	h->last_nlhdr = nlh;
1185 
1186 	return nlh;
1187 }
1188 
1189 /**
1190  * nfnl_callback_register - register a callback for a certain message type
1191  * @ssh: nfnetlink subsys handler
1192  * @type: subsys call
1193  * @cb: nfnetlink callback to be registered
1194  *
1195  * On success, 0 is returned. On error, -1 is returned and errno is set
1196  * appropiately.
1197  */
nfnl_callback_register(struct nfnl_subsys_handle * ssh,u_int8_t type,struct nfnl_callback * cb)1198 int nfnl_callback_register(struct nfnl_subsys_handle *ssh,
1199 			   u_int8_t type, struct nfnl_callback *cb)
1200 {
1201 	assert(ssh);
1202 	assert(cb);
1203 
1204 	if (type >= ssh->cb_count) {
1205 		errno = EINVAL;
1206 		return -1;
1207 	}
1208 
1209 	memcpy(&ssh->cb[type], cb, sizeof(*cb));
1210 
1211 	return 0;
1212 }
1213 
1214 /**
1215  * nfnl_callback_unregister - unregister a certain callback
1216  * @ssh: nfnetlink subsys handler
1217  * @type: subsys call
1218  *
1219  * On sucess, 0 is returned. On error, -1 is returned and errno is
1220  * set appropiately.
1221  */
nfnl_callback_unregister(struct nfnl_subsys_handle * ssh,u_int8_t type)1222 int nfnl_callback_unregister(struct nfnl_subsys_handle *ssh, u_int8_t type)
1223 {
1224 	assert(ssh);
1225 
1226 	if (type >= ssh->cb_count) {
1227 		errno = EINVAL;
1228 		return -1;
1229 	}
1230 
1231 	ssh->cb[type].call = NULL;
1232 
1233 	return 0;
1234 }
1235 
nfnl_check_attributes(const struct nfnl_handle * h,const struct nlmsghdr * nlh,struct nfattr * nfa[])1236 int nfnl_check_attributes(const struct nfnl_handle *h,
1237 			 const struct nlmsghdr *nlh,
1238 			 struct nfattr *nfa[])
1239 {
1240 	assert(h);
1241 	assert(nlh);
1242 	assert(nfa);
1243 
1244 	int min_len;
1245 	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
1246 	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
1247 	const struct nfnl_subsys_handle *ssh;
1248 	struct nfnl_callback *cb;
1249 
1250 	if (subsys_id > NFNL_MAX_SUBSYS)
1251 		return -EINVAL;
1252 
1253 	ssh = &h->subsys[subsys_id];
1254  	cb = &ssh->cb[type];
1255 
1256 #if 1
1257 	/* checks need to be enabled as soon as this is called from
1258 	 * somebody else than __nfnl_handle_msg */
1259 	if (type >= ssh->cb_count)
1260 		return -EINVAL;
1261 
1262 	min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
1263 	if (nlh->nlmsg_len < min_len)
1264 		return -EINVAL;
1265 #endif
1266 	memset(nfa, 0, sizeof(struct nfattr *) * cb->attr_count);
1267 
1268 	if (nlh->nlmsg_len > min_len) {
1269 		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
1270 		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
1271 
1272 		while (NFA_OK(attr, attrlen)) {
1273 			unsigned int flavor = NFA_TYPE(attr);
1274 			if (flavor) {
1275 				if (flavor > cb->attr_count) {
1276 					/* we have received an attribute from
1277 					 * the kernel which we don't understand
1278 					 * yet. We have to silently ignore this
1279 					 * for the sake of future compatibility */
1280 					attr = NFA_NEXT(attr, attrlen);
1281 					continue;
1282 				}
1283 				nfa[flavor - 1] = attr;
1284 			}
1285 			attr = NFA_NEXT(attr, attrlen);
1286 		}
1287 	}
1288 
1289 	return 0;
1290 }
1291 
__nfnl_handle_msg(struct nfnl_handle * h,struct nlmsghdr * nlh,int len)1292 static int __nfnl_handle_msg(struct nfnl_handle *h, struct nlmsghdr *nlh,
1293 			     int len)
1294 {
1295 	struct nfnl_subsys_handle *ssh;
1296 	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
1297 	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
1298 	int err = 0;
1299 
1300 	if (subsys_id > NFNL_MAX_SUBSYS)
1301 		return -1;
1302 
1303 	ssh = &h->subsys[subsys_id];
1304 
1305 	if (nlh->nlmsg_len < NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg))))
1306 		return -1;
1307 
1308 	if (type >= ssh->cb_count)
1309 		return -1;
1310 
1311 	if (ssh->cb[type].attr_count) {
1312 		struct nfattr *nfa[ssh->cb[type].attr_count];
1313 
1314 		err = nfnl_check_attributes(h, nlh, nfa);
1315 		if (err < 0)
1316 			return err;
1317 		if (ssh->cb[type].call)
1318 			return ssh->cb[type].call(nlh, nfa, ssh->cb[type].data);
1319 	}
1320 	return 0;
1321 }
1322 
nfnl_handle_packet(struct nfnl_handle * h,char * buf,int len)1323 int nfnl_handle_packet(struct nfnl_handle *h, char *buf, int len)
1324 {
1325 
1326 	while (len >= NLMSG_SPACE(0)) {
1327 		u_int32_t rlen;
1328 		struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
1329 
1330 		if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
1331 		    || len < nlh->nlmsg_len)
1332 			return -1;
1333 
1334 		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1335 		if (rlen > len)
1336 			rlen = len;
1337 
1338 		if (__nfnl_handle_msg(h, nlh, rlen) < 0)
1339 			return -1;
1340 
1341 		len -= rlen;
1342 		buf += rlen;
1343 	}
1344 	return 0;
1345 }
1346 
nfnl_is_error(struct nfnl_handle * h,struct nlmsghdr * nlh)1347 static int nfnl_is_error(struct nfnl_handle *h, struct nlmsghdr *nlh)
1348 {
1349 	/* This message is an ACK or a DONE */
1350 	if (nlh->nlmsg_type == NLMSG_ERROR ||
1351 	    (nlh->nlmsg_type == NLMSG_DONE &&
1352 	     nlh->nlmsg_flags & NLM_F_MULTI)) {
1353 		if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) {
1354 			errno = EBADMSG;
1355 			return 1;
1356 		}
1357 		errno = -(*((int *)NLMSG_DATA(nlh)));
1358 		return 1;
1359 	}
1360 	return 0;
1361 }
1362 
1363 /* On error, -1 is returned and errno is set appropiately. On success,
1364  * 0 is returned if there is no more data to process, >0 if there is
1365  * more data to process */
nfnl_step(struct nfnl_handle * h,struct nlmsghdr * nlh)1366 static int nfnl_step(struct nfnl_handle *h, struct nlmsghdr *nlh)
1367 {
1368 	struct nfnl_subsys_handle *ssh;
1369 	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
1370 	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
1371 
1372 	/* Is this an error message? */
1373 	if (nfnl_is_error(h, nlh)) {
1374 		/* This is an ACK */
1375 		if (errno == 0)
1376 			return 0;
1377 		/* This an error message */
1378 		return -1;
1379 	}
1380 
1381 	/* nfnetlink sanity checks: check for nfgenmsg size */
1382 	if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) {
1383 		errno = ENOSPC;
1384 		return -1;
1385 	}
1386 
1387 	if (subsys_id > NFNL_MAX_SUBSYS) {
1388 		errno = ENOENT;
1389 		return -1;
1390 	}
1391 
1392 	ssh = &h->subsys[subsys_id];
1393 	if (!ssh) {
1394 		errno = ENOENT;
1395 		return -1;
1396 	}
1397 
1398 	if (type >= ssh->cb_count) {
1399 		errno = ENOENT;
1400 		return -1;
1401 	}
1402 
1403 	if (ssh->cb[type].attr_count) {
1404 		int err;
1405 		struct nfattr *tb[ssh->cb[type].attr_count];
1406 		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
1407 		int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
1408 		int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
1409 
1410 		err = nfnl_parse_attr(tb, ssh->cb[type].attr_count, attr, len);
1411 		if (err == -1)
1412 			return -1;
1413 
1414 		if (ssh->cb[type].call) {
1415 			/*
1416 			 * On error, the callback returns NFNL_CB_FAILURE and
1417 			 * errno must be explicitely set. On success,
1418 			 * NFNL_CB_STOP is returned and we're done, otherwise
1419 			 * NFNL_CB_CONTINUE means that we want to continue
1420 			 * data processing.
1421 			 */
1422 			return ssh->cb[type].call(nlh,
1423 						  tb,
1424 						  ssh->cb[type].data);
1425 		}
1426 	}
1427 	/* no callback set, continue data processing */
1428 	return 1;
1429 }
1430 
1431 /**
1432  * nfnl_process - process data coming from a nfnetlink system
1433  * @h: nfnetlink handler
1434  * @buf: buffer that contains the netlink message
1435  * @len: size of the data contained in the buffer (not the buffer size)
1436  *
1437  * This function processes all the nfnetlink messages contained inside a
1438  * buffer. It performs the appropiate sanity checks and passes the message
1439  * to a certain handler that is registered via register_callback().
1440  *
1441  * On success, NFNL_CB_STOP is returned if the data processing has finished.
1442  * If a value NFNL_CB_CONTINUE is returned, then there is more data to
1443  * process. On error, NFNL_CB_CONTINUE is returned and errno is set to the
1444  * appropiate value.
1445  *
1446  * In case that the callback returns NFNL_CB_FAILURE, errno may be set by
1447  * the library client. If your callback decides not to process data anymore
1448  * for any reason, then it must return NFNL_CB_STOP. Otherwise, if the
1449  * callback continues the processing NFNL_CB_CONTINUE is returned.
1450  */
nfnl_process(struct nfnl_handle * h,const unsigned char * buf,size_t len)1451 int nfnl_process(struct nfnl_handle *h, const unsigned char *buf, size_t len)
1452 {
1453 	int ret = 0;
1454 	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
1455 
1456 	assert(h);
1457 	assert(buf);
1458 	assert(len > 0);
1459 
1460 	/* check for out of sequence message */
1461 	if (nlh->nlmsg_seq && nlh->nlmsg_seq != h->seq) {
1462 		errno = EILSEQ;
1463 		return -1;
1464 	}
1465 	while (len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) {
1466 
1467 		ret = nfnl_step(h, nlh);
1468 		if (ret <= NFNL_CB_STOP)
1469 			break;
1470 
1471 		nlh = NLMSG_NEXT(nlh, len);
1472 	}
1473 	return ret;
1474 }
1475 
1476 /*
1477  * New parsing functions based on iterators
1478  */
1479 
1480 struct nfnl_iterator {
1481 	struct nlmsghdr *nlh;
1482 	unsigned int	len;
1483 };
1484 
1485 /**
1486  * nfnl_iterator_create: create an nfnetlink iterator
1487  * @h: nfnetlink handler
1488  * @buf: buffer that contains data received from a nfnetlink system
1489  * @len: size of the data contained in the buffer (not the buffer size)
1490  *
1491  * This function creates an iterator that can be used to parse nfnetlink
1492  * message one by one. The iterator gives more control to the programmer
1493  * in the messages processing.
1494  *
1495  * On success, a valid address is returned. On error, NULL is returned
1496  * and errno is set to the appropiate value.
1497  */
1498 struct nfnl_iterator *
nfnl_iterator_create(const struct nfnl_handle * h,const char * buf,size_t len)1499 nfnl_iterator_create(const struct nfnl_handle *h,
1500 		     const char *buf,
1501 		     size_t len)
1502 {
1503 	struct nlmsghdr *nlh;
1504 	struct nfnl_iterator *it;
1505 
1506 	assert(h);
1507 	assert(buf);
1508 	assert(len > 0);
1509 
1510 	it = malloc(sizeof(struct nfnl_iterator));
1511 	if (!it) {
1512 		errno = ENOMEM;
1513 		return NULL;
1514 	}
1515 
1516 	/* first message in buffer */
1517 	nlh = (struct nlmsghdr *)buf;
1518 	if (len < NLMSG_SPACE(0) || !NLMSG_OK(nlh, len)) {
1519 		free(it);
1520 		errno = EBADMSG;
1521 		return NULL;
1522 	}
1523 	it->nlh = nlh;
1524 	it->len = len;
1525 
1526 	return it;
1527 }
1528 
1529 /**
1530  * nfnl_iterator_destroy - destroy a nfnetlink iterator
1531  * @it: nfnetlink iterator
1532  *
1533  * This function destroys a certain iterator. Nothing is returned.
1534  */
nfnl_iterator_destroy(struct nfnl_iterator * it)1535 void nfnl_iterator_destroy(struct nfnl_iterator *it)
1536 {
1537 	assert(it);
1538 	free(it);
1539 }
1540 
1541 /**
1542  * nfnl_iterator_process - process a nfnetlink message
1543  * @h: nfnetlink handler
1544  * @it: nfnetlink iterator that contains the current message to be proccesed
1545  *
1546  * This function process just the current message selected by the iterator.
1547  * On success, a value greater or equal to zero is returned. On error,
1548  * -1 is returned and errno is appropiately set.
1549  */
nfnl_iterator_process(struct nfnl_handle * h,struct nfnl_iterator * it)1550 int nfnl_iterator_process(struct nfnl_handle *h, struct nfnl_iterator *it)
1551 {
1552 	assert(h);
1553 	assert(it->nlh);
1554 
1555         /* check for out of sequence message */
1556 	if (it->nlh->nlmsg_seq && it->nlh->nlmsg_seq != h->seq) {
1557 		errno = EILSEQ;
1558 		return -1;
1559 	}
1560 	if (it->len < NLMSG_SPACE(0) || !NLMSG_OK(it->nlh, it->len)) {
1561 		errno = EBADMSG;
1562 		return -1;
1563 	}
1564 	return nfnl_step(h, it->nlh);
1565 }
1566 
1567 /**
1568  * nfnl_iterator_next - get the next message hold by the iterator
1569  * @h: nfnetlink handler
1570  * @it: nfnetlink iterator that contains the current message processed
1571  *
1572  * This function update the current message to be processed pointer.
1573  * It returns NFNL_CB_CONTINUE if there is still more messages to be
1574  * processed, otherwise NFNL_CB_STOP is returned.
1575  */
nfnl_iterator_next(const struct nfnl_handle * h,struct nfnl_iterator * it)1576 int nfnl_iterator_next(const struct nfnl_handle *h, struct nfnl_iterator *it)
1577 {
1578 	assert(h);
1579 	assert(it);
1580 
1581 	it->nlh = NLMSG_NEXT(it->nlh, it->len);
1582 	if (!it->nlh)
1583 		return 0;
1584 	return 1;
1585 }
1586 
1587 /**
1588  * nfnl_catch - get responses from the nfnetlink system and process them
1589  * @h: nfnetlink handler
1590 *
1591  * This function handles the data received from the nfnetlink system.
1592  * For example, events generated by one of the subsystems. The message
1593  * is passed to the callback registered via callback_register(). Note that
1594  * this a replacement of nfnl_listen and its use is recommended.
1595  *
1596  * On success, 0 is returned. On error, a -1 is returned. If you do not
1597  * want to listen to events anymore, then your callback must return
1598  * NFNL_CB_STOP.
1599  *
1600  * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
1601  * that case is possible that the information requested is incomplete.
1602  */
nfnl_catch(struct nfnl_handle * h)1603 int nfnl_catch(struct nfnl_handle *h)
1604 {
1605 	int ret;
1606 
1607 	assert(h);
1608 
1609 	while (1) {
1610 		unsigned char buf[h->rcv_buffer_size]
1611 			__attribute__ ((aligned));
1612 
1613 		ret = nfnl_recv(h, buf, sizeof(buf));
1614 		if (ret == -1) {
1615 			/* interrupted syscall must retry */
1616 			if (errno == EINTR)
1617 				continue;
1618 			break;
1619 		}
1620 
1621 		ret = nfnl_process(h, buf, ret);
1622 		if (ret <= NFNL_CB_STOP)
1623 			break;
1624 	}
1625 
1626 	return ret;
1627 }
1628 
1629 /**
1630  * nfnl_query - request/response communication challenge
1631  * @h: nfnetlink handler
1632  * @nlh: nfnetlink message to be sent
1633  *
1634  * This function sends a nfnetlink message to a certain subsystem and
1635  * receives the response messages associated, such messages are passed to
1636  * the callback registered via register_callback(). Note that this function
1637  * is a replacement for nfnl_talk, its use is recommended.
1638  *
1639  * On success, 0 is returned. On error, a negative is returned. If your
1640  * does not want to listen to events anymore, then your callback must
1641  * return NFNL_CB_STOP.
1642  *
1643  * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
1644  * that case is possible that the information requested is incomplete.
1645  */
nfnl_query(struct nfnl_handle * h,struct nlmsghdr * nlh)1646 int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh)
1647 {
1648 	assert(h);
1649 	assert(nlh);
1650 
1651 	if (nfnl_send(h, nlh) == -1)
1652 		return -1;
1653 
1654 	return nfnl_catch(h);
1655 }
1656