1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "sd-netlink.h"
4 
5 #include "format-util.h"
6 #include "memory-util.h"
7 #include "netlink-internal.h"
8 #include "netlink-util.h"
9 #include "parse-util.h"
10 #include "strv.h"
11 
rtnl_set_link_name(sd_netlink ** rtnl,int ifindex,const char * name)12 int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
13         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
14         _cleanup_strv_free_ char **alternative_names = NULL;
15         char old_name[IF_NAMESIZE] = {};
16         int r;
17 
18         assert(rtnl);
19         assert(ifindex > 0);
20         assert(name);
21 
22         if (!ifname_valid(name))
23                 return -EINVAL;
24 
25         r = rtnl_get_link_alternative_names(rtnl, ifindex, &alternative_names);
26         if (r < 0)
27                 log_debug_errno(r, "Failed to get alternative names on network interface %i, ignoring: %m",
28                                 ifindex);
29 
30         if (strv_contains(alternative_names, name)) {
31                 r = rtnl_delete_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
32                 if (r < 0)
33                         return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
34                                                name, ifindex);
35 
36                 r = format_ifname(ifindex, old_name);
37                 if (r < 0)
38                         return log_debug_errno(r, "Failed to get current name of network interface %i: %m", ifindex);
39         }
40 
41         r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
42         if (r < 0)
43                 return r;
44 
45         r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
46         if (r < 0)
47                 return r;
48 
49         r = sd_netlink_call(*rtnl, message, 0, NULL);
50         if (r < 0)
51                 return r;
52 
53         if (!isempty(old_name)) {
54                 r = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(old_name));
55                 if (r < 0)
56                         log_debug_errno(r, "Failed to set '%s' as an alternative name on network interface %i, ignoring: %m",
57                                         old_name, ifindex);
58         }
59 
60         return 0;
61 }
62 
rtnl_set_link_properties(sd_netlink ** rtnl,int ifindex,const char * alias,const struct hw_addr_data * hw_addr,uint32_t txqueues,uint32_t rxqueues,uint32_t txqueuelen,uint32_t mtu,uint32_t gso_max_size,size_t gso_max_segments)63 int rtnl_set_link_properties(
64                 sd_netlink **rtnl,
65                 int ifindex,
66                 const char *alias,
67                 const struct hw_addr_data *hw_addr,
68                 uint32_t txqueues,
69                 uint32_t rxqueues,
70                 uint32_t txqueuelen,
71                 uint32_t mtu,
72                 uint32_t gso_max_size,
73                 size_t gso_max_segments) {
74         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
75         int r;
76 
77         assert(rtnl);
78         assert(ifindex > 0);
79 
80         if (!alias &&
81             (!hw_addr || hw_addr->length == 0) &&
82             txqueues == 0 &&
83             rxqueues == 0 &&
84             txqueuelen == UINT32_MAX &&
85             mtu == 0 &&
86             gso_max_size == 0 &&
87             gso_max_segments == 0)
88                 return 0;
89 
90         if (!*rtnl) {
91                 r = sd_netlink_open(rtnl);
92                 if (r < 0)
93                         return r;
94         }
95 
96         r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
97         if (r < 0)
98                 return r;
99 
100         if (alias) {
101                 r = sd_netlink_message_append_string(message, IFLA_IFALIAS, alias);
102                 if (r < 0)
103                         return r;
104         }
105 
106         if (hw_addr && hw_addr->length > 0) {
107                 r = netlink_message_append_hw_addr(message, IFLA_ADDRESS, hw_addr);
108                 if (r < 0)
109                         return r;
110         }
111 
112         if (txqueues > 0) {
113                 r = sd_netlink_message_append_u32(message, IFLA_NUM_TX_QUEUES, txqueues);
114                 if (r < 0)
115                         return r;
116         }
117 
118         if (rxqueues > 0) {
119                 r = sd_netlink_message_append_u32(message, IFLA_NUM_RX_QUEUES, rxqueues);
120                 if (r < 0)
121                         return r;
122         }
123 
124         if (txqueuelen < UINT32_MAX) {
125                 r = sd_netlink_message_append_u32(message, IFLA_TXQLEN, txqueuelen);
126                 if (r < 0)
127                         return r;
128         }
129 
130         if (mtu != 0) {
131                 r = sd_netlink_message_append_u32(message, IFLA_MTU, mtu);
132                 if (r < 0)
133                         return r;
134         }
135 
136         if (gso_max_size > 0) {
137                 r = sd_netlink_message_append_u32(message, IFLA_GSO_MAX_SIZE, gso_max_size);
138                 if (r < 0)
139                         return r;
140         }
141 
142         if (gso_max_segments > 0) {
143                 r = sd_netlink_message_append_u32(message, IFLA_GSO_MAX_SEGS, gso_max_segments);
144                 if (r < 0)
145                         return r;
146         }
147 
148         r = sd_netlink_call(*rtnl, message, 0, NULL);
149         if (r < 0)
150                 return r;
151 
152         return 0;
153 }
154 
rtnl_get_link_alternative_names(sd_netlink ** rtnl,int ifindex,char *** ret)155 int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret) {
156         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
157         _cleanup_strv_free_ char **names = NULL;
158         int r;
159 
160         assert(rtnl);
161         assert(ifindex > 0);
162         assert(ret);
163 
164         if (!*rtnl) {
165                 r = sd_netlink_open(rtnl);
166                 if (r < 0)
167                         return r;
168         }
169 
170         r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
171         if (r < 0)
172                 return r;
173 
174         r = sd_netlink_call(*rtnl, message, 0, &reply);
175         if (r < 0)
176                 return r;
177 
178         r = sd_netlink_message_read_strv(reply, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &names);
179         if (r < 0 && r != -ENODATA)
180                 return r;
181 
182         *ret = TAKE_PTR(names);
183 
184         return 0;
185 }
186 
rtnl_update_link_alternative_names(sd_netlink ** rtnl,uint16_t nlmsg_type,int ifindex,char * const * alternative_names)187 static int rtnl_update_link_alternative_names(sd_netlink **rtnl, uint16_t nlmsg_type, int ifindex, char * const *alternative_names) {
188         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
189         int r;
190 
191         assert(rtnl);
192         assert(ifindex > 0);
193         assert(IN_SET(nlmsg_type, RTM_NEWLINKPROP, RTM_DELLINKPROP));
194 
195         if (strv_isempty(alternative_names))
196                 return 0;
197 
198         if (!*rtnl) {
199                 r = sd_netlink_open(rtnl);
200                 if (r < 0)
201                         return r;
202         }
203 
204         r = sd_rtnl_message_new_link(*rtnl, &message, nlmsg_type, ifindex);
205         if (r < 0)
206                 return r;
207 
208         r = sd_netlink_message_open_container(message, IFLA_PROP_LIST);
209         if (r < 0)
210                 return r;
211 
212         r = sd_netlink_message_append_strv(message, IFLA_ALT_IFNAME, alternative_names);
213         if (r < 0)
214                 return r;
215 
216         r = sd_netlink_message_close_container(message);
217         if (r < 0)
218                 return r;
219 
220         r = sd_netlink_call(*rtnl, message, 0, NULL);
221         if (r < 0)
222                 return r;
223 
224         return 0;
225 }
226 
rtnl_set_link_alternative_names(sd_netlink ** rtnl,int ifindex,char * const * alternative_names)227 int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names) {
228         return rtnl_update_link_alternative_names(rtnl, RTM_NEWLINKPROP, ifindex, alternative_names);
229 }
230 
rtnl_delete_link_alternative_names(sd_netlink ** rtnl,int ifindex,char * const * alternative_names)231 int rtnl_delete_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names) {
232         return rtnl_update_link_alternative_names(rtnl, RTM_DELLINKPROP, ifindex, alternative_names);
233 }
234 
rtnl_set_link_alternative_names_by_ifname(sd_netlink ** rtnl,const char * ifname,char * const * alternative_names)235 int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char * const *alternative_names) {
236         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
237         int r;
238 
239         assert(rtnl);
240         assert(ifname);
241 
242         if (strv_isempty(alternative_names))
243                 return 0;
244 
245         if (!*rtnl) {
246                 r = sd_netlink_open(rtnl);
247                 if (r < 0)
248                         return r;
249         }
250 
251         r = sd_rtnl_message_new_link(*rtnl, &message, RTM_NEWLINKPROP, 0);
252         if (r < 0)
253                 return r;
254 
255         r = sd_netlink_message_append_string(message, IFLA_IFNAME, ifname);
256         if (r < 0)
257                 return r;
258 
259         r = sd_netlink_message_open_container(message, IFLA_PROP_LIST);
260         if (r < 0)
261                 return r;
262 
263         r = sd_netlink_message_append_strv(message, IFLA_ALT_IFNAME, alternative_names);
264         if (r < 0)
265                 return r;
266 
267         r = sd_netlink_message_close_container(message);
268         if (r < 0)
269                 return r;
270 
271         r = sd_netlink_call(*rtnl, message, 0, NULL);
272         if (r < 0)
273                 return r;
274 
275         return 0;
276 }
277 
rtnl_resolve_link_alternative_name(sd_netlink ** rtnl,const char * name,char ** ret)278 int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, char **ret) {
279         _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
280         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
281         int r, ifindex;
282 
283         assert(name);
284 
285         /* This returns ifindex and the main interface name. */
286 
287         if (!ifname_valid_full(name, IFNAME_VALID_ALTERNATIVE))
288                 return -EINVAL;
289 
290         if (!rtnl)
291                 rtnl = &our_rtnl;
292         if (!*rtnl) {
293                 r = sd_netlink_open(rtnl);
294                 if (r < 0)
295                         return r;
296         }
297 
298         r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, 0);
299         if (r < 0)
300                 return r;
301 
302         r = sd_netlink_message_append_string(message, IFLA_ALT_IFNAME, name);
303         if (r < 0)
304                 return r;
305 
306         r = sd_netlink_call(*rtnl, message, 0, &reply);
307         if (r == -EINVAL)
308                 return -ENODEV; /* The device doesn't exist */
309         if (r < 0)
310                 return r;
311 
312         r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
313         if (r < 0)
314                 return r;
315         assert(ifindex > 0);
316 
317         if (ret) {
318                 r = sd_netlink_message_read_string_strdup(message, IFLA_IFNAME, ret);
319                 if (r < 0)
320                         return r;
321         }
322 
323         return ifindex;
324 }
325 
rtnl_resolve_ifname(sd_netlink ** rtnl,const char * name)326 int rtnl_resolve_ifname(sd_netlink **rtnl, const char *name) {
327         int r;
328 
329         /* Like if_nametoindex, but resolves "alternative names" too. */
330 
331         assert(name);
332 
333         r = if_nametoindex(name);
334         if (r > 0)
335                 return r;
336 
337         return rtnl_resolve_link_alternative_name(rtnl, name, NULL);
338 }
339 
rtnl_resolve_interface(sd_netlink ** rtnl,const char * name)340 int rtnl_resolve_interface(sd_netlink **rtnl, const char *name) {
341         int r;
342 
343         /* Like rtnl_resolve_ifname, but resolves interface numbers too. */
344 
345         assert(name);
346 
347         r = parse_ifindex(name);
348         if (r > 0)
349                 return r;
350         assert(r < 0);
351 
352         return rtnl_resolve_ifname(rtnl, name);
353 }
354 
rtnl_resolve_interface_or_warn(sd_netlink ** rtnl,const char * name)355 int rtnl_resolve_interface_or_warn(sd_netlink **rtnl, const char *name) {
356         int r;
357 
358         r = rtnl_resolve_interface(rtnl, name);
359         if (r < 0)
360                 return log_error_errno(r, "Failed to resolve interface \"%s\": %m", name);
361         return r;
362 }
363 
rtnl_get_link_info(sd_netlink ** rtnl,int ifindex,unsigned short * ret_iftype,unsigned * ret_flags,char ** ret_kind,struct hw_addr_data * ret_hw_addr,struct hw_addr_data * ret_permanent_hw_addr)364 int rtnl_get_link_info(
365                 sd_netlink **rtnl,
366                 int ifindex,
367                 unsigned short *ret_iftype,
368                 unsigned *ret_flags,
369                 char **ret_kind,
370                 struct hw_addr_data *ret_hw_addr,
371                 struct hw_addr_data *ret_permanent_hw_addr) {
372 
373         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
374         struct hw_addr_data addr = HW_ADDR_NULL, perm_addr = HW_ADDR_NULL;
375         _cleanup_free_ char *kind = NULL;
376         unsigned short iftype;
377         unsigned flags;
378         int r;
379 
380         assert(rtnl);
381         assert(ifindex > 0);
382 
383         if (!ret_iftype && !ret_flags)
384                 return 0;
385 
386         if (!*rtnl) {
387                 r = sd_netlink_open(rtnl);
388                 if (r < 0)
389                         return r;
390         }
391 
392         r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
393         if (r < 0)
394                 return r;
395 
396         r = sd_netlink_call(*rtnl, message, 0, &reply);
397         if (r == -EINVAL)
398                 return -ENODEV; /* The device does not exist */
399         if (r < 0)
400                 return r;
401 
402         if (ret_iftype) {
403                 r = sd_rtnl_message_link_get_type(reply, &iftype);
404                 if (r < 0)
405                         return r;
406         }
407 
408         if (ret_flags) {
409                 r = sd_rtnl_message_link_get_flags(reply, &flags);
410                 if (r < 0)
411                         return r;
412         }
413 
414         if (ret_kind) {
415                 r = sd_netlink_message_enter_container(reply, IFLA_LINKINFO);
416                 if (r >= 0) {
417                         r = sd_netlink_message_read_string_strdup(reply, IFLA_INFO_KIND, &kind);
418                         if (r < 0 && r != -ENODATA)
419                                 return r;
420 
421                         r = sd_netlink_message_exit_container(reply);
422                         if (r < 0)
423                                 return r;
424                 }
425         }
426 
427         if (ret_hw_addr) {
428                 r = netlink_message_read_hw_addr(reply, IFLA_ADDRESS, &addr);
429                 if (r < 0 && r != -ENODATA)
430                         return r;
431         }
432 
433         if (ret_permanent_hw_addr) {
434                 r = netlink_message_read_hw_addr(reply, IFLA_PERM_ADDRESS, &perm_addr);
435                 if (r < 0 && r != -ENODATA)
436                         return r;
437         }
438 
439         if (ret_iftype)
440                 *ret_iftype = iftype;
441         if (ret_flags)
442                 *ret_flags = flags;
443         if (ret_kind)
444                 *ret_kind = TAKE_PTR(kind);
445         if (ret_hw_addr)
446                 *ret_hw_addr = addr;
447         if (ret_permanent_hw_addr)
448                 *ret_permanent_hw_addr = perm_addr;
449         return 0;
450 }
451 
rtnl_log_parse_error(int r)452 int rtnl_log_parse_error(int r) {
453         return log_error_errno(r, "Failed to parse netlink message: %m");
454 }
455 
rtnl_log_create_error(int r)456 int rtnl_log_create_error(int r) {
457         return log_error_errno(r, "Failed to create netlink message: %m");
458 }
459 
rtattr_append_attribute_internal(struct rtattr * rta,unsigned short type,const void * data,size_t data_length)460 void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length) {
461         size_t padding_length;
462         uint8_t *padding;
463 
464         assert(rta);
465         assert(!data || data_length > 0);
466 
467         /* fill in the attribute */
468         rta->rta_type = type;
469         rta->rta_len = RTA_LENGTH(data_length);
470         if (data)
471                 /* we don't deal with the case where the user lies about the type
472                  * and gives us too little data (so don't do that)
473                  */
474                 padding = mempcpy(RTA_DATA(rta), data, data_length);
475 
476         else
477                 /* if no data was passed, make sure we still initialize the padding
478                    note that we can have data_length > 0 (used by some containers) */
479                 padding = RTA_DATA(rta);
480 
481         /* make sure also the padding at the end of the message is initialized */
482         padding_length = (uint8_t *) rta + RTA_SPACE(data_length) - padding;
483         memzero(padding, padding_length);
484 }
485 
rtattr_append_attribute(struct rtattr ** rta,unsigned short type,const void * data,size_t data_length)486 int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void *data, size_t data_length) {
487         struct rtattr *new_rta, *sub_rta;
488         size_t message_length;
489 
490         assert(rta);
491         assert(!data || data_length > 0);
492 
493         /* get the new message size (with padding at the end) */
494         message_length = RTA_ALIGN(rta ? (*rta)->rta_len : 0) + RTA_SPACE(data_length);
495 
496         /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
497         if (message_length > MIN(page_size(), 8192UL))
498                 return -ENOBUFS;
499 
500         /* realloc to fit the new attribute */
501         new_rta = realloc(*rta, message_length);
502         if (!new_rta)
503                 return -ENOMEM;
504         *rta = new_rta;
505 
506         /* get pointer to the attribute we are about to add */
507         sub_rta = (struct rtattr *) ((uint8_t *) *rta + RTA_ALIGN((*rta)->rta_len));
508 
509         rtattr_append_attribute_internal(sub_rta, type, data, data_length);
510 
511         /* update rta_len */
512         (*rta)->rta_len = message_length;
513 
514         return 0;
515 }
516 
multipath_route_free(MultipathRoute * m)517 MultipathRoute *multipath_route_free(MultipathRoute *m) {
518         if (!m)
519                 return NULL;
520 
521         free(m->ifname);
522 
523         return mfree(m);
524 }
525 
multipath_route_dup(const MultipathRoute * m,MultipathRoute ** ret)526 int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret) {
527         _cleanup_(multipath_route_freep) MultipathRoute *n = NULL;
528         _cleanup_free_ char *ifname = NULL;
529 
530         assert(m);
531         assert(ret);
532 
533         if (m->ifname) {
534                 ifname = strdup(m->ifname);
535                 if (!ifname)
536                         return -ENOMEM;
537         }
538 
539         n = new(MultipathRoute, 1);
540         if (!n)
541                 return -ENOMEM;
542 
543         *n = (MultipathRoute) {
544                 .gateway = m->gateway,
545                 .weight = m->weight,
546                 .ifindex = m->ifindex,
547                 .ifname = TAKE_PTR(ifname),
548         };
549 
550         *ret = TAKE_PTR(n);
551 
552         return 0;
553 }
554 
rtattr_read_nexthop(const struct rtnexthop * rtnh,size_t size,int family,OrderedSet ** ret)555 int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret) {
556         _cleanup_ordered_set_free_free_ OrderedSet *set = NULL;
557         int r;
558 
559         assert(rtnh);
560         assert(IN_SET(family, AF_INET, AF_INET6));
561 
562         if (size < sizeof(struct rtnexthop))
563                 return -EBADMSG;
564 
565         for (; size >= sizeof(struct rtnexthop); ) {
566                 _cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
567 
568                 if (NLMSG_ALIGN(rtnh->rtnh_len) > size)
569                         return -EBADMSG;
570 
571                 if (rtnh->rtnh_len < sizeof(struct rtnexthop))
572                         return -EBADMSG;
573 
574                 m = new(MultipathRoute, 1);
575                 if (!m)
576                         return -ENOMEM;
577 
578                 *m = (MultipathRoute) {
579                         .ifindex = rtnh->rtnh_ifindex,
580                         .weight = rtnh->rtnh_hops,
581                 };
582 
583                 if (rtnh->rtnh_len > sizeof(struct rtnexthop)) {
584                         size_t len = rtnh->rtnh_len - sizeof(struct rtnexthop);
585 
586                         for (struct rtattr *attr = RTNH_DATA(rtnh); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
587                                 if (attr->rta_type == RTA_GATEWAY) {
588                                         if (attr->rta_len != RTA_LENGTH(FAMILY_ADDRESS_SIZE(family)))
589                                                 return -EBADMSG;
590 
591                                         m->gateway.family = family;
592                                         memcpy(&m->gateway.address, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(family));
593                                         break;
594                                 } else if (attr->rta_type == RTA_VIA) {
595                                         uint16_t gw_family;
596 
597                                         if (family != AF_INET)
598                                                 return -EINVAL;
599 
600                                         if (attr->rta_len < RTA_LENGTH(sizeof(uint16_t)))
601                                                 return -EBADMSG;
602 
603                                         gw_family = *(uint16_t *) RTA_DATA(attr);
604 
605                                         if (gw_family != AF_INET6)
606                                                 return -EBADMSG;
607 
608                                         if (attr->rta_len != RTA_LENGTH(FAMILY_ADDRESS_SIZE(gw_family) + sizeof(gw_family)))
609                                                 return -EBADMSG;
610 
611                                         memcpy(&m->gateway, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(gw_family) + sizeof(gw_family));
612                                         break;
613                                 }
614                         }
615                 }
616 
617                 r = ordered_set_ensure_put(&set, NULL, m);
618                 if (r < 0)
619                         return r;
620 
621                 TAKE_PTR(m);
622 
623                 size -= NLMSG_ALIGN(rtnh->rtnh_len);
624                 rtnh = RTNH_NEXT(rtnh);
625         }
626 
627         if (ret)
628                 *ret = TAKE_PTR(set);
629         return 0;
630 }
631