]> git.proxmox.com Git - systemd.git/blame - src/shared/in-addr-util.c
Imported Upstream version 217
[systemd.git] / src / shared / in-addr-util.c
CommitLineData
5eef597e
MP
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
26int 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
42int 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
54int 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
71int 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
128int 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
181int 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
209int 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
224int 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
246unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
247 assert(addr);
248
249 return 32 - u32ctz(be32toh(addr->s_addr));
250}
251
252int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
253 uint32_t address;
254
255 assert(addr);
256 assert(addr->s_addr != INADDR_ANY);
257 assert(prefixlen);
258
259 address = be32toh(addr->s_addr);
260
261 if ((address >> 31) == 0x0)
262 /* class A, leading bits: 0 */
263 *prefixlen = 8;
264 else if ((address >> 30) == 0x2)
265 /* class B, leading bits 10 */
266 *prefixlen = 16;
267 else if ((address >> 29) == 0x6)
268 /* class C, leading bits 110 */
269 *prefixlen = 24;
270 else
271 /* class D or E, no default prefixlen */
272 return -ERANGE;
273
274 return 0;
275}
276
277int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
278 unsigned char prefixlen;
279 int r;
280
281 assert(addr);
282 assert(mask);
283
284 r = in_addr_default_prefixlen(addr, &prefixlen);
285 if (r < 0)
286 return r;
287
288 assert(prefixlen > 0 && prefixlen < 32);
289
290 mask->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
291
292 return 0;
293}