chiark / gitweb /
rtnl: fix memory corruptions after realloc
[elogind.git] / src / libsystemd-rtnl / rtnl-message.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <linux/rtnetlink.h>
23 #include <netinet/in.h>
24 #include <netinet/ether.h>
25 #include <stdbool.h>
26 #include <unistd.h>
27
28 #include "util.h"
29 #include "refcnt.h"
30
31 #include "sd-rtnl.h"
32 #include "rtnl-internal.h"
33
34 struct sd_rtnl_message {
35         RefCount n_ref;
36
37         struct nlmsghdr *hdr;
38         size_t container_offset; /* offset from hdr to container start */
39         size_t next_rta_offset; /* offset from hdr to next rta */
40
41         bool sealed:1;
42 };
43
44 #define CURRENT_CONTAINER(m) ((m)->container_offset ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offset) : NULL)
45 #define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
46 #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
47
48 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
49         sd_rtnl_message *m;
50
51         assert_return(ret, -EINVAL);
52         assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
53
54         m = new0(sd_rtnl_message, 1);
55         if (!m)
56                 return -ENOMEM;
57
58         m->hdr = malloc0(initial_size);
59         if (!m->hdr) {
60                 free(m);
61                 return -ENOMEM;
62         }
63
64         m->n_ref = REFCNT_INIT;
65
66         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
67         m->sealed = false;
68
69         *ret = m;
70
71         return 0;
72 }
73
74 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
75         struct nlmsgerr *err;
76         int r;
77
78         assert(error <= 0);
79
80         r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
81         if (r < 0)
82                 return r;
83
84         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
85         (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
86         (*ret)->hdr->nlmsg_seq = serial;
87
88         err = NLMSG_DATA((*ret)->hdr);
89
90         err->error = error;
91
92         return 0;
93 }
94
95 bool message_type_is_route(uint16_t type) {
96         switch (type) {
97                 case RTM_NEWROUTE:
98                 case RTM_GETROUTE:
99                 case RTM_DELROUTE:
100                         return true;
101                 default:
102                         return false;
103         }
104 }
105
106 bool message_type_is_link(uint16_t type) {
107         switch (type) {
108                 case RTM_NEWLINK:
109                 case RTM_SETLINK:
110                 case RTM_GETLINK:
111                 case RTM_DELLINK:
112                         return true;
113                 default:
114                         return false;
115         }
116 }
117
118 bool message_type_is_addr(uint16_t type) {
119         switch (type) {
120                 case RTM_NEWADDR:
121                 case RTM_GETADDR:
122                 case RTM_DELADDR:
123                         return true;
124                 default:
125                         return false;
126         }
127 }
128
129 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
130         struct rtmsg *rtm;
131
132         rtm = NLMSG_DATA(m->hdr);
133
134         rtm->rtm_dst_len = prefixlen;
135
136         return 0;
137 }
138
139 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
140                               sd_rtnl_message **ret) {
141         struct rtmsg *rtm;
142         int r;
143
144         assert_return(message_type_is_route(nlmsg_type), -EINVAL);
145         assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
146         assert_return(ret, -EINVAL);
147
148         r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
149         if (r < 0)
150                 return r;
151
152         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
153         (*ret)->hdr->nlmsg_type = nlmsg_type;
154         if (nlmsg_type == RTM_NEWROUTE)
155                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
156
157         rtm = NLMSG_DATA((*ret)->hdr);
158
159         UPDATE_RTA(*ret, RTM_RTA(rtm));
160
161         rtm->rtm_family = rtm_family;
162         rtm->rtm_scope = RT_SCOPE_UNIVERSE;
163         rtm->rtm_type = RTN_UNICAST;
164         rtm->rtm_table = RT_TABLE_MAIN;
165         rtm->rtm_protocol = RTPROT_BOOT;
166
167         return 0;
168 }
169
170 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags) {
171         struct ifinfomsg *ifi;
172
173         ifi = NLMSG_DATA(m->hdr);
174
175         ifi->ifi_flags = flags;
176
177         return 0;
178 }
179
180 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
181         struct ifinfomsg *ifi;
182
183         ifi = NLMSG_DATA(m->hdr);
184
185         ifi->ifi_type = type;
186
187         return 0;
188 }
189
190 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
191         struct ifinfomsg *ifi;
192         int r;
193
194         assert_return(message_type_is_link(nlmsg_type), -EINVAL);
195         assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
196         assert_return(ret, -EINVAL);
197
198         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
199         if (r < 0)
200                 return r;
201
202         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
203         (*ret)->hdr->nlmsg_type = nlmsg_type;
204         if (nlmsg_type == RTM_NEWLINK)
205                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
206
207         ifi = NLMSG_DATA((*ret)->hdr);
208
209         ifi->ifi_family = AF_UNSPEC;
210         ifi->ifi_index = index;
211         ifi->ifi_change = 0xffffffff;
212
213         UPDATE_RTA(*ret, IFLA_RTA(ifi));
214
215         return 0;
216 }
217
218 int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family, unsigned char prefixlen, unsigned char flags, unsigned char scope, sd_rtnl_message **ret) {
219         struct ifaddrmsg *ifa;
220         int r;
221
222         assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
223         assert_return(index > 0, -EINVAL);
224         assert_return(ret, -EINVAL);
225
226         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
227         if (r < 0)
228                 return r;
229
230         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
231         (*ret)->hdr->nlmsg_type = nlmsg_type;
232
233         ifa = NLMSG_DATA((*ret)->hdr);
234
235         ifa->ifa_family = family;
236         ifa->ifa_prefixlen = prefixlen;
237         ifa->ifa_flags = flags;
238         ifa->ifa_scope = scope;
239         ifa->ifa_index = index;
240
241         UPDATE_RTA(*ret, IFA_RTA(ifa));
242
243         return 0;
244 }
245
246 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
247         if (m)
248                 assert_se(REFCNT_INC(m->n_ref) >= 2);
249
250         return m;
251 }
252
253 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
254         if (m && REFCNT_DEC(m->n_ref) <= 0) {
255                 free(m->hdr);
256                 free(m);
257         }
258
259         return NULL;
260 }
261
262 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
263         assert_return(m, -EINVAL);
264         assert_return(type, -EINVAL);
265
266         *type = m->hdr->nlmsg_type;
267
268         return 0;
269 }
270
271 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
272         struct ifinfomsg *ifi;
273
274         assert_return(m, -EINVAL);
275         assert_return(m->hdr, -EINVAL);
276         assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
277         assert_return(ifindex, -EINVAL);
278
279         ifi = NLMSG_DATA(m->hdr);
280
281         *ifindex = ifi->ifi_index;
282
283         return 0;
284 }
285
286 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
287         struct ifinfomsg *ifi;
288
289         assert_return(m, -EINVAL);
290         assert_return(m->hdr, -EINVAL);
291         assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
292         assert_return(flags, -EINVAL);
293
294         ifi = NLMSG_DATA(m->hdr);
295
296         *flags = ifi->ifi_flags;
297
298         return 0;
299 }
300
301 /* If successful the updated message will be correctly aligned, if
302    unsuccessful the old message is untouched. */
303 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
304         uint32_t rta_length, message_length;
305         struct nlmsghdr *new_hdr;
306         struct rtattr *rta;
307         char *padding;
308
309         assert(m);
310         assert(m->hdr);
311         assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
312         assert(!data || data_length > 0);
313
314         /* get the size of the new rta attribute (with padding at the end) */
315         rta_length = RTA_LENGTH(data_length);
316
317         /* get the new message size (with padding at the end) */
318         message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
319
320         /* realloc to fit the new attribute */
321         new_hdr = realloc(m->hdr, message_length);
322         if (!new_hdr)
323                 return -ENOMEM;
324         m->hdr = new_hdr;
325
326         /* get pointer to the attribute we are about to add */
327         rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
328
329         /* if we are inside a container, extend it */
330         if (CURRENT_CONTAINER(m))
331                 CURRENT_CONTAINER(m)->rta_len += message_length - m->hdr->nlmsg_len;
332
333         /* fill in the attribute */
334         rta->rta_type = type;
335         rta->rta_len = rta_length;
336         if (!data) {
337                 /* this is the start of a new container */
338                 m->container_offset = m->hdr->nlmsg_len;
339         } else {
340                 /* we don't deal with the case where the user lies about the type
341                  * and gives us too little data (so don't do that)
342                 */
343                 padding = mempcpy(RTA_DATA(rta), data, data_length);
344                 /* make sure also the padding at the end of the message is initialized */
345                 memzero(padding,
346                         (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
347         }
348
349         /* update message size */
350         m->hdr->nlmsg_len = message_length;
351
352         return 0;
353 }
354
355 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
356         uint16_t rtm_type;
357         int r;
358
359         assert_return(m, -EINVAL);
360         assert_return(data, -EINVAL);
361
362         r = sd_rtnl_message_get_type(m, &rtm_type);
363         if (r < 0)
364                 return r;
365
366         /* check that the type is correct */
367         switch (rtm_type) {
368                 case RTM_NEWLINK:
369                 case RTM_SETLINK:
370                 case RTM_GETLINK:
371                 case RTM_DELLINK:
372                         if (CURRENT_CONTAINER(m)) {
373                                 if (CURRENT_CONTAINER(m)->rta_type != IFLA_LINKINFO ||
374                                     type != IFLA_INFO_KIND)
375                                         return -ENOTSUP;
376                         } else {
377                                 switch (type) {
378                                         case IFLA_IFNAME:
379                                         case IFLA_IFALIAS:
380                                         case IFLA_QDISC:
381                                                 break;
382                                         default:
383                                                 return -ENOTSUP;
384                                 }
385                         }
386                         break;
387                 case RTM_NEWADDR:
388                 case RTM_GETADDR:
389                 case RTM_DELADDR:
390                         if (type != IFA_LABEL)
391                                 return -ENOTSUP;
392                         break;
393                 default:
394                         return -ENOTSUP;
395         }
396
397         r = add_rtattr(m, type, data, strlen(data) + 1);
398         if (r < 0)
399                 return r;
400
401         return 0;
402 }
403
404 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
405         uint16_t rtm_type;
406         int r;
407
408         assert_return(m, -EINVAL);
409
410         r = sd_rtnl_message_get_type(m, &rtm_type);
411         if (r < 0)
412                 return r;
413
414         /* check that the type is correct */
415         switch (rtm_type) {
416                 case RTM_NEWLINK:
417                 case RTM_SETLINK:
418                 case RTM_GETLINK:
419                 case RTM_DELLINK:
420                         switch (type) {
421                                 case IFLA_MASTER:
422                                 case IFLA_MTU:
423                                 case IFLA_LINK:
424                                         break;
425                                 default:
426                                         return -ENOTSUP;
427                         }
428                         break;
429                 case RTM_NEWROUTE:
430                 case RTM_GETROUTE:
431                 case RTM_DELROUTE:
432                         switch (type) {
433                                 case RTA_TABLE:
434                                 case RTA_PRIORITY:
435                                 case RTA_IIF:
436                                 case RTA_OIF:
437                                         break;
438                                 default:
439                                         return -ENOTSUP;
440                         }
441                         break;
442                 default:
443                         return -ENOTSUP;
444         }
445
446         r = add_rtattr(m, type, &data, sizeof(uint32_t));
447         if (r < 0)
448                 return r;
449
450         return 0;
451 }
452
453 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
454         struct ifaddrmsg *ifa;
455         struct rtmsg *rtm;
456         uint16_t rtm_type;
457         int r;
458
459         assert_return(m, -EINVAL);
460         assert_return(data, -EINVAL);
461
462         r = sd_rtnl_message_get_type(m, &rtm_type);
463         if (r < 0)
464                 return r;
465
466         /* check that the type is correct */
467         switch (rtm_type) {
468                 case RTM_NEWADDR:
469                 case RTM_GETADDR:
470                 case RTM_DELADDR:
471                         switch (type) {
472                                 case IFA_ADDRESS:
473                                 case IFA_LOCAL:
474                                 case IFA_BROADCAST:
475                                 case IFA_ANYCAST:
476                                         ifa = NLMSG_DATA(m->hdr);
477
478                                         if (ifa->ifa_family != AF_INET)
479                                                 return -EINVAL;
480
481                                         break;
482                                 default:
483                                         return -ENOTSUP;
484                         }
485                         break;
486                 case RTM_NEWROUTE:
487                 case RTM_GETROUTE:
488                 case RTM_DELROUTE:
489                         switch (type) {
490                                 case RTA_DST:
491                                 case RTA_SRC:
492                                 case RTA_GATEWAY:
493                                         rtm = NLMSG_DATA(m->hdr);
494
495                                         if (rtm->rtm_family != AF_INET)
496                                                 return -EINVAL;
497
498                                         break;
499                                 default:
500                                         return -ENOTSUP;
501                         }
502                         break;
503                 default:
504                         return -ENOTSUP;
505         }
506
507         r = add_rtattr(m, type, data, sizeof(struct in_addr));
508         if (r < 0)
509                 return r;
510
511         return 0;
512 }
513
514 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
515         struct ifaddrmsg *ifa;
516         struct rtmsg *rtm;
517         uint16_t rtm_type;
518         int r;
519
520         assert_return(m, -EINVAL);
521         assert_return(data, -EINVAL);
522
523         r = sd_rtnl_message_get_type(m, &rtm_type);
524         if (r < 0)
525                 return r;
526
527         /* check that the type is correct */
528         switch (rtm_type) {
529                 case RTM_NEWADDR:
530                 case RTM_GETADDR:
531                 case RTM_DELADDR:
532                         switch (type) {
533                                 case IFA_ADDRESS:
534                                 case IFA_LOCAL:
535                                 case IFA_BROADCAST:
536                                 case IFA_ANYCAST:
537                                         ifa = NLMSG_DATA(m->hdr);
538
539                                         if (ifa->ifa_family != AF_INET6)
540                                                 return -EINVAL;
541
542                                         break;
543                                 default:
544                                         return -ENOTSUP;
545                         }
546                         break;
547                 case RTM_NEWROUTE:
548                 case RTM_GETROUTE:
549                 case RTM_DELROUTE:
550                         switch (type) {
551                                 case RTA_DST:
552                                 case RTA_SRC:
553                                 case RTA_GATEWAY:
554                                         rtm = NLMSG_DATA(m->hdr);
555
556                                         if (rtm->rtm_family != AF_INET6)
557                                                 return -EINVAL;
558
559                                         break;
560                                 default:
561                                         return -ENOTSUP;
562                         }
563                 default:
564                         return -ENOTSUP;
565         }
566
567         r = add_rtattr(m, type, data, sizeof(struct in6_addr));
568         if (r < 0)
569                 return r;
570
571         return 0;
572 }
573
574 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
575         uint16_t rtm_type;
576         int r;
577
578         assert_return(m, -EINVAL);
579         assert_return(data, -EINVAL);
580
581         sd_rtnl_message_get_type(m, &rtm_type);
582
583         switch (rtm_type) {
584                 case RTM_NEWLINK:
585                 case RTM_SETLINK:
586                 case RTM_DELLINK:
587                 case RTM_GETLINK:
588                         switch (type) {
589                                 case IFLA_ADDRESS:
590                                 case IFLA_BROADCAST:
591                                         break;
592                                 default:
593                                         return -ENOTSUP;
594                         }
595                         break;
596                 default:
597                         return -ENOTSUP;
598         }
599
600         r = add_rtattr(m, type, data, ETH_ALEN);
601         if (r < 0)
602                 return r;
603
604         return 0;
605 }
606
607 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
608         uint16_t rtm_type;
609
610         assert_return(m, -EINVAL);
611         assert_return(!CURRENT_CONTAINER(m), -EINVAL);
612
613         sd_rtnl_message_get_type(m, &rtm_type);
614
615         if (message_type_is_link(rtm_type)) {
616                 if (type == IFLA_LINKINFO)
617                         return add_rtattr(m, type, NULL, 0);
618                 else
619                         return -ENOTSUP;
620         } else
621                 return -ENOTSUP;
622
623         return 0;
624 }
625
626 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
627         assert_return(m, -EINVAL);
628         assert_return(CURRENT_CONTAINER(m), -EINVAL);
629
630         m->container_offset = 0;
631
632         return 0;
633 }
634
635 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
636         size_t remaining_size;
637         uint16_t rtm_type;
638         int r;
639
640         assert(m);
641         assert(m->next_rta_offset);
642         assert(type);
643         assert(data);
644
645         remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
646
647         if (!RTA_OK(NEXT_RTA(m), remaining_size))
648                 return 0;
649
650         /* make sure we don't try to read a container
651          * TODO: add support for entering containers for reading */
652         r = sd_rtnl_message_get_type(m, &rtm_type);
653         if (r < 0)
654                 return r;
655
656         if (message_type_is_link(rtm_type) &&
657             NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
658                return -EINVAL;
659
660         *data = RTA_DATA(NEXT_RTA(m));
661         *type = NEXT_RTA(m)->rta_type;
662
663         UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
664
665         return 1;
666 }
667
668 uint32_t message_get_serial(sd_rtnl_message *m) {
669         assert(m);
670         assert(m->hdr);
671
672         return m->hdr->nlmsg_seq;
673 }
674
675 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
676         struct nlmsgerr *err;
677
678         assert_return(m, -EINVAL);
679         assert_return(m->hdr, -EINVAL);
680
681         if (m->hdr->nlmsg_type != NLMSG_ERROR)
682                 return 0;
683
684         err = NLMSG_DATA(m->hdr);
685
686         return err->error;
687 }
688
689 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
690         assert(nl);
691         assert(m);
692         assert(m->hdr);
693
694         if (m->sealed)
695                 return -EPERM;
696
697         m->hdr->nlmsg_seq = nl->serial++;
698         m->sealed = true;
699
700         return 0;
701 }
702
703 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
704         assert(rtnl);
705         assert(need);
706
707         /* ioctl(rtnl->fd, FIONREAD, &need)
708            Does not appear to work on netlink sockets. libnl uses
709            MSG_PEEK instead. I don't know if that is worth the
710            extra roundtrip.
711
712            For now we simply use the maximum message size the kernel
713            may use (NLMSG_GOODSIZE), and then realloc to the actual
714            size after reading the message (hence avoiding huge memory
715            usage in case many small messages are kept around) */
716         *need = page_size();
717         if (*need > 8192UL)
718                 *need = 8192UL;
719
720         return 0;
721 }
722
723 /* returns the number of bytes sent, or a negative error code */
724 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
725         union {
726                 struct sockaddr sa;
727                 struct sockaddr_nl nl;
728         } addr = {
729                 .nl.nl_family = AF_NETLINK,
730         };
731         ssize_t k;
732
733         assert(nl);
734         assert(m);
735         assert(m->hdr);
736
737         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
738                         0, &addr.sa, sizeof(addr));
739         if (k < 0)
740                 return (errno == EAGAIN) ? 0 : -errno;
741
742         return k;
743 }
744
745 /* On success, the number of bytes received is returned and *ret points to the received message
746  * which has a valid header and the correct size.
747  * If nothing useful was received 0 is returned.
748  * On failure, a negative error code is returned.
749  */
750 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
751         sd_rtnl_message *m;
752         union {
753                 struct sockaddr sa;
754                 struct sockaddr_nl nl;
755         } addr;
756         socklen_t addr_len;
757         int r;
758         ssize_t k;
759         size_t need;
760
761         assert(nl);
762         assert(ret);
763
764         r = message_receive_need(nl, &need);
765         if (r < 0)
766                 return r;
767
768         r = message_new(&m, need);
769         if (r < 0)
770                 return r;
771
772         addr_len = sizeof(addr);
773
774         k = recvfrom(nl->fd, m->hdr, need,
775                         0, &addr.sa, &addr_len);
776         if (k < 0)
777                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
778         else if (k == 0)
779                 k = -ECONNRESET; /* connection was closed by the kernel */
780         else if (addr_len != sizeof(addr.nl) ||
781                         addr.nl.nl_family != AF_NETLINK)
782                 k = -EIO; /* not a netlink message */
783         else if (addr.nl.nl_pid != 0)
784                 k = 0; /* not from the kernel */
785         else if ((size_t) k < sizeof(struct nlmsghdr) ||
786                         (size_t) k < m->hdr->nlmsg_len)
787                 k = -EIO; /* too small (we do accept too big though) */
788         else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
789                 k = 0; /* not broadcast and not for us */
790
791         if (k > 0)
792                 switch (m->hdr->nlmsg_type) {
793                         struct ifinfomsg *ifi;
794                         struct ifaddrmsg *ifa;
795                         struct rtmsg *rtm;
796
797                         /* check that the size matches the message type */
798                         case NLMSG_ERROR:
799                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
800                                         k = -EIO;
801                                 break;
802                         case RTM_NEWLINK:
803                         case RTM_SETLINK:
804                         case RTM_DELLINK:
805                         case RTM_GETLINK:
806                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
807                                         k = -EIO;
808                                 else {
809                                         ifi = NLMSG_DATA(m->hdr);
810                                         UPDATE_RTA(m, IFLA_RTA(ifi));
811                                 }
812                                 break;
813                         case RTM_NEWADDR:
814                         case RTM_DELADDR:
815                         case RTM_GETADDR:
816                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
817                                         k = -EIO;
818                                 else {
819                                         ifa = NLMSG_DATA(m->hdr);
820                                         UPDATE_RTA(m, IFA_RTA(ifa));
821                                 }
822                                 break;
823                         case RTM_NEWROUTE:
824                         case RTM_DELROUTE:
825                         case RTM_GETROUTE:
826                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
827                                         k = -EIO;
828                                 else {
829                                         rtm = NLMSG_DATA(m->hdr);
830                                         UPDATE_RTA(m, RTM_RTA(rtm));
831                                 }
832                                 break;
833                         case NLMSG_NOOP:
834                                 k = 0;
835                                 break;
836                         default:
837                                 k = 0; /* ignoring message of unknown type */
838                 }
839
840         if (k <= 0)
841                 sd_rtnl_message_unref(m);
842         else {
843                 /* we probably allocated way too much memory, give it back */
844                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
845                 *ret = m;
846         }
847
848         return k;
849 }
850
851 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
852         struct ifinfomsg *ifi;
853         struct ifaddrmsg *ifa;
854         struct rtmsg *rtm;
855
856         assert_return(m, -EINVAL);
857         assert_return(m->hdr, -EINVAL);
858
859         switch(m->hdr->nlmsg_type) {
860                 case RTM_NEWLINK:
861                 case RTM_SETLINK:
862                 case RTM_GETLINK:
863                 case RTM_DELLINK:
864                         ifi = NLMSG_DATA(m->hdr);
865                         UPDATE_RTA(m, IFLA_RTA(ifi));
866
867                         break;
868                 case RTM_NEWADDR:
869                 case RTM_GETADDR:
870                 case RTM_DELADDR:
871                         ifa = NLMSG_DATA(m->hdr);
872                         UPDATE_RTA(m, IFA_RTA(ifa));
873
874                         break;
875                 case RTM_NEWROUTE:
876                 case RTM_GETROUTE:
877                 case RTM_DELROUTE:
878                         rtm = NLMSG_DATA(m->hdr);
879                         UPDATE_RTA(m, RTM_RTA(rtm));
880
881                         break;
882                 default:
883                         return -ENOTSUP;
884         }
885
886         return 0;
887 }