LCOV - code coverage report
Current view: top level - libsystemd-network - network-internal.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 214 414 51.7 %
Date: 2019-08-22 15:41:25 Functions: 10 20 50.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <arpa/inet.h>
       4             : #include <linux/if.h>
       5             : #include <netinet/ether.h>
       6             : 
       7             : #include "sd-id128.h"
       8             : #include "sd-ndisc.h"
       9             : 
      10             : #include "alloc-util.h"
      11             : #include "condition.h"
      12             : #include "conf-parser.h"
      13             : #include "device-util.h"
      14             : #include "dhcp-lease-internal.h"
      15             : #include "env-util.h"
      16             : #include "ether-addr-util.h"
      17             : #include "hexdecoct.h"
      18             : #include "log.h"
      19             : #include "network-internal.h"
      20             : #include "parse-util.h"
      21             : #include "siphash24.h"
      22             : #include "socket-util.h"
      23             : #include "string-util.h"
      24             : #include "strv.h"
      25             : #include "utf8.h"
      26             : #include "util.h"
      27             : 
      28           0 : const char *net_get_name_persistent(sd_device *device) {
      29             :         const char *name, *field;
      30             : 
      31           0 :         assert(device);
      32             : 
      33             :         /* fetch some persistent data unique (on this machine) to this device */
      34           0 :         FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC")
      35           0 :                 if (sd_device_get_property_value(device, field, &name) >= 0)
      36           0 :                         return name;
      37             : 
      38           0 :         return NULL;
      39             : }
      40             : 
      41             : #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
      42             : 
      43           0 : int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) {
      44           0 :         size_t l, sz = 0;
      45             :         const char *name;
      46             :         int r;
      47             :         uint8_t *v;
      48             : 
      49           0 :         assert(device);
      50             : 
      51             :         /* net_get_name_persistent() will return one of the device names based on stable information about
      52             :          * the device. If this is not available, we fall back to using the actual device name. */
      53           0 :         name = net_get_name_persistent(device);
      54           0 :         if (!name && use_sysname)
      55           0 :                 (void) sd_device_get_sysname(device, &name);
      56           0 :         if (!name)
      57           0 :                 return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
      58             :                                               "No stable identifying information found");
      59             : 
      60           0 :         log_device_debug(device, "Using \"%s\" as stable identifying information", name);
      61           0 :         l = strlen(name);
      62           0 :         sz = sizeof(sd_id128_t) + l;
      63           0 :         v = newa(uint8_t, sz);
      64             : 
      65             :         /* Fetch some persistent data unique to this machine */
      66           0 :         r = sd_id128_get_machine((sd_id128_t*) v);
      67           0 :         if (r < 0)
      68           0 :                  return r;
      69           0 :         memcpy(v + sizeof(sd_id128_t), name, l);
      70             : 
      71             :         /* Let's hash the machine ID plus the device name. We use
      72             :          * a fixed, but originally randomly created hash key here. */
      73           0 :         *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
      74           0 :         return 0;
      75             : }
      76             : 
      77           4 : static bool net_condition_test_strv(char * const *patterns, const char *string) {
      78             :         char * const *p;
      79           4 :         bool match = false, has_positive_rule = false;
      80             : 
      81           4 :         if (strv_isempty(patterns))
      82           2 :                 return true;
      83             : 
      84           4 :         STRV_FOREACH(p, patterns) {
      85           2 :                 const char *q = *p;
      86             :                 bool invert;
      87             : 
      88           2 :                 invert = *q == '!';
      89           2 :                 q += invert;
      90             : 
      91           2 :                 if (!invert)
      92           2 :                         has_positive_rule = true;
      93             : 
      94           2 :                 if (string && fnmatch(q, string, 0) == 0) {
      95           0 :                         if (invert)
      96           0 :                                 return false;
      97             :                         else
      98           0 :                                 match = true;
      99             :                 }
     100             :         }
     101             : 
     102           2 :         return has_positive_rule ? match : true;
     103             : }
     104             : 
     105           0 : static int net_condition_test_property(char * const *match_property, sd_device *device) {
     106             :         char * const *p;
     107             : 
     108           0 :         if (strv_isempty(match_property))
     109           0 :                 return true;
     110             : 
     111           0 :         STRV_FOREACH(p, match_property) {
     112           0 :                 _cleanup_free_ char *key = NULL;
     113             :                 const char *val, *dev_val;
     114             :                 bool invert, v;
     115             : 
     116           0 :                 invert = **p == '!';
     117             : 
     118           0 :                 val = strchr(*p + invert, '=');
     119           0 :                 if (!val)
     120           0 :                         return -EINVAL;
     121             : 
     122           0 :                 key = strndup(*p + invert, val - *p - invert);
     123           0 :                 if (!key)
     124           0 :                         return -ENOMEM;
     125             : 
     126           0 :                 val++;
     127             : 
     128           0 :                 v = device &&
     129           0 :                         sd_device_get_property_value(device, key, &dev_val) >= 0 &&
     130           0 :                         fnmatch(val, dev_val, 0) == 0;
     131             : 
     132           0 :                 if (invert ? v : !v)
     133           0 :                         return false;
     134             :         }
     135             : 
     136           0 :         return true;
     137             : }
     138             : 
     139           2 : bool net_match_config(Set *match_mac,
     140             :                       char * const *match_paths,
     141             :                       char * const *match_drivers,
     142             :                       char * const *match_types,
     143             :                       char * const *match_names,
     144             :                       char * const *match_property,
     145             :                       sd_device *device,
     146             :                       const struct ether_addr *dev_mac,
     147             :                       const char *dev_name) {
     148             : 
     149           2 :         const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
     150             : 
     151           2 :         if (device) {
     152           2 :                 (void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
     153           2 :                 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
     154           2 :                 (void) sd_device_get_devtype(device, &dev_type);
     155             : 
     156           2 :                 if (!dev_name)
     157           0 :                         (void) sd_device_get_sysname(device, &dev_name);
     158           2 :                 if (!dev_mac &&
     159           0 :                     sd_device_get_sysattr_value(device, "address", &mac_str) >= 0)
     160           0 :                         dev_mac = ether_aton(mac_str);
     161             :         }
     162             : 
     163           2 :         if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
     164           0 :                 return false;
     165             : 
     166           2 :         if (!net_condition_test_strv(match_paths, dev_path))
     167           0 :                 return false;
     168             : 
     169           2 :         if (!net_condition_test_strv(match_drivers, dev_driver))
     170           2 :                 return false;
     171             : 
     172           0 :         if (!net_condition_test_strv(match_types, dev_type))
     173           0 :                 return false;
     174             : 
     175           0 :         if (!net_condition_test_strv(match_names, dev_name))
     176           0 :                 return false;
     177             : 
     178           0 :         if (!net_condition_test_property(match_property, device))
     179           0 :                 return false;
     180             : 
     181           0 :         return true;
     182             : }
     183             : 
     184           1 : int config_parse_net_condition(const char *unit,
     185             :                                const char *filename,
     186             :                                unsigned line,
     187             :                                const char *section,
     188             :                                unsigned section_line,
     189             :                                const char *lvalue,
     190             :                                int ltype,
     191             :                                const char *rvalue,
     192             :                                void *data,
     193             :                                void *userdata) {
     194             : 
     195           1 :         ConditionType cond = ltype;
     196           1 :         Condition **list = data, *c;
     197             :         bool negate;
     198             : 
     199           1 :         assert(filename);
     200           1 :         assert(lvalue);
     201           1 :         assert(rvalue);
     202           1 :         assert(data);
     203             : 
     204           1 :         if (isempty(rvalue)) {
     205           0 :                 *list = condition_free_list_type(*list, cond);
     206           0 :                 return 0;
     207             :         }
     208             : 
     209           1 :         negate = rvalue[0] == '!';
     210           1 :         if (negate)
     211           0 :                 rvalue++;
     212             : 
     213           1 :         c = condition_new(cond, rvalue, false, negate);
     214           1 :         if (!c)
     215           0 :                 return log_oom();
     216             : 
     217             :         /* Drop previous assignment. */
     218           1 :         *list = condition_free_list_type(*list, cond);
     219             : 
     220           1 :         LIST_PREPEND(conditions, *list, c);
     221           1 :         return 0;
     222             : }
     223             : 
     224           5 : int config_parse_match_strv(
     225             :                 const char *unit,
     226             :                 const char *filename,
     227             :                 unsigned line,
     228             :                 const char *section,
     229             :                 unsigned section_line,
     230             :                 const char *lvalue,
     231             :                 int ltype,
     232             :                 const char *rvalue,
     233             :                 void *data,
     234             :                 void *userdata) {
     235             : 
     236           5 :         const char *p = rvalue;
     237           5 :         char ***sv = data;
     238             :         bool invert;
     239             :         int r;
     240             : 
     241           5 :         assert(filename);
     242           5 :         assert(lvalue);
     243           5 :         assert(rvalue);
     244           5 :         assert(data);
     245             : 
     246           5 :         if (isempty(rvalue)) {
     247           0 :                 *sv = strv_free(*sv);
     248           0 :                 return 0;
     249             :         }
     250             : 
     251           5 :         invert = *p == '!';
     252           5 :         p += invert;
     253             : 
     254           9 :         for (;;) {
     255          19 :                 _cleanup_free_ char *word = NULL, *k = NULL;
     256             : 
     257          14 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
     258          14 :                 if (r == 0)
     259           5 :                         return 0;
     260           9 :                 if (r == -ENOMEM)
     261           0 :                         return log_oom();
     262           9 :                 if (r < 0) {
     263           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
     264           0 :                         return 0;
     265             :                 }
     266             : 
     267           9 :                 if (invert) {
     268           4 :                         k = strjoin("!", word);
     269           4 :                         if (!k)
     270           0 :                                 return log_oom();
     271             :                 } else
     272           5 :                         k = TAKE_PTR(word);
     273             : 
     274           9 :                 r = strv_consume(sv, TAKE_PTR(k));
     275           9 :                 if (r < 0)
     276           0 :                         return log_oom();
     277             :         }
     278             : }
     279             : 
     280          29 : int config_parse_match_ifnames(
     281             :                 const char *unit,
     282             :                 const char *filename,
     283             :                 unsigned line,
     284             :                 const char *section,
     285             :                 unsigned section_line,
     286             :                 const char *lvalue,
     287             :                 int ltype,
     288             :                 const char *rvalue,
     289             :                 void *data,
     290             :                 void *userdata) {
     291             : 
     292          29 :         const char *p = rvalue;
     293          29 :         char ***sv = data;
     294             :         bool invert;
     295             :         int r;
     296             : 
     297          29 :         assert(filename);
     298          29 :         assert(lvalue);
     299          29 :         assert(rvalue);
     300          29 :         assert(data);
     301             : 
     302          29 :         invert = *p == '!';
     303          29 :         p += invert;
     304             : 
     305          33 :         for (;;) {
     306          91 :                 _cleanup_free_ char *word = NULL, *k = NULL;
     307             : 
     308          62 :                 r = extract_first_word(&p, &word, NULL, 0);
     309          62 :                 if (r == 0)
     310          29 :                         return 0;
     311          33 :                 if (r == -ENOMEM)
     312           0 :                         return log_oom();
     313          33 :                 if (r < 0) {
     314           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     315             :                                    "Failed to parse interface name list: %s", rvalue);
     316           0 :                         return 0;
     317             :                 }
     318             : 
     319          33 :                 if (!ifname_valid(word)) {
     320           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     321             :                                    "Interface name is not valid or too long, ignoring assignment: %s", word);
     322           0 :                         continue;
     323             :                 }
     324             : 
     325          33 :                 if (invert) {
     326           4 :                         k = strjoin("!", word);
     327           4 :                         if (!k)
     328           0 :                                 return log_oom();
     329             :                 } else
     330          29 :                         k = TAKE_PTR(word);
     331             : 
     332          33 :                 r = strv_consume(sv, TAKE_PTR(k));
     333          33 :                 if (r < 0)
     334           0 :                         return log_oom();
     335             :         }
     336             : }
     337             : 
     338           0 : int config_parse_match_property(
     339             :                 const char *unit,
     340             :                 const char *filename,
     341             :                 unsigned line,
     342             :                 const char *section,
     343             :                 unsigned section_line,
     344             :                 const char *lvalue,
     345             :                 int ltype,
     346             :                 const char *rvalue,
     347             :                 void *data,
     348             :                 void *userdata) {
     349             : 
     350           0 :         const char *p = rvalue;
     351           0 :         char ***sv = data;
     352             :         bool invert;
     353             :         int r;
     354             : 
     355           0 :         assert(filename);
     356           0 :         assert(lvalue);
     357           0 :         assert(rvalue);
     358           0 :         assert(data);
     359             : 
     360           0 :         invert = *p == '!';
     361           0 :         p += invert;
     362             : 
     363           0 :         for (;;) {
     364           0 :                 _cleanup_free_ char *word = NULL, *k = NULL;
     365             : 
     366           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
     367           0 :                 if (r == 0)
     368           0 :                         return 0;
     369           0 :                 if (r == -ENOMEM)
     370           0 :                         return log_oom();
     371           0 :                 if (r < 0) {
     372           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     373             :                                    "Invalid syntax, ignoring: %s", rvalue);
     374           0 :                         return 0;
     375             :                 }
     376             : 
     377           0 :                 if (!env_assignment_is_valid(word)) {
     378           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     379             :                                    "Invalid property or value, ignoring assignment: %s", word);
     380           0 :                         continue;
     381             :                 }
     382             : 
     383           0 :                 if (invert) {
     384           0 :                         k = strjoin("!", word);
     385           0 :                         if (!k)
     386           0 :                                 return log_oom();
     387             :                 } else
     388           0 :                         k = TAKE_PTR(word);
     389             : 
     390           0 :                 r = strv_consume(sv, TAKE_PTR(k));
     391           0 :                 if (r < 0)
     392           0 :                         return log_oom();
     393             :         }
     394             : }
     395             : 
     396           0 : int config_parse_ifalias(const char *unit,
     397             :                          const char *filename,
     398             :                          unsigned line,
     399             :                          const char *section,
     400             :                          unsigned section_line,
     401             :                          const char *lvalue,
     402             :                          int ltype,
     403             :                          const char *rvalue,
     404             :                          void *data,
     405             :                          void *userdata) {
     406             : 
     407           0 :         char **s = data;
     408           0 :         _cleanup_free_ char *n = NULL;
     409             : 
     410           0 :         assert(filename);
     411           0 :         assert(lvalue);
     412           0 :         assert(rvalue);
     413           0 :         assert(data);
     414             : 
     415           0 :         n = strdup(rvalue);
     416           0 :         if (!n)
     417           0 :                 return log_oom();
     418             : 
     419           0 :         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
     420           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
     421           0 :                 return 0;
     422             :         }
     423             : 
     424           0 :         if (isempty(n))
     425           0 :                 *s = mfree(*s);
     426             :         else
     427           0 :                 free_and_replace(*s, n);
     428             : 
     429           0 :         return 0;
     430             : }
     431             : 
     432          26 : int config_parse_hwaddr(const char *unit,
     433             :                         const char *filename,
     434             :                         unsigned line,
     435             :                         const char *section,
     436             :                         unsigned section_line,
     437             :                         const char *lvalue,
     438             :                         int ltype,
     439             :                         const char *rvalue,
     440             :                         void *data,
     441             :                         void *userdata) {
     442             : 
     443          26 :         _cleanup_free_ struct ether_addr *n = NULL;
     444          26 :         struct ether_addr **hwaddr = data;
     445             :         int r;
     446             : 
     447          26 :         assert(filename);
     448          26 :         assert(lvalue);
     449          26 :         assert(rvalue);
     450          26 :         assert(data);
     451             : 
     452          26 :         n = new0(struct ether_addr, 1);
     453          26 :         if (!n)
     454           0 :                 return log_oom();
     455             : 
     456          26 :         r = ether_addr_from_string(rvalue, n);
     457          26 :         if (r < 0) {
     458          15 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue);
     459          15 :                 return 0;
     460             :         }
     461             : 
     462          11 :         free_and_replace(*hwaddr, n);
     463             : 
     464          11 :         return 0;
     465             : }
     466             : 
     467          28 : int config_parse_hwaddrs(const char *unit,
     468             :                          const char *filename,
     469             :                          unsigned line,
     470             :                          const char *section,
     471             :                          unsigned section_line,
     472             :                          const char *lvalue,
     473             :                          int ltype,
     474             :                          const char *rvalue,
     475             :                          void *data,
     476             :                          void *userdata) {
     477             : 
     478          28 :         _cleanup_set_free_free_ Set *s = NULL;
     479          28 :         const char *p = rvalue;
     480          28 :         Set **hwaddrs = data;
     481             :         int r;
     482             : 
     483          28 :         assert(filename);
     484          28 :         assert(lvalue);
     485          28 :         assert(rvalue);
     486          28 :         assert(data);
     487             : 
     488          28 :         if (isempty(rvalue)) {
     489             :                 /* Empty assignment resets the list */
     490           1 :                 *hwaddrs = set_free_free(*hwaddrs);
     491           1 :                 return 0;
     492             :         }
     493             : 
     494          27 :         s = set_new(&ether_addr_hash_ops);
     495          27 :         if (!s)
     496           0 :                 return log_oom();
     497             : 
     498          38 :         for (;;) {
     499          65 :                 _cleanup_free_ char *word = NULL;
     500          65 :                 _cleanup_free_ struct ether_addr *n = NULL;
     501             : 
     502          65 :                 r = extract_first_word(&p, &word, NULL, 0);
     503          65 :                 if (r == 0)
     504          27 :                         break;
     505          38 :                 if (r == -ENOMEM)
     506           0 :                         return log_oom();
     507          38 :                 if (r < 0) {
     508           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
     509           0 :                         return 0;
     510             :                 }
     511             : 
     512          38 :                 n = new(struct ether_addr, 1);
     513          38 :                 if (!n)
     514           0 :                         return log_oom();
     515             : 
     516          38 :                 r = ether_addr_from_string(word, n);
     517          38 :                 if (r < 0) {
     518          18 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word);
     519          18 :                         continue;
     520             :                 }
     521             : 
     522          20 :                 r = set_put(s, n);
     523          20 :                 if (r < 0)
     524           0 :                         return log_oom();
     525          20 :                 if (r > 0)
     526          17 :                         n = NULL; /* avoid cleanup */
     527             :         }
     528             : 
     529          27 :         r = set_ensure_allocated(hwaddrs, &ether_addr_hash_ops);
     530          27 :         if (r < 0)
     531           0 :                 return log_oom();
     532             : 
     533          27 :         r = set_move(*hwaddrs, s);
     534          27 :         if (r < 0)
     535           0 :                 return log_oom();
     536             : 
     537          27 :         return 0;
     538             : }
     539             : 
     540           0 : int config_parse_bridge_port_priority(
     541             :                 const char *unit,
     542             :                 const char *filename,
     543             :                 unsigned line,
     544             :                 const char *section,
     545             :                 unsigned section_line,
     546             :                 const char *lvalue,
     547             :                 int ltype,
     548             :                 const char *rvalue,
     549             :                 void *data,
     550             :                 void *userdata) {
     551             : 
     552             :         uint16_t i;
     553             :         int r;
     554             : 
     555           0 :         assert(filename);
     556           0 :         assert(lvalue);
     557           0 :         assert(rvalue);
     558           0 :         assert(data);
     559             : 
     560           0 :         r = safe_atou16(rvalue, &i);
     561           0 :         if (r < 0) {
     562           0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
     563             :                            "Failed to parse bridge port priority, ignoring: %s", rvalue);
     564           0 :                 return 0;
     565             :         }
     566             : 
     567           0 :         if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
     568           0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
     569             :                            "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
     570           0 :                 return 0;
     571             :         }
     572             : 
     573           0 :         *((uint16_t *)data) = i;
     574             : 
     575           0 :         return 0;
     576             : }
     577             : 
     578           0 : size_t serialize_in_addrs(FILE *f,
     579             :                           const struct in_addr *addresses,
     580             :                           size_t size,
     581             :                           bool with_leading_space,
     582             :                           bool (*predicate)(const struct in_addr *addr)) {
     583             :         size_t count;
     584             :         size_t i;
     585             : 
     586           0 :         assert(f);
     587           0 :         assert(addresses);
     588             : 
     589           0 :         count = 0;
     590             : 
     591           0 :         for (i = 0; i < size; i++) {
     592             :                 char sbuf[INET_ADDRSTRLEN];
     593             : 
     594           0 :                 if (predicate && !predicate(&addresses[i]))
     595           0 :                         continue;
     596           0 :                 if (with_leading_space)
     597           0 :                         fputc(' ', f);
     598             :                 else
     599           0 :                         with_leading_space = true;
     600           0 :                 fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
     601           0 :                 count++;
     602             :         }
     603             : 
     604           0 :         return count;
     605             : }
     606             : 
     607           1 : int deserialize_in_addrs(struct in_addr **ret, const char *string) {
     608           1 :         _cleanup_free_ struct in_addr *addresses = NULL;
     609           1 :         int size = 0;
     610             : 
     611           1 :         assert(ret);
     612           1 :         assert(string);
     613             : 
     614           6 :         for (;;) {
     615           7 :                 _cleanup_free_ char *word = NULL;
     616             :                 struct in_addr *new_addresses;
     617             :                 int r;
     618             : 
     619           7 :                 r = extract_first_word(&string, &word, NULL, 0);
     620           7 :                 if (r < 0)
     621           0 :                         return r;
     622           7 :                 if (r == 0)
     623           1 :                         break;
     624             : 
     625           6 :                 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
     626           6 :                 if (!new_addresses)
     627           0 :                         return -ENOMEM;
     628             :                 else
     629           6 :                         addresses = new_addresses;
     630             : 
     631           6 :                 r = inet_pton(AF_INET, word, &(addresses[size]));
     632           6 :                 if (r <= 0)
     633           3 :                         continue;
     634             : 
     635           3 :                 size++;
     636             :         }
     637             : 
     638           1 :         *ret = size > 0 ? TAKE_PTR(addresses) : NULL;
     639             : 
     640           1 :         return size;
     641             : }
     642             : 
     643           0 : void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
     644             :         unsigned i;
     645             : 
     646           0 :         assert(f);
     647           0 :         assert(addresses);
     648           0 :         assert(size);
     649             : 
     650           0 :         for (i = 0; i < size; i++) {
     651             :                 char buffer[INET6_ADDRSTRLEN];
     652             : 
     653           0 :                 fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
     654             : 
     655           0 :                 if (i < size - 1)
     656           0 :                         fputc(' ', f);
     657             :         }
     658           0 : }
     659             : 
     660           1 : int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
     661           1 :         _cleanup_free_ struct in6_addr *addresses = NULL;
     662           1 :         int size = 0;
     663             : 
     664           1 :         assert(ret);
     665           1 :         assert(string);
     666             : 
     667           6 :         for (;;) {
     668           7 :                 _cleanup_free_ char *word = NULL;
     669             :                 struct in6_addr *new_addresses;
     670             :                 int r;
     671             : 
     672           7 :                 r = extract_first_word(&string, &word, NULL, 0);
     673           7 :                 if (r < 0)
     674           0 :                         return r;
     675           7 :                 if (r == 0)
     676           1 :                         break;
     677             : 
     678           6 :                 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
     679           6 :                 if (!new_addresses)
     680           0 :                         return -ENOMEM;
     681             :                 else
     682           6 :                         addresses = new_addresses;
     683             : 
     684           6 :                 r = inet_pton(AF_INET6, word, &(addresses[size]));
     685           6 :                 if (r <= 0)
     686           3 :                         continue;
     687             : 
     688           3 :                 size++;
     689             :         }
     690             : 
     691           1 :         *ret = TAKE_PTR(addresses);
     692             : 
     693           1 :         return size;
     694             : }
     695             : 
     696           0 : void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
     697             :         unsigned i;
     698             : 
     699           0 :         assert(f);
     700           0 :         assert(key);
     701           0 :         assert(routes);
     702           0 :         assert(size);
     703             : 
     704           0 :         fprintf(f, "%s=", key);
     705             : 
     706           0 :         for (i = 0; i < size; i++) {
     707             :                 char sbuf[INET_ADDRSTRLEN];
     708             :                 struct in_addr dest, gw;
     709             :                 uint8_t length;
     710             : 
     711           0 :                 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
     712           0 :                 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
     713           0 :                 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
     714             : 
     715           0 :                 fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof(sbuf)), length);
     716           0 :                 fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof(sbuf)), (i < (size - 1)) ? " ": "");
     717             :         }
     718             : 
     719           0 :         fputs("\n", f);
     720           0 : }
     721             : 
     722           4 : int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
     723           4 :         _cleanup_free_ struct sd_dhcp_route *routes = NULL;
     724           4 :         size_t size = 0, allocated = 0;
     725             : 
     726           4 :         assert(ret);
     727           4 :         assert(ret_size);
     728           4 :         assert(ret_allocated);
     729           4 :         assert(string);
     730             : 
     731             :          /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
     732           9 :         for (;;) {
     733          13 :                 _cleanup_free_ char *word = NULL;
     734             :                 char *tok, *tok_end;
     735             :                 unsigned n;
     736             :                 int r;
     737             : 
     738          13 :                 r = extract_first_word(&string, &word, NULL, 0);
     739          13 :                 if (r < 0)
     740           0 :                         return r;
     741          13 :                 if (r == 0)
     742           4 :                         break;
     743             : 
     744           9 :                 if (!GREEDY_REALLOC(routes, allocated, size + 1))
     745           0 :                         return -ENOMEM;
     746             : 
     747           9 :                 tok = word;
     748             : 
     749             :                 /* get the subnet */
     750           9 :                 tok_end = strchr(tok, '/');
     751           9 :                 if (!tok_end)
     752           2 :                         continue;
     753           7 :                 *tok_end = '\0';
     754             : 
     755           7 :                 r = inet_aton(tok, &routes[size].dst_addr);
     756           7 :                 if (r == 0)
     757           0 :                         continue;
     758             : 
     759           7 :                 tok = tok_end + 1;
     760             : 
     761             :                 /* get the prefixlen */
     762           7 :                 tok_end = strchr(tok, ',');
     763           7 :                 if (!tok_end)
     764           0 :                         continue;
     765             : 
     766           7 :                 *tok_end = '\0';
     767             : 
     768           7 :                 r = safe_atou(tok, &n);
     769           7 :                 if (r < 0 || n > 32)
     770           1 :                         continue;
     771             : 
     772           6 :                 routes[size].dst_prefixlen = (uint8_t) n;
     773           6 :                 tok = tok_end + 1;
     774             : 
     775             :                 /* get the gateway */
     776           6 :                 r = inet_aton(tok, &routes[size].gw_addr);
     777           6 :                 if (r == 0)
     778           1 :                         continue;
     779             : 
     780           5 :                 size++;
     781             :         }
     782             : 
     783           4 :         *ret_size = size;
     784           4 :         *ret_allocated = allocated;
     785           4 :         *ret = TAKE_PTR(routes);
     786             : 
     787           4 :         return 0;
     788             : }
     789             : 
     790           0 : int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
     791           0 :         _cleanup_free_ char *hex_buf = NULL;
     792             : 
     793           0 :         assert(f);
     794           0 :         assert(key);
     795           0 :         assert(data);
     796             : 
     797           0 :         hex_buf = hexmem(data, size);
     798           0 :         if (!hex_buf)
     799           0 :                 return -ENOMEM;
     800             : 
     801           0 :         fprintf(f, "%s=%s\n", key, hex_buf);
     802             : 
     803           0 :         return 0;
     804             : }

Generated by: LCOV version 1.14