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