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