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