1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <arpa/inet.h>
4 #include <linux/if.h>
5 #include <netinet/ether.h>
6 
7 #include "sd-ndisc.h"
8 
9 #include "alloc-util.h"
10 #include "dhcp-lease-internal.h"
11 #include "extract-word.h"
12 #include "hexdecoct.h"
13 #include "log.h"
14 #include "network-internal.h"
15 #include "parse-util.h"
16 
serialize_in_addrs(FILE * f,const struct in_addr * addresses,size_t size,bool * with_leading_space,bool (* predicate)(const struct in_addr * addr))17 size_t serialize_in_addrs(FILE *f,
18                           const struct in_addr *addresses,
19                           size_t size,
20                           bool *with_leading_space,
21                           bool (*predicate)(const struct in_addr *addr)) {
22         assert(f);
23         assert(addresses);
24 
25         size_t count = 0;
26         bool _space = false;
27         if (!with_leading_space)
28                 with_leading_space = &_space;
29 
30         for (size_t i = 0; i < size; i++) {
31                 char sbuf[INET_ADDRSTRLEN];
32 
33                 if (predicate && !predicate(&addresses[i]))
34                         continue;
35 
36                 if (*with_leading_space)
37                         fputc(' ', f);
38                 fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
39                 count++;
40                 *with_leading_space = true;
41         }
42 
43         return count;
44 }
45 
deserialize_in_addrs(struct in_addr ** ret,const char * string)46 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
47         _cleanup_free_ struct in_addr *addresses = NULL;
48         int size = 0;
49 
50         assert(ret);
51         assert(string);
52 
53         for (;;) {
54                 _cleanup_free_ char *word = NULL;
55                 struct in_addr *new_addresses;
56                 int r;
57 
58                 r = extract_first_word(&string, &word, NULL, 0);
59                 if (r < 0)
60                         return r;
61                 if (r == 0)
62                         break;
63 
64                 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
65                 if (!new_addresses)
66                         return -ENOMEM;
67                 else
68                         addresses = new_addresses;
69 
70                 r = inet_pton(AF_INET, word, &(addresses[size]));
71                 if (r <= 0)
72                         continue;
73 
74                 size++;
75         }
76 
77         *ret = size > 0 ? TAKE_PTR(addresses) : NULL;
78 
79         return size;
80 }
81 
serialize_in6_addrs(FILE * f,const struct in6_addr * addresses,size_t size,bool * with_leading_space)82 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size, bool *with_leading_space) {
83         assert(f);
84         assert(addresses);
85         assert(size);
86 
87         bool _space = false;
88         if (!with_leading_space)
89                 with_leading_space = &_space;
90 
91         for (size_t i = 0; i < size; i++) {
92                 char buffer[INET6_ADDRSTRLEN];
93 
94                 if (*with_leading_space)
95                         fputc(' ', f);
96                 fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
97                 *with_leading_space = true;
98         }
99 }
100 
deserialize_in6_addrs(struct in6_addr ** ret,const char * string)101 int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
102         _cleanup_free_ struct in6_addr *addresses = NULL;
103         int size = 0;
104 
105         assert(ret);
106         assert(string);
107 
108         for (;;) {
109                 _cleanup_free_ char *word = NULL;
110                 struct in6_addr *new_addresses;
111                 int r;
112 
113                 r = extract_first_word(&string, &word, NULL, 0);
114                 if (r < 0)
115                         return r;
116                 if (r == 0)
117                         break;
118 
119                 new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
120                 if (!new_addresses)
121                         return -ENOMEM;
122                 else
123                         addresses = new_addresses;
124 
125                 r = inet_pton(AF_INET6, word, &(addresses[size]));
126                 if (r <= 0)
127                         continue;
128 
129                 size++;
130         }
131 
132         *ret = TAKE_PTR(addresses);
133 
134         return size;
135 }
136 
serialize_dhcp_routes(FILE * f,const char * key,sd_dhcp_route ** routes,size_t size)137 void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
138         assert(f);
139         assert(key);
140         assert(routes);
141         assert(size);
142 
143         fprintf(f, "%s=", key);
144 
145         for (size_t i = 0; i < size; i++) {
146                 char sbuf[INET_ADDRSTRLEN];
147                 struct in_addr dest, gw;
148                 uint8_t length;
149 
150                 assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
151                 assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
152                 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
153 
154                 fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof sbuf), length);
155                 fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof sbuf), i < size - 1 ? " ": "");
156         }
157 
158         fputs("\n", f);
159 }
160 
deserialize_dhcp_routes(struct sd_dhcp_route ** ret,size_t * ret_size,const char * string)161 int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string) {
162         _cleanup_free_ struct sd_dhcp_route *routes = NULL;
163         size_t size = 0;
164 
165         assert(ret);
166         assert(ret_size);
167         assert(string);
168 
169          /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
170         for (;;) {
171                 _cleanup_free_ char *word = NULL;
172                 char *tok, *tok_end;
173                 unsigned n;
174                 int r;
175 
176                 r = extract_first_word(&string, &word, NULL, 0);
177                 if (r < 0)
178                         return r;
179                 if (r == 0)
180                         break;
181 
182                 if (!GREEDY_REALLOC(routes, size + 1))
183                         return -ENOMEM;
184 
185                 tok = word;
186 
187                 /* get the subnet */
188                 tok_end = strchr(tok, '/');
189                 if (!tok_end)
190                         continue;
191                 *tok_end = '\0';
192 
193                 r = inet_aton(tok, &routes[size].dst_addr);
194                 if (r == 0)
195                         continue;
196 
197                 tok = tok_end + 1;
198 
199                 /* get the prefixlen */
200                 tok_end = strchr(tok, ',');
201                 if (!tok_end)
202                         continue;
203 
204                 *tok_end = '\0';
205 
206                 r = safe_atou(tok, &n);
207                 if (r < 0 || n > 32)
208                         continue;
209 
210                 routes[size].dst_prefixlen = (uint8_t) n;
211                 tok = tok_end + 1;
212 
213                 /* get the gateway */
214                 r = inet_aton(tok, &routes[size].gw_addr);
215                 if (r == 0)
216                         continue;
217 
218                 size++;
219         }
220 
221         *ret_size = size;
222         *ret = TAKE_PTR(routes);
223 
224         return 0;
225 }
226 
serialize_dhcp_option(FILE * f,const char * key,const void * data,size_t size)227 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
228         _cleanup_free_ char *hex_buf = NULL;
229 
230         assert(f);
231         assert(key);
232         assert(data);
233 
234         hex_buf = hexmem(data, size);
235         if (!hex_buf)
236                 return -ENOMEM;
237 
238         fprintf(f, "%s=%s\n", key, hex_buf);
239 
240         return 0;
241 }
242