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