1 |
|
|
/* $OpenBSD: asr_utils.c,v 1.18 2017/09/23 20:55:06 jca Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2009-2012 Eric Faurot <eric@faurot.net> |
4 |
|
|
* |
5 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
6 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
7 |
|
|
* copyright notice and this permission notice appear in all copies. |
8 |
|
|
* |
9 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 |
|
|
*/ |
17 |
|
|
|
18 |
|
|
#include <sys/types.h> |
19 |
|
|
#include <sys/socket.h> |
20 |
|
|
#include <net/if.h> |
21 |
|
|
#include <netinet/in.h> |
22 |
|
|
#include <arpa/inet.h> |
23 |
|
|
#include <arpa/nameser.h> |
24 |
|
|
#include <netdb.h> |
25 |
|
|
|
26 |
|
|
#include <asr.h> |
27 |
|
|
#include <ctype.h> |
28 |
|
|
#include <errno.h> |
29 |
|
|
#include <stdint.h> |
30 |
|
|
#include <stdio.h> |
31 |
|
|
#include <stdlib.h> |
32 |
|
|
#include <string.h> |
33 |
|
|
#include <unistd.h> |
34 |
|
|
|
35 |
|
|
#include "asr_private.h" |
36 |
|
|
|
37 |
|
|
static int dname_check_label(const char *, size_t); |
38 |
|
|
static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *, |
39 |
|
|
char *, size_t); |
40 |
|
|
|
41 |
|
|
static int unpack_data(struct asr_unpack *, void *, size_t); |
42 |
|
|
static int unpack_u16(struct asr_unpack *, uint16_t *); |
43 |
|
|
static int unpack_u32(struct asr_unpack *, uint32_t *); |
44 |
|
|
static int unpack_inaddr(struct asr_unpack *, struct in_addr *); |
45 |
|
|
static int unpack_in6addr(struct asr_unpack *, struct in6_addr *); |
46 |
|
|
static int unpack_dname(struct asr_unpack *, char *, size_t); |
47 |
|
|
|
48 |
|
|
static int pack_data(struct asr_pack *, const void *, size_t); |
49 |
|
|
static int pack_u16(struct asr_pack *, uint16_t); |
50 |
|
|
static int pack_dname(struct asr_pack *, const char *); |
51 |
|
|
|
52 |
|
|
static int |
53 |
|
|
dname_check_label(const char *s, size_t l) |
54 |
|
|
{ |
55 |
|
|
if (l == 0 || l > 63) |
56 |
|
|
return (-1); |
57 |
|
|
|
58 |
|
|
return (0); |
59 |
|
|
} |
60 |
|
|
|
61 |
|
|
ssize_t |
62 |
|
|
_asr_dname_from_fqdn(const char *str, char *dst, size_t max) |
63 |
|
|
{ |
64 |
|
|
ssize_t res; |
65 |
|
|
size_t l, n; |
66 |
|
|
char *d; |
67 |
|
|
|
68 |
|
|
res = 0; |
69 |
|
|
|
70 |
|
|
/* special case: the root domain */ |
71 |
|
|
if (str[0] == '.') { |
72 |
|
|
if (str[1] != '\0') |
73 |
|
|
return (-1); |
74 |
|
|
if (dst && max >= 1) |
75 |
|
|
*dst = '\0'; |
76 |
|
|
return (1); |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
for (; *str; str = d + 1) { |
80 |
|
|
|
81 |
|
|
d = strchr(str, '.'); |
82 |
|
|
if (d == NULL || d == str) |
83 |
|
|
return (-1); |
84 |
|
|
|
85 |
|
|
l = (d - str); |
86 |
|
|
|
87 |
|
|
if (dname_check_label(str, l) == -1) |
88 |
|
|
return (-1); |
89 |
|
|
|
90 |
|
|
res += l + 1; |
91 |
|
|
|
92 |
|
|
if (dst) { |
93 |
|
|
*dst++ = l; |
94 |
|
|
max -= 1; |
95 |
|
|
n = (l > max) ? max : l; |
96 |
|
|
memmove(dst, str, n); |
97 |
|
|
max -= n; |
98 |
|
|
if (max == 0) |
99 |
|
|
dst = NULL; |
100 |
|
|
else |
101 |
|
|
dst += n; |
102 |
|
|
} |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
if (dst) |
106 |
|
|
*dst++ = '\0'; |
107 |
|
|
|
108 |
|
|
return (res + 1); |
109 |
|
|
} |
110 |
|
|
|
111 |
|
|
static ssize_t |
112 |
|
|
dname_expand(const unsigned char *data, size_t len, size_t offset, |
113 |
|
|
size_t *newoffset, char *dst, size_t max) |
114 |
|
|
{ |
115 |
|
|
size_t n, count, end, ptr, start; |
116 |
|
|
ssize_t res; |
117 |
|
|
|
118 |
|
|
if (offset >= len) |
119 |
|
|
return (-1); |
120 |
|
|
|
121 |
|
|
res = 0; |
122 |
|
|
end = start = offset; |
123 |
|
|
|
124 |
|
|
for (; (n = data[offset]); ) { |
125 |
|
|
if ((n & 0xc0) == 0xc0) { |
126 |
|
|
if (offset + 2 > len) |
127 |
|
|
return (-1); |
128 |
|
|
ptr = 256 * (n & ~0xc0) + data[offset + 1]; |
129 |
|
|
if (ptr >= start) |
130 |
|
|
return (-1); |
131 |
|
|
if (end < offset + 2) |
132 |
|
|
end = offset + 2; |
133 |
|
|
offset = start = ptr; |
134 |
|
|
continue; |
135 |
|
|
} |
136 |
|
|
if (offset + n + 1 > len) |
137 |
|
|
return (-1); |
138 |
|
|
|
139 |
|
|
if (dname_check_label(data + offset + 1, n) == -1) |
140 |
|
|
return (-1); |
141 |
|
|
|
142 |
|
|
/* copy n + at offset+1 */ |
143 |
|
|
if (dst != NULL && max != 0) { |
144 |
|
|
count = (max < n + 1) ? (max) : (n + 1); |
145 |
|
|
memmove(dst, data + offset, count); |
146 |
|
|
dst += count; |
147 |
|
|
max -= count; |
148 |
|
|
} |
149 |
|
|
res += n + 1; |
150 |
|
|
offset += n + 1; |
151 |
|
|
if (end < offset) |
152 |
|
|
end = offset; |
153 |
|
|
} |
154 |
|
|
if (end < offset + 1) |
155 |
|
|
end = offset + 1; |
156 |
|
|
|
157 |
|
|
if (dst != NULL && max != 0) |
158 |
|
|
dst[0] = 0; |
159 |
|
|
if (newoffset) |
160 |
|
|
*newoffset = end; |
161 |
|
|
return (res + 1); |
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
void |
165 |
|
|
_asr_pack_init(struct asr_pack *pack, char *buf, size_t len) |
166 |
|
|
{ |
167 |
|
|
pack->buf = buf; |
168 |
|
|
pack->len = len; |
169 |
|
|
pack->offset = 0; |
170 |
|
|
pack->err = 0; |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
void |
174 |
|
|
_asr_unpack_init(struct asr_unpack *unpack, const char *buf, size_t len) |
175 |
|
|
{ |
176 |
|
|
unpack->buf = buf; |
177 |
|
|
unpack->len = len; |
178 |
|
|
unpack->offset = 0; |
179 |
|
|
unpack->err = 0; |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
static int |
183 |
|
|
unpack_data(struct asr_unpack *p, void *data, size_t len) |
184 |
|
|
{ |
185 |
|
|
if (p->err) |
186 |
|
|
return (-1); |
187 |
|
|
|
188 |
|
|
if (p->len - p->offset < len) { |
189 |
|
|
p->err = EOVERFLOW; |
190 |
|
|
return (-1); |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
memmove(data, p->buf + p->offset, len); |
194 |
|
|
p->offset += len; |
195 |
|
|
|
196 |
|
|
return (0); |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
static int |
200 |
|
|
unpack_u16(struct asr_unpack *p, uint16_t *u16) |
201 |
|
|
{ |
202 |
|
|
if (unpack_data(p, u16, 2) == -1) |
203 |
|
|
return (-1); |
204 |
|
|
|
205 |
|
|
*u16 = ntohs(*u16); |
206 |
|
|
|
207 |
|
|
return (0); |
208 |
|
|
} |
209 |
|
|
|
210 |
|
|
static int |
211 |
|
|
unpack_u32(struct asr_unpack *p, uint32_t *u32) |
212 |
|
|
{ |
213 |
|
|
if (unpack_data(p, u32, 4) == -1) |
214 |
|
|
return (-1); |
215 |
|
|
|
216 |
|
|
*u32 = ntohl(*u32); |
217 |
|
|
|
218 |
|
|
return (0); |
219 |
|
|
} |
220 |
|
|
|
221 |
|
|
static int |
222 |
|
|
unpack_inaddr(struct asr_unpack *p, struct in_addr *a) |
223 |
|
|
{ |
224 |
|
|
return (unpack_data(p, a, 4)); |
225 |
|
|
} |
226 |
|
|
|
227 |
|
|
static int |
228 |
|
|
unpack_in6addr(struct asr_unpack *p, struct in6_addr *a6) |
229 |
|
|
{ |
230 |
|
|
return (unpack_data(p, a6, 16)); |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
static int |
234 |
|
|
unpack_dname(struct asr_unpack *p, char *dst, size_t max) |
235 |
|
|
{ |
236 |
|
|
ssize_t e; |
237 |
|
|
|
238 |
|
|
if (p->err) |
239 |
|
|
return (-1); |
240 |
|
|
|
241 |
|
|
e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max); |
242 |
|
|
if (e == -1) { |
243 |
|
|
p->err = EINVAL; |
244 |
|
|
return (-1); |
245 |
|
|
} |
246 |
|
|
if (e < 0 || e > MAXDNAME) { |
247 |
|
|
p->err = ERANGE; |
248 |
|
|
return (-1); |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
return (0); |
252 |
|
|
} |
253 |
|
|
|
254 |
|
|
int |
255 |
|
|
_asr_unpack_header(struct asr_unpack *p, struct asr_dns_header *h) |
256 |
|
|
{ |
257 |
|
|
if (unpack_data(p, h, HFIXEDSZ) == -1) |
258 |
|
|
return (-1); |
259 |
|
|
|
260 |
|
|
h->flags = ntohs(h->flags); |
261 |
|
|
h->qdcount = ntohs(h->qdcount); |
262 |
|
|
h->ancount = ntohs(h->ancount); |
263 |
|
|
h->nscount = ntohs(h->nscount); |
264 |
|
|
h->arcount = ntohs(h->arcount); |
265 |
|
|
|
266 |
|
|
return (0); |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
int |
270 |
|
|
_asr_unpack_query(struct asr_unpack *p, struct asr_dns_query *q) |
271 |
|
|
{ |
272 |
|
|
unpack_dname(p, q->q_dname, sizeof(q->q_dname)); |
273 |
|
|
unpack_u16(p, &q->q_type); |
274 |
|
|
unpack_u16(p, &q->q_class); |
275 |
|
|
|
276 |
|
|
return (p->err) ? (-1) : (0); |
277 |
|
|
} |
278 |
|
|
|
279 |
|
|
int |
280 |
|
|
_asr_unpack_rr(struct asr_unpack *p, struct asr_dns_rr *rr) |
281 |
|
|
{ |
282 |
|
|
uint16_t rdlen; |
283 |
|
|
size_t save_offset; |
284 |
|
|
|
285 |
|
|
unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname)); |
286 |
|
|
unpack_u16(p, &rr->rr_type); |
287 |
|
|
unpack_u16(p, &rr->rr_class); |
288 |
|
|
unpack_u32(p, &rr->rr_ttl); |
289 |
|
|
unpack_u16(p, &rdlen); |
290 |
|
|
|
291 |
|
|
if (p->err) |
292 |
|
|
return (-1); |
293 |
|
|
|
294 |
|
|
if (p->len - p->offset < rdlen) { |
295 |
|
|
p->err = EOVERFLOW; |
296 |
|
|
return (-1); |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
save_offset = p->offset; |
300 |
|
|
|
301 |
|
|
switch (rr->rr_type) { |
302 |
|
|
|
303 |
|
|
case T_CNAME: |
304 |
|
|
unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname)); |
305 |
|
|
break; |
306 |
|
|
|
307 |
|
|
case T_MX: |
308 |
|
|
unpack_u16(p, &rr->rr.mx.preference); |
309 |
|
|
unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange)); |
310 |
|
|
break; |
311 |
|
|
|
312 |
|
|
case T_NS: |
313 |
|
|
unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname)); |
314 |
|
|
break; |
315 |
|
|
|
316 |
|
|
case T_PTR: |
317 |
|
|
unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname)); |
318 |
|
|
break; |
319 |
|
|
|
320 |
|
|
case T_SOA: |
321 |
|
|
unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname)); |
322 |
|
|
unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname)); |
323 |
|
|
unpack_u32(p, &rr->rr.soa.serial); |
324 |
|
|
unpack_u32(p, &rr->rr.soa.refresh); |
325 |
|
|
unpack_u32(p, &rr->rr.soa.retry); |
326 |
|
|
unpack_u32(p, &rr->rr.soa.expire); |
327 |
|
|
unpack_u32(p, &rr->rr.soa.minimum); |
328 |
|
|
break; |
329 |
|
|
|
330 |
|
|
case T_A: |
331 |
|
|
if (rr->rr_class != C_IN) |
332 |
|
|
goto other; |
333 |
|
|
unpack_inaddr(p, &rr->rr.in_a.addr); |
334 |
|
|
break; |
335 |
|
|
|
336 |
|
|
case T_AAAA: |
337 |
|
|
if (rr->rr_class != C_IN) |
338 |
|
|
goto other; |
339 |
|
|
unpack_in6addr(p, &rr->rr.in_aaaa.addr6); |
340 |
|
|
break; |
341 |
|
|
default: |
342 |
|
|
other: |
343 |
|
|
rr->rr.other.rdata = p->buf + p->offset; |
344 |
|
|
rr->rr.other.rdlen = rdlen; |
345 |
|
|
p->offset += rdlen; |
346 |
|
|
} |
347 |
|
|
|
348 |
|
|
if (p->err) |
349 |
|
|
return (-1); |
350 |
|
|
|
351 |
|
|
/* make sure that the advertised rdlen is really ok */ |
352 |
|
|
if (p->offset - save_offset != rdlen) |
353 |
|
|
p->err = EINVAL; |
354 |
|
|
|
355 |
|
|
return (p->err) ? (-1) : (0); |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
static int |
359 |
|
|
pack_data(struct asr_pack *p, const void *data, size_t len) |
360 |
|
|
{ |
361 |
|
|
if (p->err) |
362 |
|
|
return (-1); |
363 |
|
|
|
364 |
|
|
if (p->len < p->offset + len) { |
365 |
|
|
p->err = EOVERFLOW; |
366 |
|
|
return (-1); |
367 |
|
|
} |
368 |
|
|
|
369 |
|
|
memmove(p->buf + p->offset, data, len); |
370 |
|
|
p->offset += len; |
371 |
|
|
|
372 |
|
|
return (0); |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
static int |
376 |
|
|
pack_u16(struct asr_pack *p, uint16_t v) |
377 |
|
|
{ |
378 |
|
|
v = htons(v); |
379 |
|
|
|
380 |
|
|
return (pack_data(p, &v, 2)); |
381 |
|
|
} |
382 |
|
|
|
383 |
|
|
static int |
384 |
|
|
pack_dname(struct asr_pack *p, const char *dname) |
385 |
|
|
{ |
386 |
|
|
/* dname compression would be nice to have here. |
387 |
|
|
* need additionnal context. |
388 |
|
|
*/ |
389 |
|
|
return (pack_data(p, dname, strlen(dname) + 1)); |
390 |
|
|
} |
391 |
|
|
|
392 |
|
|
int |
393 |
|
|
_asr_pack_header(struct asr_pack *p, const struct asr_dns_header *h) |
394 |
|
|
{ |
395 |
|
|
struct asr_dns_header c; |
396 |
|
|
|
397 |
|
|
c.id = h->id; |
398 |
|
|
c.flags = htons(h->flags); |
399 |
|
|
c.qdcount = htons(h->qdcount); |
400 |
|
|
c.ancount = htons(h->ancount); |
401 |
|
|
c.nscount = htons(h->nscount); |
402 |
|
|
c.arcount = htons(h->arcount); |
403 |
|
|
|
404 |
|
|
return (pack_data(p, &c, HFIXEDSZ)); |
405 |
|
|
} |
406 |
|
|
|
407 |
|
|
int |
408 |
|
|
_asr_pack_query(struct asr_pack *p, uint16_t type, uint16_t class, const char *dname) |
409 |
|
|
{ |
410 |
|
|
pack_dname(p, dname); |
411 |
|
|
pack_u16(p, type); |
412 |
|
|
pack_u16(p, class); |
413 |
|
|
|
414 |
|
|
return (p->err) ? (-1) : (0); |
415 |
|
|
} |
416 |
|
|
|
417 |
|
|
int |
418 |
|
|
_asr_pack_edns0(struct asr_pack *p, uint16_t pktsz, int dnssec_do) |
419 |
|
|
{ |
420 |
|
|
DPRINT("asr EDNS0 pktsz:%hu dnssec:%s\n", pktsz, |
421 |
|
|
dnssec_do ? "yes" : "no"); |
422 |
|
|
|
423 |
|
|
pack_dname(p, ""); /* root */ |
424 |
|
|
pack_u16(p, T_OPT); /* OPT */ |
425 |
|
|
pack_u16(p, pktsz); /* UDP payload size */ |
426 |
|
|
|
427 |
|
|
/* extended RCODE and flags */ |
428 |
|
|
pack_u16(p, 0); |
429 |
|
|
pack_u16(p, dnssec_do ? DNS_MESSAGEEXTFLAG_DO : 0); |
430 |
|
|
|
431 |
|
|
pack_u16(p, 0); /* RDATA len */ |
432 |
|
|
|
433 |
|
|
return (p->err) ? (-1) : (0); |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
int |
437 |
|
|
_asr_sockaddr_from_str(struct sockaddr *sa, int family, const char *str) |
438 |
|
|
{ |
439 |
|
|
struct in_addr ina; |
440 |
|
|
struct in6_addr in6a; |
441 |
|
|
struct sockaddr_in *sin; |
442 |
|
|
struct sockaddr_in6 *sin6; |
443 |
|
|
char *cp, *str2; |
444 |
|
|
const char *errstr; |
445 |
|
|
|
446 |
|
|
switch (family) { |
447 |
|
|
case PF_UNSPEC: |
448 |
|
|
if (_asr_sockaddr_from_str(sa, PF_INET, str) == 0) |
449 |
|
|
return (0); |
450 |
|
|
return _asr_sockaddr_from_str(sa, PF_INET6, str); |
451 |
|
|
|
452 |
|
|
case PF_INET: |
453 |
|
|
if (inet_pton(PF_INET, str, &ina) != 1) |
454 |
|
|
return (-1); |
455 |
|
|
|
456 |
|
|
sin = (struct sockaddr_in *)sa; |
457 |
|
|
memset(sin, 0, sizeof *sin); |
458 |
|
|
sin->sin_len = sizeof(struct sockaddr_in); |
459 |
|
|
sin->sin_family = PF_INET; |
460 |
|
|
sin->sin_addr.s_addr = ina.s_addr; |
461 |
|
|
return (0); |
462 |
|
|
|
463 |
|
|
case PF_INET6: |
464 |
|
|
cp = strchr(str, SCOPE_DELIMITER); |
465 |
|
|
if (cp) { |
466 |
|
|
str2 = strdup(str); |
467 |
|
|
if (str2 == NULL) |
468 |
|
|
return (-1); |
469 |
|
|
str2[cp - str] = '\0'; |
470 |
|
|
if (inet_pton(PF_INET6, str2, &in6a) != 1) { |
471 |
|
|
free(str2); |
472 |
|
|
return (-1); |
473 |
|
|
} |
474 |
|
|
cp++; |
475 |
|
|
free(str2); |
476 |
|
|
} else if (inet_pton(PF_INET6, str, &in6a) != 1) |
477 |
|
|
return (-1); |
478 |
|
|
|
479 |
|
|
sin6 = (struct sockaddr_in6 *)sa; |
480 |
|
|
memset(sin6, 0, sizeof *sin6); |
481 |
|
|
sin6->sin6_len = sizeof(struct sockaddr_in6); |
482 |
|
|
sin6->sin6_family = PF_INET6; |
483 |
|
|
sin6->sin6_addr = in6a; |
484 |
|
|
|
485 |
|
|
if (cp == NULL) |
486 |
|
|
return (0); |
487 |
|
|
|
488 |
|
|
if (IN6_IS_ADDR_LINKLOCAL(&in6a) || |
489 |
|
|
IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || |
490 |
|
|
IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) |
491 |
|
|
if ((sin6->sin6_scope_id = if_nametoindex(cp))) |
492 |
|
|
return (0); |
493 |
|
|
|
494 |
|
|
sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); |
495 |
|
|
if (errstr) |
496 |
|
|
return (-1); |
497 |
|
|
return (0); |
498 |
|
|
|
499 |
|
|
default: |
500 |
|
|
break; |
501 |
|
|
} |
502 |
|
|
|
503 |
|
|
return (-1); |
504 |
|
|
} |
505 |
|
|
|
506 |
|
|
ssize_t |
507 |
|
|
_asr_addr_as_fqdn(const char *addr, int family, char *dst, size_t max) |
508 |
|
|
{ |
509 |
|
|
const struct in6_addr *in6_addr; |
510 |
|
|
in_addr_t in_addr; |
511 |
|
|
|
512 |
|
|
switch (family) { |
513 |
|
|
case AF_INET: |
514 |
|
|
in_addr = ntohl(*((const in_addr_t *)addr)); |
515 |
|
|
snprintf(dst, max, |
516 |
|
|
"%d.%d.%d.%d.in-addr.arpa.", |
517 |
|
|
in_addr & 0xff, |
518 |
|
|
(in_addr >> 8) & 0xff, |
519 |
|
|
(in_addr >> 16) & 0xff, |
520 |
|
|
(in_addr >> 24) & 0xff); |
521 |
|
|
break; |
522 |
|
|
case AF_INET6: |
523 |
|
|
in6_addr = (const struct in6_addr *)addr; |
524 |
|
|
snprintf(dst, max, |
525 |
|
|
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." |
526 |
|
|
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." |
527 |
|
|
"ip6.arpa.", |
528 |
|
|
in6_addr->s6_addr[15] & 0xf, |
529 |
|
|
(in6_addr->s6_addr[15] >> 4) & 0xf, |
530 |
|
|
in6_addr->s6_addr[14] & 0xf, |
531 |
|
|
(in6_addr->s6_addr[14] >> 4) & 0xf, |
532 |
|
|
in6_addr->s6_addr[13] & 0xf, |
533 |
|
|
(in6_addr->s6_addr[13] >> 4) & 0xf, |
534 |
|
|
in6_addr->s6_addr[12] & 0xf, |
535 |
|
|
(in6_addr->s6_addr[12] >> 4) & 0xf, |
536 |
|
|
in6_addr->s6_addr[11] & 0xf, |
537 |
|
|
(in6_addr->s6_addr[11] >> 4) & 0xf, |
538 |
|
|
in6_addr->s6_addr[10] & 0xf, |
539 |
|
|
(in6_addr->s6_addr[10] >> 4) & 0xf, |
540 |
|
|
in6_addr->s6_addr[9] & 0xf, |
541 |
|
|
(in6_addr->s6_addr[9] >> 4) & 0xf, |
542 |
|
|
in6_addr->s6_addr[8] & 0xf, |
543 |
|
|
(in6_addr->s6_addr[8] >> 4) & 0xf, |
544 |
|
|
in6_addr->s6_addr[7] & 0xf, |
545 |
|
|
(in6_addr->s6_addr[7] >> 4) & 0xf, |
546 |
|
|
in6_addr->s6_addr[6] & 0xf, |
547 |
|
|
(in6_addr->s6_addr[6] >> 4) & 0xf, |
548 |
|
|
in6_addr->s6_addr[5] & 0xf, |
549 |
|
|
(in6_addr->s6_addr[5] >> 4) & 0xf, |
550 |
|
|
in6_addr->s6_addr[4] & 0xf, |
551 |
|
|
(in6_addr->s6_addr[4] >> 4) & 0xf, |
552 |
|
|
in6_addr->s6_addr[3] & 0xf, |
553 |
|
|
(in6_addr->s6_addr[3] >> 4) & 0xf, |
554 |
|
|
in6_addr->s6_addr[2] & 0xf, |
555 |
|
|
(in6_addr->s6_addr[2] >> 4) & 0xf, |
556 |
|
|
in6_addr->s6_addr[1] & 0xf, |
557 |
|
|
(in6_addr->s6_addr[1] >> 4) & 0xf, |
558 |
|
|
in6_addr->s6_addr[0] & 0xf, |
559 |
|
|
(in6_addr->s6_addr[0] >> 4) & 0xf); |
560 |
|
|
break; |
561 |
|
|
default: |
562 |
|
|
return (-1); |
563 |
|
|
} |
564 |
|
|
return (0); |
565 |
|
|
} |