]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/in-addr-util.c
Merge pull request #1691 from poettering/util-lib-3
[thirdparty/systemd.git] / src / basic / in-addr-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
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 <arpa/inet.h>
23
24 #include "alloc-util.h"
25 #include "in-addr-util.h"
26
27 int in_addr_is_null(int family, const union in_addr_union *u) {
28 assert(u);
29
30 if (family == AF_INET)
31 return u->in.s_addr == 0;
32
33 if (family == AF_INET6)
34 return
35 u->in6.s6_addr32[0] == 0 &&
36 u->in6.s6_addr32[1] == 0 &&
37 u->in6.s6_addr32[2] == 0 &&
38 u->in6.s6_addr32[3] == 0;
39
40 return -EAFNOSUPPORT;
41 }
42
43 int in_addr_is_link_local(int family, const union in_addr_union *u) {
44 assert(u);
45
46 if (family == AF_INET)
47 return (be32toh(u->in.s_addr) & 0xFFFF0000) == (169U << 24 | 254U << 16);
48
49 if (family == AF_INET6)
50 return IN6_IS_ADDR_LINKLOCAL(&u->in6);
51
52 return -EAFNOSUPPORT;
53 }
54
55 int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
56 assert(a);
57 assert(b);
58
59 if (family == AF_INET)
60 return a->in.s_addr == b->in.s_addr;
61
62 if (family == AF_INET6)
63 return
64 a->in6.s6_addr32[0] == b->in6.s6_addr32[0] &&
65 a->in6.s6_addr32[1] == b->in6.s6_addr32[1] &&
66 a->in6.s6_addr32[2] == b->in6.s6_addr32[2] &&
67 a->in6.s6_addr32[3] == b->in6.s6_addr32[3];
68
69 return -EAFNOSUPPORT;
70 }
71
72 int in_addr_prefix_intersect(
73 int family,
74 const union in_addr_union *a,
75 unsigned aprefixlen,
76 const union in_addr_union *b,
77 unsigned bprefixlen) {
78
79 unsigned m;
80
81 assert(a);
82 assert(b);
83
84 /* Checks whether there are any addresses that are in both
85 * networks */
86
87 m = MIN(aprefixlen, bprefixlen);
88
89 if (family == AF_INET) {
90 uint32_t x, nm;
91
92 x = be32toh(a->in.s_addr ^ b->in.s_addr);
93 nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
94
95 return (x & nm) == 0;
96 }
97
98 if (family == AF_INET6) {
99 unsigned i;
100
101 if (m > 128)
102 m = 128;
103
104 for (i = 0; i < 16; i++) {
105 uint8_t x, nm;
106
107 x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
108
109 if (m < 8)
110 nm = 0xFF << (8 - m);
111 else
112 nm = 0xFF;
113
114 if ((x & nm) != 0)
115 return 0;
116
117 if (m > 8)
118 m -= 8;
119 else
120 m = 0;
121 }
122
123 return 1;
124 }
125
126 return -EAFNOSUPPORT;
127 }
128
129 int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
130 assert(u);
131
132 /* Increases the network part of an address by one. Returns
133 * positive it that succeeds, or 0 if this overflows. */
134
135 if (prefixlen <= 0)
136 return 0;
137
138 if (family == AF_INET) {
139 uint32_t c, n;
140
141 if (prefixlen > 32)
142 prefixlen = 32;
143
144 c = be32toh(u->in.s_addr);
145 n = c + (1UL << (32 - prefixlen));
146 if (n < c)
147 return 0;
148 n &= 0xFFFFFFFFUL << (32 - prefixlen);
149
150 u->in.s_addr = htobe32(n);
151 return 1;
152 }
153
154 if (family == AF_INET6) {
155 struct in6_addr add = {}, result;
156 uint8_t overflow = 0;
157 unsigned i;
158
159 if (prefixlen > 128)
160 prefixlen = 128;
161
162 /* First calculate what we have to add */
163 add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8);
164
165 for (i = 16; i > 0; i--) {
166 unsigned j = i - 1;
167
168 result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow;
169 overflow = (result.s6_addr[j] < u->in6.s6_addr[j]);
170 }
171
172 if (overflow)
173 return 0;
174
175 u->in6 = result;
176 return 1;
177 }
178
179 return -EAFNOSUPPORT;
180 }
181
182 int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
183 char *x;
184 size_t l;
185
186 assert(u);
187 assert(ret);
188
189 if (family == AF_INET)
190 l = INET_ADDRSTRLEN;
191 else if (family == AF_INET6)
192 l = INET6_ADDRSTRLEN;
193 else
194 return -EAFNOSUPPORT;
195
196 x = new(char, l);
197 if (!x)
198 return -ENOMEM;
199
200 errno = 0;
201 if (!inet_ntop(family, u, x, l)) {
202 free(x);
203 return errno ? -errno : -EINVAL;
204 }
205
206 *ret = x;
207 return 0;
208 }
209
210 int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
211
212 assert(s);
213 assert(ret);
214
215 if (!IN_SET(family, AF_INET, AF_INET6))
216 return -EAFNOSUPPORT;
217
218 errno = 0;
219 if (inet_pton(family, s, ret) <= 0)
220 return errno ? -errno : -EINVAL;
221
222 return 0;
223 }
224
225 int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret) {
226 int r;
227
228 assert(s);
229 assert(family);
230 assert(ret);
231
232 r = in_addr_from_string(AF_INET, s, ret);
233 if (r >= 0) {
234 *family = AF_INET;
235 return 0;
236 }
237
238 r = in_addr_from_string(AF_INET6, s, ret);
239 if (r >= 0) {
240 *family = AF_INET6;
241 return 0;
242 }
243
244 return -EINVAL;
245 }
246
247 unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
248 assert(addr);
249
250 return 32 - u32ctz(be32toh(addr->s_addr));
251 }
252
253 struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
254 assert(addr);
255 assert(prefixlen <= 32);
256
257 /* Shifting beyond 32 is not defined, handle this specially. */
258 if (prefixlen == 0)
259 addr->s_addr = 0;
260 else
261 addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
262
263 return addr;
264 }
265
266 int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
267 uint8_t msb_octet = *(uint8_t*) addr;
268
269 /* addr may not be aligned, so make sure we only access it byte-wise */
270
271 assert(addr);
272 assert(prefixlen);
273
274 if (msb_octet < 128)
275 /* class A, leading bits: 0 */
276 *prefixlen = 8;
277 else if (msb_octet < 192)
278 /* class B, leading bits 10 */
279 *prefixlen = 16;
280 else if (msb_octet < 224)
281 /* class C, leading bits 110 */
282 *prefixlen = 24;
283 else
284 /* class D or E, no default prefixlen */
285 return -ERANGE;
286
287 return 0;
288 }
289
290 int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
291 unsigned char prefixlen;
292 int r;
293
294 assert(addr);
295 assert(mask);
296
297 r = in_addr_default_prefixlen(addr, &prefixlen);
298 if (r < 0)
299 return r;
300
301 in_addr_prefixlen_to_netmask(mask, prefixlen);
302 return 0;
303 }
304
305 int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
306 assert(addr);
307
308 if (family == AF_INET) {
309 struct in_addr mask;
310
311 if (!in_addr_prefixlen_to_netmask(&mask, prefixlen))
312 return -EINVAL;
313
314 addr->in.s_addr &= mask.s_addr;
315 return 0;
316 }
317
318 if (family == AF_INET6) {
319 unsigned i;
320
321 for (i = 0; i < 16; i++) {
322 uint8_t mask;
323
324 if (prefixlen >= 8) {
325 mask = 0xFF;
326 prefixlen -= 8;
327 } else {
328 mask = 0xFF << (8 - prefixlen);
329 prefixlen = 0;
330 }
331
332 addr->in6.s6_addr[i] &= mask;
333 }
334
335 return 0;
336 }
337
338 return -EAFNOSUPPORT;
339 }