1/*
2 * libnetlink.c	RTnetlink service routines.
3 *
4 *		This program is free software; you can redistribute it and/or
5 *		modify it under the terms of the GNU General Public License
6 *		as published by the Free Software Foundation; either version
7 *		2 of the License, or (at your option) any later version.
8 *
9 * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <syslog.h>
17#include <fcntl.h>
18#include <net/if_arp.h>
19#include <sys/socket.h>
20#include <netinet/in.h>
21#include <string.h>
22#include <errno.h>
23#include <time.h>
24#include <sys/uio.h>
25
26#include "libnetlink.h"
27
28int rcvbuf = 1024 * 1024;
29
30void rtnl_close(struct rtnl_handle *rth)
31{
32	if (rth->fd >= 0) {
33		close(rth->fd);
34		rth->fd = -1;
35	}
36}
37
38int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
39		      int protocol)
40{
41	socklen_t addr_len;
42	int sndbuf = 32768;
43
44	memset(rth, 0, sizeof(*rth));
45
46	rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
47	if (rth->fd < 0) {
48		perror("Cannot open netlink socket");
49		return -1;
50	}
51
52	if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
53		perror("SO_SNDBUF");
54		return -1;
55	}
56
57	if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
58		perror("SO_RCVBUF");
59		return -1;
60	}
61
62	memset(&rth->local, 0, sizeof(rth->local));
63	rth->local.nl_family = AF_NETLINK;
64	rth->local.nl_groups = subscriptions;
65
66	if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
67		perror("Cannot bind netlink socket");
68		return -1;
69	}
70	addr_len = sizeof(rth->local);
71	if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
72		perror("Cannot getsockname");
73		return -1;
74	}
75	if (addr_len != sizeof(rth->local)) {
76		fprintf(stderr, "Wrong address length %d\n", addr_len);
77		return -1;
78	}
79	if (rth->local.nl_family != AF_NETLINK) {
80		fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
81		return -1;
82	}
83	rth->seq = time(NULL);
84	return 0;
85}
86
87int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
88{
89	return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
90}
91
92int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
93{
94	struct {
95		struct nlmsghdr nlh;
96		struct rtgenmsg g;
97		__u16 align_rta;	/* attribute has to be 32bit aligned */
98		struct rtattr ext_req;
99		__u32 ext_filter_mask;
100	} req;
101
102	memset(&req, 0, sizeof(req));
103	req.nlh.nlmsg_len = sizeof(req);
104	req.nlh.nlmsg_type = type;
105	req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
106	req.nlh.nlmsg_pid = 0;
107	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
108	req.g.rtgen_family = family;
109
110	req.ext_req.rta_type = IFLA_EXT_MASK;
111	req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32));
112	req.ext_filter_mask = RTEXT_FILTER_VF;
113
114	return send(rth->fd, (void*)&req, sizeof(req), 0);
115}
116
117int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
118{
119	return send(rth->fd, buf, len, 0);
120}
121
122int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
123{
124	struct nlmsghdr *h;
125	int status;
126	char resp[1024];
127
128	status = send(rth->fd, buf, len, 0);
129	if (status < 0)
130		return status;
131
132	/* Check for immediate errors */
133	status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
134	if (status < 0) {
135		if (errno == EAGAIN)
136			return 0;
137		return -1;
138	}
139
140	for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
141	     h = NLMSG_NEXT(h, status)) {
142		if (h->nlmsg_type == NLMSG_ERROR) {
143			struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
144			if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
145				fprintf(stderr, "ERROR truncated\n");
146			else
147				errno = -err->error;
148			return -1;
149		}
150	}
151
152	return 0;
153}
154
155int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
156{
157	struct nlmsghdr nlh;
158	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
159	struct iovec iov[2] = {
160		{ .iov_base = &nlh, .iov_len = sizeof(nlh) },
161		{ .iov_base = req, .iov_len = len }
162	};
163	struct msghdr msg = {
164		.msg_name = &nladdr,
165		.msg_namelen = 	sizeof(nladdr),
166		.msg_iov = iov,
167		.msg_iovlen = 2,
168	};
169
170	nlh.nlmsg_len = NLMSG_LENGTH(len);
171	nlh.nlmsg_type = type;
172	nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
173	nlh.nlmsg_pid = 0;
174	nlh.nlmsg_seq = rth->dump = ++rth->seq;
175
176	return sendmsg(rth->fd, &msg, 0);
177}
178
179int rtnl_dump_filter_l(struct rtnl_handle *rth,
180		       const struct rtnl_dump_filter_arg *arg)
181{
182	struct sockaddr_nl nladdr;
183	struct iovec iov;
184	struct msghdr msg = {
185		.msg_name = &nladdr,
186		.msg_namelen = sizeof(nladdr),
187		.msg_iov = &iov,
188		.msg_iovlen = 1,
189	};
190	char buf[16384];
191
192	iov.iov_base = buf;
193	while (1) {
194		int status;
195		const struct rtnl_dump_filter_arg *a;
196		int found_done = 0;
197		int msglen = 0;
198
199		iov.iov_len = sizeof(buf);
200		status = recvmsg(rth->fd, &msg, 0);
201
202		if (status < 0) {
203			if (errno == EINTR || errno == EAGAIN)
204				continue;
205			fprintf(stderr, "netlink receive error %s (%d)\n",
206				strerror(errno), errno);
207			return -1;
208		}
209
210		if (status == 0) {
211			fprintf(stderr, "EOF on netlink\n");
212			return -1;
213		}
214
215		for (a = arg; a->filter; a++) {
216			struct nlmsghdr *h = (struct nlmsghdr*)buf;
217			msglen = status;
218
219			while (NLMSG_OK(h, msglen)) {
220				int err;
221
222				if (nladdr.nl_pid != 0 ||
223				    h->nlmsg_pid != rth->local.nl_pid ||
224				    h->nlmsg_seq != rth->dump)
225					goto skip_it;
226
227				if (h->nlmsg_type == NLMSG_DONE) {
228					found_done = 1;
229					break; /* process next filter */
230				}
231				if (h->nlmsg_type == NLMSG_ERROR) {
232					struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
233					if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
234						fprintf(stderr,
235							"ERROR truncated\n");
236					} else {
237						errno = -err->error;
238						perror("RTNETLINK answers");
239					}
240					return -1;
241				}
242				err = a->filter(&nladdr, h, a->arg1);
243				if (err < 0)
244					return err;
245
246skip_it:
247				h = NLMSG_NEXT(h, msglen);
248			}
249		}
250
251		if (found_done)
252			return 0;
253
254		if (msg.msg_flags & MSG_TRUNC) {
255			fprintf(stderr, "Message truncated\n");
256			continue;
257		}
258		if (msglen) {
259			fprintf(stderr, "!!!Remnant of size %d\n", msglen);
260			exit(1);
261		}
262	}
263}
264
265int rtnl_dump_filter(struct rtnl_handle *rth,
266		     rtnl_filter_t filter,
267		     void *arg1)
268{
269	const struct rtnl_dump_filter_arg a[2] = {
270		{ .filter = filter, .arg1 = arg1, },
271		{ .filter = NULL,   .arg1 = NULL, },
272	};
273
274	return rtnl_dump_filter_l(rth, a);
275}
276
277int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
278	      unsigned groups, struct nlmsghdr *answer)
279{
280	int status;
281	unsigned seq;
282	struct nlmsghdr *h;
283	struct sockaddr_nl nladdr;
284	struct iovec iov = {
285		.iov_base = (void*) n,
286		.iov_len = n->nlmsg_len
287	};
288	struct msghdr msg = {
289		.msg_name = &nladdr,
290		.msg_namelen = sizeof(nladdr),
291		.msg_iov = &iov,
292		.msg_iovlen = 1,
293	};
294	char   buf[16384];
295
296	memset(&nladdr, 0, sizeof(nladdr));
297	nladdr.nl_family = AF_NETLINK;
298	nladdr.nl_pid = peer;
299	nladdr.nl_groups = groups;
300
301	n->nlmsg_seq = seq = ++rtnl->seq;
302
303	if (answer == NULL)
304		n->nlmsg_flags |= NLM_F_ACK;
305
306	status = sendmsg(rtnl->fd, &msg, 0);
307
308	if (status < 0) {
309		perror("Cannot talk to rtnetlink");
310		return -1;
311	}
312
313	memset(buf,0,sizeof(buf));
314
315	iov.iov_base = buf;
316
317	while (1) {
318		iov.iov_len = sizeof(buf);
319		status = recvmsg(rtnl->fd, &msg, 0);
320
321		if (status < 0) {
322			if (errno == EINTR || errno == EAGAIN)
323				continue;
324			fprintf(stderr, "netlink receive error %s (%d)\n",
325				strerror(errno), errno);
326			return -1;
327		}
328		if (status == 0) {
329			fprintf(stderr, "EOF on netlink\n");
330			return -1;
331		}
332		if (msg.msg_namelen != sizeof(nladdr)) {
333			fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
334			exit(1);
335		}
336		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
337			int len = h->nlmsg_len;
338			int l = len - sizeof(*h);
339
340			if (l < 0 || len>status) {
341				if (msg.msg_flags & MSG_TRUNC) {
342					fprintf(stderr, "Truncated message\n");
343					return -1;
344				}
345				fprintf(stderr, "!!!malformed message: len=%d\n", len);
346				exit(1);
347			}
348
349			if (nladdr.nl_pid != peer ||
350			    h->nlmsg_pid != rtnl->local.nl_pid ||
351			    h->nlmsg_seq != seq) {
352				/* Don't forget to skip that message. */
353				status -= NLMSG_ALIGN(len);
354				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
355				continue;
356			}
357
358			if (h->nlmsg_type == NLMSG_ERROR) {
359				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
360				if (l < sizeof(struct nlmsgerr)) {
361					fprintf(stderr, "ERROR truncated\n");
362				} else {
363					errno = -err->error;
364					if (errno == 0) {
365						if (answer)
366							memcpy(answer, h, h->nlmsg_len);
367						return 0;
368					}
369					perror("RTNETLINK answers");
370				}
371				return -1;
372			}
373			if (answer) {
374				memcpy(answer, h, h->nlmsg_len);
375				return 0;
376			}
377
378			fprintf(stderr, "Unexpected reply!!!\n");
379
380			status -= NLMSG_ALIGN(len);
381			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
382		}
383		if (msg.msg_flags & MSG_TRUNC) {
384			fprintf(stderr, "Message truncated\n");
385			continue;
386		}
387		if (status) {
388			fprintf(stderr, "!!!Remnant of size %d\n", status);
389			exit(1);
390		}
391	}
392}
393
394int rtnl_listen(struct rtnl_handle *rtnl,
395		rtnl_filter_t handler,
396		void *jarg)
397{
398	int status;
399	struct nlmsghdr *h;
400	struct sockaddr_nl nladdr;
401	struct iovec iov;
402	struct msghdr msg = {
403		.msg_name = &nladdr,
404		.msg_namelen = sizeof(nladdr),
405		.msg_iov = &iov,
406		.msg_iovlen = 1,
407	};
408	char   buf[8192];
409
410	memset(&nladdr, 0, sizeof(nladdr));
411	nladdr.nl_family = AF_NETLINK;
412	nladdr.nl_pid = 0;
413	nladdr.nl_groups = 0;
414
415	iov.iov_base = buf;
416	while (1) {
417		iov.iov_len = sizeof(buf);
418		status = recvmsg(rtnl->fd, &msg, 0);
419
420		if (status < 0) {
421			if (errno == EINTR || errno == EAGAIN)
422				continue;
423			fprintf(stderr, "netlink receive error %s (%d)\n",
424				strerror(errno), errno);
425			if (errno == ENOBUFS)
426				continue;
427			return -1;
428		}
429		if (status == 0) {
430			fprintf(stderr, "EOF on netlink\n");
431			return -1;
432		}
433		if (msg.msg_namelen != sizeof(nladdr)) {
434			fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
435			exit(1);
436		}
437		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
438			int err;
439			int len = h->nlmsg_len;
440			int l = len - sizeof(*h);
441
442			if (l<0 || len>status) {
443				if (msg.msg_flags & MSG_TRUNC) {
444					fprintf(stderr, "Truncated message\n");
445					return -1;
446				}
447				fprintf(stderr, "!!!malformed message: len=%d\n", len);
448				exit(1);
449			}
450
451			err = handler(&nladdr, h, jarg);
452			if (err < 0)
453				return err;
454
455			status -= NLMSG_ALIGN(len);
456			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
457		}
458		if (msg.msg_flags & MSG_TRUNC) {
459			fprintf(stderr, "Message truncated\n");
460			continue;
461		}
462		if (status) {
463			fprintf(stderr, "!!!Remnant of size %d\n", status);
464			exit(1);
465		}
466	}
467}
468
469int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
470		   void *jarg)
471{
472	int status;
473	struct sockaddr_nl nladdr;
474	char   buf[8192];
475	struct nlmsghdr *h = (void*)buf;
476
477	memset(&nladdr, 0, sizeof(nladdr));
478	nladdr.nl_family = AF_NETLINK;
479	nladdr.nl_pid = 0;
480	nladdr.nl_groups = 0;
481
482	while (1) {
483		int err, len;
484		int l;
485
486		status = fread(&buf, 1, sizeof(*h), rtnl);
487
488		if (status < 0) {
489			if (errno == EINTR)
490				continue;
491			perror("rtnl_from_file: fread");
492			return -1;
493		}
494		if (status == 0)
495			return 0;
496
497		len = h->nlmsg_len;
498		l = len - sizeof(*h);
499
500		if (l<0 || len>sizeof(buf)) {
501			fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
502				len, ftell(rtnl));
503			return -1;
504		}
505
506		status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
507
508		if (status < 0) {
509			perror("rtnl_from_file: fread");
510			return -1;
511		}
512		if (status < l) {
513			fprintf(stderr, "rtnl-from_file: truncated message\n");
514			return -1;
515		}
516
517		err = handler(&nladdr, h, jarg);
518		if (err < 0)
519			return err;
520	}
521}
522
523int addattr(struct nlmsghdr *n, int maxlen, int type)
524{
525	return addattr_l(n, maxlen, type, NULL, 0);
526}
527
528int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
529{
530	return addattr_l(n, maxlen, type, &data, sizeof(__u8));
531}
532
533int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
534{
535	return addattr_l(n, maxlen, type, &data, sizeof(__u16));
536}
537
538int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
539{
540	return addattr_l(n, maxlen, type, &data, sizeof(__u32));
541}
542
543int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
544{
545	return addattr_l(n, maxlen, type, &data, sizeof(__u64));
546}
547
548int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
549{
550	return addattr_l(n, maxlen, type, str, strlen(str)+1);
551}
552
553int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
554	      int alen)
555{
556	int len = RTA_LENGTH(alen);
557	struct rtattr *rta;
558
559	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
560		fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
561		return -1;
562	}
563	rta = NLMSG_TAIL(n);
564	rta->rta_type = type;
565	rta->rta_len = len;
566	memcpy(RTA_DATA(rta), data, alen);
567	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
568	return 0;
569}
570
571int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
572{
573	if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
574		fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
575		return -1;
576	}
577
578	memcpy(NLMSG_TAIL(n), data, len);
579	memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
580	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
581	return 0;
582}
583
584struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
585{
586	struct rtattr *nest = NLMSG_TAIL(n);
587
588	addattr_l(n, maxlen, type, NULL, 0);
589	return nest;
590}
591
592int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
593{
594	nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
595	return n->nlmsg_len;
596}
597
598struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
599				   const void *data, int len)
600{
601	struct rtattr *start = NLMSG_TAIL(n);
602
603	addattr_l(n, maxlen, type, data, len);
604	addattr_nest(n, maxlen, type);
605	return start;
606}
607
608int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
609{
610	struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
611
612	start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
613	addattr_nest_end(n, nest);
614	return n->nlmsg_len;
615}
616
617int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
618{
619	int len = RTA_LENGTH(4);
620	struct rtattr *subrta;
621
622	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
623		fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
624		return -1;
625	}
626	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
627	subrta->rta_type = type;
628	subrta->rta_len = len;
629	memcpy(RTA_DATA(subrta), &data, 4);
630	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
631	return 0;
632}
633
634int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
635		  const void *data, int alen)
636{
637	struct rtattr *subrta;
638	int len = RTA_LENGTH(alen);
639
640	if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
641		fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
642		return -1;
643	}
644	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
645	subrta->rta_type = type;
646	subrta->rta_len = len;
647	memcpy(RTA_DATA(subrta), data, alen);
648	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
649	return 0;
650}
651
652int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
653{
654	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
655	while (RTA_OK(rta, len)) {
656		if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
657			tb[rta->rta_type] = rta;
658		rta = RTA_NEXT(rta,len);
659	}
660	if (len)
661		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
662	return 0;
663}
664
665int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
666{
667	int i = 0;
668
669	memset(tb, 0, sizeof(struct rtattr *) * max);
670	while (RTA_OK(rta, len)) {
671		if (rta->rta_type <= max && i < max)
672			tb[i++] = rta;
673		rta = RTA_NEXT(rta,len);
674	}
675	if (len)
676		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
677	return i;
678}
679
680int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
681			         int len)
682{
683	if (RTA_PAYLOAD(rta) < len)
684		return -1;
685	if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
686		rta = RTA_DATA(rta) + RTA_ALIGN(len);
687		return parse_rtattr_nested(tb, max, rta);
688	}
689	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
690	return 0;
691}
692