chiark / gitweb /
1ce68626688d7ae7bc3e231bf1fd102bcf54dee3
[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
39         struct rtattr *next_rta;
40         size_t remaining_size;
41
42         bool sealed:1;
43 };
44
45 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
46         sd_rtnl_message *m;
47
48         assert_return(ret, -EINVAL);
49         assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
50
51         m = new0(sd_rtnl_message, 1);
52         if (!m)
53                 return -ENOMEM;
54
55         m->hdr = malloc0(initial_size);
56         if (!m->hdr) {
57                 free(m);
58                 return -ENOMEM;
59         }
60
61         m->n_ref = REFCNT_INIT;
62
63         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
64         m->sealed = false;
65
66         *ret = m;
67
68         return 0;
69 }
70
71 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
72         struct nlmsgerr *err;
73         int r;
74
75         assert(error <= 0);
76
77         r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
78         if (r < 0)
79                 return r;
80
81         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
82         (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
83         (*ret)->hdr->nlmsg_seq = serial;
84
85         err = NLMSG_DATA((*ret)->hdr);
86
87         err->error = error;
88
89         return 0;
90 }
91
92 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
93                               unsigned char rtm_dst_len, unsigned char rtm_src_len,
94                               unsigned char rtm_tos, unsigned char rtm_table,
95                               unsigned char rtm_scope, unsigned char rtm_protocol,
96                               unsigned char rtm_type, unsigned rtm_flags, sd_rtnl_message **ret) {
97         struct rtmsg *rtm;
98         int r;
99
100         assert_return(nlmsg_type == RTM_NEWROUTE || nlmsg_type == RTM_DELROUTE ||
101                       nlmsg_type == RTM_GETROUTE, -EINVAL);
102         assert_return(ret, -EINVAL);
103
104         r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
105         if (r < 0)
106                 return r;
107
108         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
109         (*ret)->hdr->nlmsg_type = nlmsg_type;
110         if (nlmsg_type == RTM_NEWROUTE)
111                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
112
113         rtm = NLMSG_DATA((*ret)->hdr);
114
115         rtm->rtm_family = rtm_family;
116         rtm->rtm_dst_len = rtm_dst_len;
117         rtm->rtm_src_len = rtm_src_len;
118         rtm->rtm_tos = rtm_tos;
119         rtm->rtm_table = rtm_table;
120         rtm->rtm_protocol = rtm_protocol;
121         rtm->rtm_scope = rtm_scope;
122         rtm->rtm_type = rtm_type;
123         rtm->rtm_flags = rtm_flags;
124
125         return 0;
126 }
127
128 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, unsigned int type, unsigned int flags, sd_rtnl_message **ret) {
129         struct ifinfomsg *ifi;
130         int r;
131
132         assert_return(nlmsg_type == RTM_NEWLINK || nlmsg_type == RTM_DELLINK || nlmsg_type == RTM_GETLINK, -EINVAL);
133         assert_return(index > 0, -EINVAL);
134         assert_return(ret, -EINVAL);
135
136         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
137         if (r < 0)
138                 return r;
139
140         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
141         (*ret)->hdr->nlmsg_type = nlmsg_type;
142
143         ifi = NLMSG_DATA((*ret)->hdr);
144
145         ifi->ifi_family = AF_UNSPEC;
146         ifi->ifi_index = index;
147         ifi->ifi_type = type;
148         ifi->ifi_flags = flags;
149         ifi->ifi_change = 0xffffffff;
150
151         return 0;
152 }
153
154 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) {
155         struct ifaddrmsg *ifa;
156         int r;
157
158         assert_return(nlmsg_type == RTM_NEWADDR || nlmsg_type == RTM_DELADDR || nlmsg_type == RTM_GETADDR, -EINVAL);
159         assert_return(index > 0, -EINVAL);
160         assert_return(ret, -EINVAL);
161
162         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
163         if (r < 0)
164                 return r;
165
166         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
167         (*ret)->hdr->nlmsg_type = nlmsg_type;
168
169         ifa = NLMSG_DATA((*ret)->hdr);
170
171         ifa->ifa_family = family;
172         ifa->ifa_prefixlen = prefixlen;
173         ifa->ifa_flags = flags;
174         ifa->ifa_scope = scope;
175         ifa->ifa_index = index;
176
177         return 0;
178 }
179
180 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
181         if (m)
182                 assert_se(REFCNT_INC(m->n_ref) >= 2);
183
184         return m;
185 }
186
187 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
188         if (m && REFCNT_DEC(m->n_ref) <= 0) {
189                 free(m->hdr);
190                 free(m);
191         }
192
193         return NULL;
194 }
195
196 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
197         assert_return(m, -EINVAL);
198         assert_return(type, -EINVAL);
199
200         *type = m->hdr->nlmsg_type;
201
202         return 0;
203 }
204
205 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
206    untouched */
207 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
208         uint32_t rta_length, message_length;
209         struct nlmsghdr *new_hdr;
210         struct rtattr *rta;
211         char *padding;
212
213         assert_return(m, -EINVAL);
214         assert_return(m->hdr, -EINVAL);
215         assert_return(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len, -EINVAL);
216         assert_return(data, -EINVAL);
217         assert_return(data_length > 0, -EINVAL);
218
219         /* get the size of the new rta attribute (with padding at the end) */
220         rta_length = RTA_LENGTH(data_length);
221         /* get the new message size (with padding at the end)
222          */
223         message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
224
225         /* realloc to fit the new attribute */
226         new_hdr = realloc(m->hdr, message_length);
227         if (!new_hdr)
228                 return -ENOMEM;
229         m->hdr = new_hdr;
230
231         /* get pointer to the attribute we are about to add */
232         rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
233         /* update message size */
234         m->hdr->nlmsg_len = message_length;
235
236         /* fill in the attribute */
237         rta->rta_type = type;
238         rta->rta_len = rta_length;
239         /* we don't deal with the case where the user lies about the type and gives us
240          * too little data (so don't do that)
241          */
242         padding = mempcpy(RTA_DATA(rta), data, data_length);
243         /* make sure also the padding at the end of the message is initialized */
244         memset(padding, '\0', (unsigned char *) m->hdr + m->hdr->nlmsg_len - (unsigned char *) padding);
245
246         return 0;
247 }
248
249 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
250         uint16_t rtm_type;
251         struct ifaddrmsg *ifa;
252         struct rtmsg *rtm;
253
254         assert_return(m, -EINVAL);
255         assert_return(data, -EINVAL);
256
257         sd_rtnl_message_get_type(m, &rtm_type);
258
259         switch (rtm_type) {
260                 case RTM_NEWLINK:
261                 case RTM_DELLINK:
262                 case RTM_GETLINK:
263                         switch (type) {
264                                 case IFLA_IFNAME:
265                                 case IFLA_QDISC:
266                                         return add_rtattr(m, type, data, strlen(data) + 1);
267                                 case IFLA_MTU:
268                                         return add_rtattr(m, type, data, sizeof(uint32_t));
269                                 case IFLA_LINK:
270                                         return add_rtattr(m, type, data, sizeof(uint32_t));
271                                 case IFLA_STATS:
272                                         return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
273                                 case IFLA_ADDRESS:
274                                 case IFLA_BROADCAST:
275                                         return add_rtattr(m, type, data, ETH_ALEN);
276                                 default:
277                                         return -ENOTSUP;
278                         }
279                 case RTM_NEWADDR:
280                 case RTM_DELADDR:
281                 case RTM_GETADDR:
282                         switch (type) {
283                                 case IFA_LABEL:
284                                         return add_rtattr(m, type, data, strlen(data) + 1);
285                                 case IFA_ADDRESS:
286                                 case IFA_LOCAL:
287                                 case IFA_BROADCAST:
288                                 case IFA_ANYCAST:
289                                         ifa = NLMSG_DATA(m->hdr);
290                                         switch (ifa->ifa_family) {
291                                                 case AF_INET:
292                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
293                                                 case AF_INET6:
294                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
295                                                 default:
296                                                         return -EINVAL;
297                                         }
298                                 default:
299                                         return -ENOTSUP;
300                         }
301                 case RTM_NEWROUTE:
302                 case RTM_DELROUTE:
303                 case RTM_GETROUTE:
304                         switch (type) {
305                                 case RTA_DST:
306                                 case RTA_SRC:
307                                 case RTA_GATEWAY:
308                                         rtm = NLMSG_DATA(m->hdr);
309                                         switch (rtm->rtm_family) {
310                                                 case AF_INET:
311                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
312                                                 case AF_INET6:
313                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
314                                                 default:
315                                                         return -EINVAL;
316                                         }
317                                 case RTA_TABLE:
318                                 case RTA_PRIORITY:
319                                 case RTA_IIF:
320                                 case RTA_OIF:
321                                         return add_rtattr(m, type, data, sizeof(uint32_t));
322                                 default:
323                                         return -ENOTSUP;
324                         }
325                 default:
326                         return -ENOTSUP;
327         }
328 }
329
330 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
331         assert_return(m, -EINVAL);
332         assert_return(data, -EINVAL);
333
334         if (!RTA_OK(m->next_rta, m->remaining_size))
335                 return 0;
336
337         *data = RTA_DATA(m->next_rta);
338         *type = m->next_rta->rta_type;
339
340         m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
341
342         return 1;
343 }
344
345 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
346         uint16_t rtm_type;
347
348         assert_return(m, -EINVAL);
349         assert_return(data, -EINVAL);
350
351         sd_rtnl_message_get_type(m, &rtm_type);
352
353         switch (rtm_type) {
354                 case RTM_NEWLINK:
355                 case RTM_DELLINK:
356                 case RTM_GETLINK:
357                         if (!m->next_rta) {
358                                 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
359
360                                 m->next_rta = IFLA_RTA(ifi);
361                                 m->remaining_size = IFLA_PAYLOAD(m->hdr);
362                         }
363                         break;
364                 case RTM_NEWADDR:
365                 case RTM_DELADDR:
366                 case RTM_GETADDR:
367                         if (!m->next_rta) {
368                                 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
369
370                                 m->next_rta = IFA_RTA(ifa);
371                                 m->remaining_size = IFA_PAYLOAD(m->hdr);
372                         }
373                         break;
374                 case RTM_NEWROUTE:
375                 case RTM_DELROUTE:
376                 case RTM_GETROUTE:
377                         if (!m->next_rta) {
378                                 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
379
380                                 m->next_rta = RTM_RTA(rtm);
381                                 m->remaining_size = RTM_PAYLOAD(m->hdr);
382                         }
383                         break;
384                 default:
385                         return -ENOTSUP;
386         }
387
388         return message_read(m, type, data);
389 }
390
391 uint32_t message_get_serial(sd_rtnl_message *m) {
392         assert(m);
393
394         return m->hdr->nlmsg_seq;
395 }
396
397 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
398         struct nlmsgerr *err;
399
400         assert_return(m, -EINVAL);
401
402         if (m->hdr->nlmsg_type != NLMSG_ERROR)
403                 return 0;
404
405         err = NLMSG_DATA(m->hdr);
406
407         return err->error;
408 }
409
410 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
411         if (m->sealed)
412                 return -EPERM;
413
414         m->hdr->nlmsg_seq = nl->serial++;
415         m->sealed = true;
416
417         return 0;
418 }
419
420 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
421         assert_return(rtnl, -EINVAL);
422         assert_return(need, -EINVAL);
423
424         /* ioctl(rtnl->fd, FIONREAD, &need)
425            Does not appear to work on netlink sockets. libnl uses
426            MSG_PEEK instead. I don't know if that is worth the
427            extra roundtrip.
428
429            For now we simply use the maximum message size the kernel
430            may use (NLMSG_GOODSIZE), and then realloc to the actual
431            size after reading the message (hence avoiding huge memory
432            usage in case many small messages are kept around) */
433         *need = page_size();
434         if (*need > 8192UL)
435                 *need = 8192UL;
436
437         return 0;
438 }
439
440 /* returns the number of bytes sent, or a negative error code */
441 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
442         union {
443                 struct sockaddr sa;
444                 struct sockaddr_nl nl;
445         } addr = {
446                 .nl.nl_family = AF_NETLINK,
447         };
448         ssize_t k;
449
450         assert_return(nl, -EINVAL);
451         assert_return(m, -EINVAL);
452
453         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
454                         0, &addr.sa, sizeof(addr));
455         if (k < 0)
456                 return (errno == EAGAIN) ? 0 : -errno;
457
458         return k;
459 }
460
461 /* On success, the number of bytes received is returned and *ret points to the received message
462  * which has a valid header and the correct size.
463  * If nothing useful was received 0 is returned.
464  * On failure, a negative error code is returned.
465  */
466 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
467         sd_rtnl_message *m;
468         union {
469                 struct sockaddr sa;
470                 struct sockaddr_nl nl;
471         } addr;
472         socklen_t addr_len;
473         int r;
474         ssize_t k;
475         size_t need;
476
477         assert_return(nl, -EINVAL);
478         assert_return(ret, -EINVAL);
479
480         r = message_receive_need(nl, &need);
481         if (r < 0)
482                 return r;
483
484         r = message_new(&m, need);
485         if (r < 0)
486                 return r;
487
488         addr_len = sizeof(addr);
489
490         k = recvfrom(nl->fd, m->hdr, need,
491                         0, &addr.sa, &addr_len);
492         if (k < 0)
493                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
494         else if (k == 0)
495                 k = -ECONNRESET; /* connection was closed by the kernel */
496         else if (addr_len != sizeof(addr.nl) ||
497                         addr.nl.nl_family != AF_NETLINK)
498                 k = -EIO; /* not a netlink message */
499         else if (addr.nl.nl_pid != 0)
500                 k = 0; /* not from the kernel */
501         else if ((size_t) k < sizeof(struct nlmsghdr) ||
502                         (size_t) k < m->hdr->nlmsg_len)
503                 k = -EIO; /* too small (we do accept too big though) */
504         else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
505                 k = 0; /* not for us */
506
507         if (k > 0)
508                 switch (m->hdr->nlmsg_type) {
509                         /* check that the size matches the message type */
510                         case NLMSG_ERROR:
511                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
512                                         k = -EIO;
513                                 break;
514                         case RTM_NEWLINK:
515                         case RTM_DELLINK:
516                         case RTM_GETLINK:
517                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
518                                         k = -EIO;
519                                 break;
520                         case RTM_NEWADDR:
521                         case RTM_DELADDR:
522                         case RTM_GETADDR:
523                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
524                                         k = -EIO;
525                                 break;
526                         case NLMSG_NOOP:
527                                 k = 0;
528                                 break;
529                         default:
530                                 k = 0; /* ignoring message of unknown type */
531                 }
532
533         if (k <= 0)
534                 sd_rtnl_message_unref(m);
535         else {
536                 /* we probably allocated way too much memory, give it back */
537                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
538                 *ret = m;
539         }
540
541         return k;
542 }