nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * lib/addr.c Abstract Address |
||
3 | * |
||
4 | * This library is free software; you can redistribute it and/or |
||
5 | * modify it under the terms of the GNU Lesser General Public |
||
6 | * License as published by the Free Software Foundation version 2.1 |
||
7 | * of the License. |
||
8 | * |
||
9 | * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> |
||
10 | */ |
||
11 | |||
12 | /** |
||
13 | * @ingroup core |
||
14 | * @defgroup addr Abstract Address |
||
15 | * |
||
16 | * @par 1) Transform character string to abstract address |
||
17 | * @code |
||
18 | * struct nl_addr *a = nl_addr_parse("::1", AF_UNSPEC); |
||
19 | * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a))); |
||
20 | * nl_addr_put(a); |
||
21 | * a = nl_addr_parse("11:22:33:44:55:66", AF_UNSPEC); |
||
22 | * printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a))); |
||
23 | * nl_addr_put(a); |
||
24 | * @endcode |
||
25 | * @{ |
||
26 | */ |
||
27 | |||
28 | #include <netlink-local.h> |
||
29 | #include <netlink/netlink.h> |
||
30 | #include <netlink/utils.h> |
||
31 | #include <netlink/addr.h> |
||
32 | #include <linux/socket.h> |
||
33 | |||
34 | /* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote |
||
35 | * this, probably Alexey. */ |
||
36 | static inline uint16_t dn_ntohs(uint16_t addr) |
||
37 | { |
||
38 | union { |
||
39 | uint8_t byte[2]; |
||
40 | uint16_t word; |
||
41 | } u = { |
||
42 | .word = addr, |
||
43 | }; |
||
44 | |||
45 | return ((uint16_t) u.byte[0]) | (((uint16_t) u.byte[1]) << 8); |
||
46 | } |
||
47 | |||
48 | static inline int do_digit(char *str, uint16_t *addr, uint16_t scale, |
||
49 | size_t *pos, size_t len, int *started) |
||
50 | { |
||
51 | uint16_t tmp = *addr / scale; |
||
52 | |||
53 | if (*pos == len) |
||
54 | return 1; |
||
55 | |||
56 | if (((tmp) > 0) || *started || (scale == 1)) { |
||
57 | *str = tmp + '0'; |
||
58 | *started = 1; |
||
59 | (*pos)++; |
||
60 | *addr -= (tmp * scale); |
||
61 | } |
||
62 | |||
63 | return 0; |
||
64 | } |
||
65 | |||
66 | static const char *dnet_ntop(char *addrbuf, size_t addrlen, char *str, |
||
67 | size_t len) |
||
68 | { |
||
69 | uint16_t addr = dn_ntohs(*(uint16_t *)addrbuf); |
||
70 | uint16_t area = addr >> 10; |
||
71 | size_t pos = 0; |
||
72 | int started = 0; |
||
73 | |||
74 | if (addrlen != 2) |
||
75 | return NULL; |
||
76 | |||
77 | addr &= 0x03ff; |
||
78 | |||
79 | if (len == 0) |
||
80 | return str; |
||
81 | |||
82 | if (do_digit(str + pos, &area, 10, &pos, len, &started)) |
||
83 | return str; |
||
84 | |||
85 | if (do_digit(str + pos, &area, 1, &pos, len, &started)) |
||
86 | return str; |
||
87 | |||
88 | if (pos == len) |
||
89 | return str; |
||
90 | |||
91 | *(str + pos) = '.'; |
||
92 | pos++; |
||
93 | started = 0; |
||
94 | |||
95 | if (do_digit(str + pos, &addr, 1000, &pos, len, &started)) |
||
96 | return str; |
||
97 | |||
98 | if (do_digit(str + pos, &addr, 100, &pos, len, &started)) |
||
99 | return str; |
||
100 | |||
101 | if (do_digit(str + pos, &addr, 10, &pos, len, &started)) |
||
102 | return str; |
||
103 | |||
104 | if (do_digit(str + pos, &addr, 1, &pos, len, &started)) |
||
105 | return str; |
||
106 | |||
107 | if (pos == len) |
||
108 | return str; |
||
109 | |||
110 | *(str + pos) = 0; |
||
111 | |||
112 | return str; |
||
113 | } |
||
114 | |||
115 | static int dnet_num(const char *src, uint16_t * dst) |
||
116 | { |
||
117 | int rv = 0; |
||
118 | int tmp; |
||
119 | *dst = 0; |
||
120 | |||
121 | while ((tmp = *src++) != 0) { |
||
122 | tmp -= '0'; |
||
123 | if ((tmp < 0) || (tmp > 9)) |
||
124 | return rv; |
||
125 | |||
126 | rv++; |
||
127 | (*dst) *= 10; |
||
128 | (*dst) += tmp; |
||
129 | } |
||
130 | |||
131 | return rv; |
||
132 | } |
||
133 | |||
134 | static inline int dnet_pton(const char *src, char *addrbuf) |
||
135 | { |
||
136 | uint16_t area = 0; |
||
137 | uint16_t node = 0; |
||
138 | int pos; |
||
139 | |||
140 | pos = dnet_num(src, &area); |
||
141 | if ((pos == 0) || (area > 63) || |
||
142 | ((*(src + pos) != '.') && (*(src + pos) != ','))) |
||
143 | return -NLE_INVAL; |
||
144 | |||
145 | pos = dnet_num(src + pos + 1, &node); |
||
146 | if ((pos == 0) || (node > 1023)) |
||
147 | return -NLE_INVAL; |
||
148 | |||
149 | *(uint16_t *)addrbuf = dn_ntohs((area << 10) | node); |
||
150 | |||
151 | return 1; |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * @name Creating Abstract Addresses |
||
156 | * @{ |
||
157 | */ |
||
158 | |||
159 | /** |
||
160 | * Allocate new abstract address object. |
||
161 | * @arg maxsize Maximum size of the binary address. |
||
162 | * @return Newly allocated address object or NULL |
||
163 | */ |
||
164 | struct nl_addr *nl_addr_alloc(size_t maxsize) |
||
165 | { |
||
166 | struct nl_addr *addr; |
||
167 | |||
168 | addr = calloc(1, sizeof(*addr) + maxsize); |
||
169 | if (!addr) |
||
170 | return NULL; |
||
171 | |||
172 | addr->a_refcnt = 1; |
||
173 | addr->a_maxsize = maxsize; |
||
174 | |||
175 | return addr; |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * Allocate new abstract address object based on a binary address. |
||
180 | * @arg family Address family. |
||
181 | * @arg buf Buffer containing the binary address. |
||
182 | * @arg size Length of binary address buffer. |
||
183 | * @return Newly allocated address handle or NULL |
||
184 | */ |
||
185 | struct nl_addr *nl_addr_build(int family, void *buf, size_t size) |
||
186 | { |
||
187 | struct nl_addr *addr; |
||
188 | |||
189 | addr = nl_addr_alloc(size); |
||
190 | if (!addr) |
||
191 | return NULL; |
||
192 | |||
193 | addr->a_family = family; |
||
194 | addr->a_len = size; |
||
195 | addr->a_prefixlen = size*8; |
||
196 | |||
197 | if (size) |
||
198 | memcpy(addr->a_addr, buf, size); |
||
199 | |||
200 | return addr; |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * Allocate abstract address based on netlink attribute. |
||
205 | * @arg nla Netlink attribute of unspecific type. |
||
206 | * @arg family Address family. |
||
207 | * |
||
208 | * Considers the netlink attribute payload a address of the specified |
||
209 | * family and allocates a new abstract address based on it. |
||
210 | * |
||
211 | * @return Newly allocated address handle or NULL. |
||
212 | */ |
||
213 | struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family) |
||
214 | { |
||
215 | return nl_addr_build(family, nla_data(nla), nla_len(nla)); |
||
216 | } |
||
217 | |||
218 | /** |
||
219 | * Allocate abstract address object based on a character string |
||
220 | * @arg addrstr Address represented as character string. |
||
221 | * @arg hint Address family hint or AF_UNSPEC. |
||
222 | * @arg result Pointer to store resulting address. |
||
223 | * |
||
224 | * Regognizes the following address formats: |
||
225 | *@code |
||
226 | * Format Len Family |
||
227 | * ---------------------------------------------------------------- |
||
228 | * IPv6 address format 16 AF_INET6 |
||
229 | * ddd.ddd.ddd.ddd 4 AF_INET |
||
230 | * HH:HH:HH:HH:HH:HH 6 AF_LLC |
||
231 | * AA{.|,}NNNN 2 AF_DECnet |
||
232 | * HH:HH:HH:... variable AF_UNSPEC |
||
233 | * @endcode |
||
234 | * |
||
235 | * Special values: |
||
236 | * - none: All bits and length set to 0. |
||
237 | * - {default|all|any}: All bits set to 0, length based on hint or |
||
238 | * AF_INET if no hint is given. |
||
239 | * |
||
240 | * The prefix length may be appened at the end prefixed with a |
||
241 | * slash, e.g. 10.0.0.0/8. |
||
242 | * |
||
243 | * @return 0 on success or a negative error code. |
||
244 | */ |
||
245 | int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result) |
||
246 | { |
||
247 | int err, copy = 0, len = 0, family = AF_UNSPEC; |
||
248 | char *str, *prefix, buf[32]; |
||
249 | struct nl_addr *addr = NULL; /* gcc ain't that smart */ |
||
250 | |||
251 | str = strdup(addrstr); |
||
252 | if (!str) { |
||
253 | err = -NLE_NOMEM; |
||
254 | goto errout; |
||
255 | } |
||
256 | |||
257 | prefix = strchr(str, '/'); |
||
258 | if (prefix) |
||
259 | *prefix = '\0'; |
||
260 | |||
261 | if (!strcasecmp(str, "none")) { |
||
262 | family = hint; |
||
263 | goto prefix; |
||
264 | } |
||
265 | |||
266 | if (!strcasecmp(str, "default") || |
||
267 | !strcasecmp(str, "all") || |
||
268 | !strcasecmp(str, "any")) { |
||
269 | |||
270 | switch (hint) { |
||
271 | case AF_INET: |
||
272 | case AF_UNSPEC: |
||
273 | /* Kind of a hack, we assume that if there is |
||
274 | * no hint given the user wants to have a IPv4 |
||
275 | * address given back. */ |
||
276 | family = AF_INET; |
||
277 | len = 4; |
||
278 | goto prefix; |
||
279 | |||
280 | case AF_INET6: |
||
281 | family = AF_INET6; |
||
282 | len = 16; |
||
283 | goto prefix; |
||
284 | |||
285 | case AF_LLC: |
||
286 | family = AF_LLC; |
||
287 | len = 6; |
||
288 | goto prefix; |
||
289 | |||
290 | default: |
||
291 | err = -NLE_AF_NOSUPPORT; |
||
292 | goto errout; |
||
293 | } |
||
294 | } |
||
295 | |||
296 | copy = 1; |
||
297 | |||
298 | if (hint == AF_INET || hint == AF_UNSPEC) { |
||
299 | if (inet_pton(AF_INET, str, buf) > 0) { |
||
300 | family = AF_INET; |
||
301 | len = 4; |
||
302 | goto prefix; |
||
303 | } |
||
304 | if (hint == AF_INET) { |
||
305 | err = -NLE_NOADDR; |
||
306 | goto errout; |
||
307 | } |
||
308 | } |
||
309 | |||
310 | if (hint == AF_INET6 || hint == AF_UNSPEC) { |
||
311 | if (inet_pton(AF_INET6, str, buf) > 0) { |
||
312 | family = AF_INET6; |
||
313 | len = 16; |
||
314 | goto prefix; |
||
315 | } |
||
316 | if (hint == AF_INET6) { |
||
317 | err = -NLE_NOADDR; |
||
318 | goto errout; |
||
319 | } |
||
320 | } |
||
321 | |||
322 | if ((hint == AF_LLC || hint == AF_UNSPEC) && strchr(str, ':')) { |
||
323 | unsigned int a, b, c, d, e, f; |
||
324 | |||
325 | if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x", |
||
326 | &a, &b, &c, &d, &e, &f) == 6) { |
||
327 | family = AF_LLC; |
||
328 | len = 6; |
||
329 | buf[0] = (unsigned char) a; |
||
330 | buf[1] = (unsigned char) b; |
||
331 | buf[2] = (unsigned char) c; |
||
332 | buf[3] = (unsigned char) d; |
||
333 | buf[4] = (unsigned char) e; |
||
334 | buf[5] = (unsigned char) f; |
||
335 | goto prefix; |
||
336 | } |
||
337 | |||
338 | if (hint == AF_LLC) { |
||
339 | err = -NLE_NOADDR; |
||
340 | goto errout; |
||
341 | } |
||
342 | } |
||
343 | |||
344 | if ((hint == AF_DECnet || hint == AF_UNSPEC) && |
||
345 | (strchr(str, '.') || strchr(str, ','))) { |
||
346 | if (dnet_pton(str, buf) > 0) { |
||
347 | family = AF_DECnet; |
||
348 | len = 2; |
||
349 | goto prefix; |
||
350 | } |
||
351 | if (hint == AF_DECnet) { |
||
352 | err = -NLE_NOADDR; |
||
353 | goto errout; |
||
354 | } |
||
355 | } |
||
356 | |||
357 | if (hint == AF_UNSPEC && strchr(str, ':')) { |
||
358 | int i = 0; |
||
359 | char *s = str, *p; |
||
360 | for (;;) { |
||
361 | long l = strtol(s, &p, 16); |
||
362 | |||
363 | if (s == p || l > 0xff || i >= sizeof(buf)) { |
||
364 | err = -NLE_INVAL; |
||
365 | goto errout; |
||
366 | } |
||
367 | |||
368 | buf[i++] = (unsigned char) l; |
||
369 | if (*p == '\0') |
||
370 | break; |
||
371 | s = ++p; |
||
372 | } |
||
373 | |||
374 | len = i; |
||
375 | family = AF_UNSPEC; |
||
376 | goto prefix; |
||
377 | } |
||
378 | |||
379 | err = -NLE_NOADDR; |
||
380 | goto errout; |
||
381 | |||
382 | prefix: |
||
383 | addr = nl_addr_alloc(len); |
||
384 | if (!addr) { |
||
385 | err = -NLE_NOMEM; |
||
386 | goto errout; |
||
387 | } |
||
388 | |||
389 | nl_addr_set_family(addr, family); |
||
390 | |||
391 | if (copy) |
||
392 | nl_addr_set_binary_addr(addr, buf, len); |
||
393 | |||
394 | if (prefix) { |
||
395 | char *p; |
||
396 | long pl = strtol(++prefix, &p, 0); |
||
397 | if (p == prefix) { |
||
398 | nl_addr_destroy(addr); |
||
399 | err = -NLE_INVAL; |
||
400 | goto errout; |
||
401 | } |
||
402 | nl_addr_set_prefixlen(addr, pl); |
||
403 | } else |
||
404 | nl_addr_set_prefixlen(addr, len * 8); |
||
405 | |||
406 | *result = addr; |
||
407 | err = 0; |
||
408 | errout: |
||
409 | free(str); |
||
410 | |||
411 | return err; |
||
412 | } |
||
413 | |||
414 | /** |
||
415 | * Clone existing abstract address object. |
||
416 | * @arg addr Abstract address object. |
||
417 | * @return Newly allocated abstract address object being a duplicate of the |
||
418 | * specified address object or NULL if a failure occured. |
||
419 | */ |
||
420 | struct nl_addr *nl_addr_clone(struct nl_addr *addr) |
||
421 | { |
||
422 | struct nl_addr *new; |
||
423 | |||
424 | new = nl_addr_build(addr->a_family, addr->a_addr, addr->a_len); |
||
425 | if (new) |
||
426 | new->a_prefixlen = addr->a_prefixlen; |
||
427 | |||
428 | return new; |
||
429 | } |
||
430 | |||
431 | /** @} */ |
||
432 | |||
433 | /** |
||
434 | * @name Destroying Abstract Addresses |
||
435 | * @{ |
||
436 | */ |
||
437 | |||
438 | /** |
||
439 | * Destroy abstract address object. |
||
440 | * @arg addr Abstract address object. |
||
441 | */ |
||
442 | void nl_addr_destroy(struct nl_addr *addr) |
||
443 | { |
||
444 | if (!addr) |
||
445 | return; |
||
446 | |||
447 | if (addr->a_refcnt != 1) |
||
448 | BUG(); |
||
449 | |||
450 | free(addr); |
||
451 | } |
||
452 | |||
453 | /** @} */ |
||
454 | |||
455 | /** |
||
456 | * @name Managing Usage References |
||
457 | * @{ |
||
458 | */ |
||
459 | |||
460 | struct nl_addr *nl_addr_get(struct nl_addr *addr) |
||
461 | { |
||
462 | addr->a_refcnt++; |
||
463 | |||
464 | return addr; |
||
465 | } |
||
466 | |||
467 | void nl_addr_put(struct nl_addr *addr) |
||
468 | { |
||
469 | if (!addr) |
||
470 | return; |
||
471 | |||
472 | if (addr->a_refcnt == 1) |
||
473 | nl_addr_destroy(addr); |
||
474 | else |
||
475 | addr->a_refcnt--; |
||
476 | } |
||
477 | |||
478 | /** |
||
479 | * Check whether an abstract address object is shared. |
||
480 | * @arg addr Abstract address object. |
||
481 | * @return Non-zero if the abstract address object is shared, otherwise 0. |
||
482 | */ |
||
483 | int nl_addr_shared(struct nl_addr *addr) |
||
484 | { |
||
485 | return addr->a_refcnt > 1; |
||
486 | } |
||
487 | |||
488 | /** @} */ |
||
489 | |||
490 | /** |
||
491 | * @name Miscellaneous |
||
492 | * @{ |
||
493 | */ |
||
494 | |||
495 | /** |
||
496 | * Compares two abstract address objects. |
||
497 | * @arg a A abstract address object. |
||
498 | * @arg b Another abstract address object. |
||
499 | * |
||
500 | * @return Integer less than, equal to or greather than zero if \c is found, |
||
501 | * respectively to be less than, to, or be greater than \c b. |
||
502 | */ |
||
503 | int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b) |
||
504 | { |
||
505 | int d = a->a_family - b->a_family; |
||
506 | |||
507 | if (d == 0) { |
||
508 | d = a->a_len - b->a_len; |
||
509 | |||
510 | if (a->a_len && d == 0) |
||
511 | return memcmp(a->a_addr, b->a_addr, a->a_len); |
||
512 | } |
||
513 | |||
514 | return d; |
||
515 | } |
||
516 | |||
517 | /** |
||
518 | * Compares the prefix of two abstract address objects. |
||
519 | * @arg a A abstract address object. |
||
520 | * @arg b Another abstract address object. |
||
521 | * |
||
522 | * @return Integer less than, equal to or greather than zero if \c is found, |
||
523 | * respectively to be less than, to, or be greater than \c b. |
||
524 | */ |
||
525 | int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b) |
||
526 | { |
||
527 | int d = a->a_family - b->a_family; |
||
528 | |||
529 | if (d == 0) { |
||
530 | int len = min(a->a_prefixlen, b->a_prefixlen); |
||
531 | int bytes = len / 8; |
||
532 | |||
533 | d = memcmp(a->a_addr, b->a_addr, bytes); |
||
534 | if (d == 0) { |
||
535 | int mask = (1UL << (len % 8)) - 1UL; |
||
536 | |||
537 | d = (a->a_addr[bytes] & mask) - |
||
538 | (b->a_addr[bytes] & mask); |
||
539 | } |
||
540 | } |
||
541 | |||
542 | return d; |
||
543 | } |
||
544 | |||
545 | /** |
||
546 | * Returns true if the address consists of all zeros |
||
547 | * @arg addr Address to look at. |
||
548 | */ |
||
549 | int nl_addr_iszero(struct nl_addr *addr) |
||
550 | { |
||
551 | int i; |
||
552 | |||
553 | for (i = 0; i < addr->a_len; i++) |
||
554 | if (addr->a_addr[i]) |
||
555 | return 0; |
||
556 | |||
557 | return 1; |
||
558 | } |
||
559 | |||
560 | /** |
||
561 | * Check if an address matches a certain family. |
||
562 | * @arg addr Address represented as character string. |
||
563 | * @arg family Desired address family. |
||
564 | * |
||
565 | * @return 1 if the address is of the desired address family, |
||
566 | * otherwise 0 is returned. |
||
567 | */ |
||
568 | int nl_addr_valid(char *addr, int family) |
||
569 | { |
||
570 | int ret; |
||
571 | char buf[32]; |
||
572 | |||
573 | switch (family) { |
||
574 | case AF_INET: |
||
575 | case AF_INET6: |
||
576 | ret = inet_pton(family, addr, buf); |
||
577 | if (ret <= 0) |
||
578 | return 0; |
||
579 | break; |
||
580 | |||
581 | case AF_DECnet: |
||
582 | ret = dnet_pton(addr, buf); |
||
583 | if (ret <= 0) |
||
584 | return 0; |
||
585 | break; |
||
586 | |||
587 | case AF_LLC: |
||
588 | if (sscanf(addr, "%*02x:%*02x:%*02x:%*02x:%*02x:%*02x") != 6) |
||
589 | return 0; |
||
590 | break; |
||
591 | } |
||
592 | |||
593 | return 1; |
||
594 | } |
||
595 | |||
596 | /** |
||
597 | * Guess address family of an abstract address object based on address size. |
||
598 | * @arg addr Abstract address object. |
||
599 | * @return Address family or AF_UNSPEC if guessing wasn't successful. |
||
600 | */ |
||
601 | int nl_addr_guess_family(struct nl_addr *addr) |
||
602 | { |
||
603 | switch (addr->a_len) { |
||
604 | case 4: |
||
605 | return AF_INET; |
||
606 | case 6: |
||
607 | return AF_LLC; |
||
608 | case 16: |
||
609 | return AF_INET6; |
||
610 | default: |
||
611 | return AF_UNSPEC; |
||
612 | } |
||
613 | } |
||
614 | |||
615 | /** |
||
616 | * Fill out sockaddr structure with values from abstract address object. |
||
617 | * @arg addr Abstract address object. |
||
618 | * @arg sa Destination sockaddr structure buffer. |
||
619 | * @arg salen Length of sockaddr structure buffer. |
||
620 | * |
||
621 | * Fills out the specified sockaddr structure with the data found in the |
||
622 | * specified abstract address. The salen argument needs to be set to the |
||
623 | * size of sa but will be modified to the actual size used during before |
||
624 | * the function exits. |
||
625 | * |
||
626 | * @return 0 on success or a negative error code |
||
627 | */ |
||
628 | int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa, |
||
629 | socklen_t *salen) |
||
630 | { |
||
631 | switch (addr->a_family) { |
||
632 | case AF_INET: { |
||
633 | struct sockaddr_in *sai = (struct sockaddr_in *) sa; |
||
634 | |||
635 | if (*salen < sizeof(*sai)) |
||
636 | return -NLE_INVAL; |
||
637 | |||
638 | sai->sin_family = addr->a_family; |
||
639 | memcpy(&sai->sin_addr, addr->a_addr, 4); |
||
640 | *salen = sizeof(*sai); |
||
641 | } |
||
642 | break; |
||
643 | |||
644 | case AF_INET6: { |
||
645 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa; |
||
646 | |||
647 | if (*salen < sizeof(*sa6)) |
||
648 | return -NLE_INVAL; |
||
649 | |||
650 | sa6->sin6_family = addr->a_family; |
||
651 | memcpy(&sa6->sin6_addr, addr->a_addr, 16); |
||
652 | *salen = sizeof(*sa6); |
||
653 | } |
||
654 | break; |
||
655 | |||
656 | default: |
||
657 | return -NLE_INVAL; |
||
658 | } |
||
659 | |||
660 | return 0; |
||
661 | } |
||
662 | |||
663 | |||
664 | /** @} */ |
||
665 | |||
666 | /** |
||
667 | * @name Getting Information About Addresses |
||
668 | * @{ |
||
669 | */ |
||
670 | |||
671 | /** |
||
672 | * Call getaddrinfo() for an abstract address object. |
||
673 | * @arg addr Abstract address object. |
||
674 | * @arg result Pointer to store resulting address list. |
||
675 | * |
||
676 | * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST |
||
677 | * mode. |
||
678 | * |
||
679 | * @note The caller is responsible for freeing the linked list using the |
||
680 | * interface provided by getaddrinfo(3). |
||
681 | * |
||
682 | * @return 0 on success or a negative error code. |
||
683 | */ |
||
684 | int nl_addr_info(struct nl_addr *addr, struct addrinfo **result) |
||
685 | { |
||
686 | int err; |
||
687 | char buf[INET6_ADDRSTRLEN+5]; |
||
688 | struct addrinfo hint = { |
||
689 | .ai_flags = AI_NUMERICHOST, |
||
690 | .ai_family = addr->a_family, |
||
691 | }; |
||
692 | |||
693 | nl_addr2str(addr, buf, sizeof(buf)); |
||
694 | |||
695 | err = getaddrinfo(buf, NULL, &hint, result); |
||
696 | if (err != 0) { |
||
697 | switch (err) { |
||
698 | case EAI_ADDRFAMILY: return -NLE_AF_NOSUPPORT; |
||
699 | case EAI_AGAIN: return -NLE_AGAIN; |
||
700 | case EAI_BADFLAGS: return -NLE_INVAL; |
||
701 | case EAI_FAIL: return -NLE_NOADDR; |
||
702 | case EAI_FAMILY: return -NLE_AF_NOSUPPORT; |
||
703 | case EAI_MEMORY: return -NLE_NOMEM; |
||
704 | case EAI_NODATA: return -NLE_NOADDR; |
||
705 | case EAI_NONAME: return -NLE_OBJ_NOTFOUND; |
||
706 | case EAI_SERVICE: return -NLE_OPNOTSUPP; |
||
707 | case EAI_SOCKTYPE: return -NLE_BAD_SOCK; |
||
708 | default: return -NLE_FAILURE; |
||
709 | } |
||
710 | } |
||
711 | |||
712 | return 0; |
||
713 | } |
||
714 | |||
715 | /** |
||
716 | * Resolve abstract address object to a name using getnameinfo(). |
||
717 | * @arg addr Abstract address object. |
||
718 | * @arg host Destination buffer for host name. |
||
719 | * @arg hostlen Length of destination buffer. |
||
720 | * |
||
721 | * Resolves the abstract address to a name and writes the looked up result |
||
722 | * into the host buffer. getnameinfo() is used to perform the lookup and |
||
723 | * is put into NI_NAMEREQD mode so the function will fail if the lookup |
||
724 | * couldn't be performed. |
||
725 | * |
||
726 | * @return 0 on success or a negative error code. |
||
727 | */ |
||
728 | int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen) |
||
729 | { |
||
730 | int err; |
||
731 | struct sockaddr_in6 buf; |
||
732 | socklen_t salen = sizeof(buf); |
||
733 | |||
734 | err = nl_addr_fill_sockaddr(addr, (struct sockaddr *) &buf, &salen); |
||
735 | if (err < 0) |
||
736 | return err; |
||
737 | |||
738 | err = getnameinfo((struct sockaddr *) &buf, salen, host, hostlen, |
||
739 | NULL, 0, NI_NAMEREQD); |
||
740 | if (err < 0) |
||
741 | return nl_syserr2nlerr(err); |
||
742 | |||
743 | return 0; |
||
744 | } |
||
745 | |||
746 | /** @} */ |
||
747 | |||
748 | /** |
||
749 | * @name Attributes |
||
750 | * @{ |
||
751 | */ |
||
752 | |||
753 | void nl_addr_set_family(struct nl_addr *addr, int family) |
||
754 | { |
||
755 | addr->a_family = family; |
||
756 | } |
||
757 | |||
758 | int nl_addr_get_family(struct nl_addr *addr) |
||
759 | { |
||
760 | return addr->a_family; |
||
761 | } |
||
762 | |||
763 | /** |
||
764 | * Set binary address of abstract address object. |
||
765 | * @arg addr Abstract address object. |
||
766 | * @arg buf Buffer containing binary address. |
||
767 | * @arg len Length of buffer containing binary address. |
||
768 | */ |
||
769 | int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len) |
||
770 | { |
||
771 | if (len > addr->a_maxsize) |
||
772 | return -NLE_RANGE; |
||
773 | |||
774 | addr->a_len = len; |
||
775 | memcpy(addr->a_addr, buf, len); |
||
776 | |||
777 | return 0; |
||
778 | } |
||
779 | |||
780 | /** |
||
781 | * Get binary address of abstract address object. |
||
782 | * @arg addr Abstract address object. |
||
783 | */ |
||
784 | void *nl_addr_get_binary_addr(struct nl_addr *addr) |
||
785 | { |
||
786 | return addr->a_addr; |
||
787 | } |
||
788 | |||
789 | /** |
||
790 | * Get length of binary address of abstract address object. |
||
791 | * @arg addr Abstract address object. |
||
792 | */ |
||
793 | unsigned int nl_addr_get_len(struct nl_addr *addr) |
||
794 | { |
||
795 | return addr->a_len; |
||
796 | } |
||
797 | |||
798 | void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen) |
||
799 | { |
||
800 | addr->a_prefixlen = prefixlen; |
||
801 | } |
||
802 | |||
803 | /** |
||
804 | * Get prefix length of abstract address object. |
||
805 | * @arg addr Abstract address object. |
||
806 | */ |
||
807 | unsigned int nl_addr_get_prefixlen(struct nl_addr *addr) |
||
808 | { |
||
809 | return addr->a_prefixlen; |
||
810 | } |
||
811 | |||
812 | /** @} */ |
||
813 | |||
814 | /** |
||
815 | * @name Translations to Strings |
||
816 | * @{ |
||
817 | */ |
||
818 | |||
819 | /** |
||
820 | * Convert abstract address object to character string. |
||
821 | * @arg addr Abstract address object. |
||
822 | * @arg buf Destination buffer. |
||
823 | * @arg size Size of destination buffer. |
||
824 | * |
||
825 | * Converts an abstract address to a character string and stores |
||
826 | * the result in the specified destination buffer. |
||
827 | * |
||
828 | * @return Address represented in ASCII stored in destination buffer. |
||
829 | */ |
||
830 | char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size) |
||
831 | { |
||
832 | int i; |
||
833 | char tmp[16]; |
||
834 | |||
835 | if (!addr || !addr->a_len) { |
||
836 | snprintf(buf, size, "none"); |
||
837 | if (addr) |
||
838 | goto prefix; |
||
839 | else |
||
840 | return buf; |
||
841 | } |
||
842 | |||
843 | switch (addr->a_family) { |
||
844 | case AF_INET: |
||
845 | inet_ntop(AF_INET, addr->a_addr, buf, size); |
||
846 | break; |
||
847 | |||
848 | case AF_INET6: |
||
849 | inet_ntop(AF_INET6, addr->a_addr, buf, size); |
||
850 | break; |
||
851 | |||
852 | case AF_DECnet: |
||
853 | dnet_ntop(addr->a_addr, addr->a_len, buf, size); |
||
854 | break; |
||
855 | |||
856 | case AF_LLC: |
||
857 | default: |
||
858 | snprintf(buf, size, "%02x", |
||
859 | (unsigned char) addr->a_addr[0]); |
||
860 | for (i = 1; i < addr->a_len; i++) { |
||
861 | snprintf(tmp, sizeof(tmp), ":%02x", |
||
862 | (unsigned char) addr->a_addr[i]); |
||
863 | strncat(buf, tmp, size - strlen(buf) - 1); |
||
864 | } |
||
865 | break; |
||
866 | } |
||
867 | |||
868 | prefix: |
||
869 | if (addr->a_prefixlen != (8 * addr->a_len)) { |
||
870 | snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen); |
||
871 | strncat(buf, tmp, size - strlen(buf) - 1); |
||
872 | } |
||
873 | |||
874 | return buf; |
||
875 | } |
||
876 | |||
877 | /** @} */ |
||
878 | |||
879 | /** |
||
880 | * @name Address Family Transformations |
||
881 | * @{ |
||
882 | */ |
||
883 | |||
884 | static struct trans_tbl afs[] = { |
||
885 | __ADD(AF_UNSPEC,unspec) |
||
886 | __ADD(AF_UNIX,unix) |
||
887 | __ADD(AF_LOCAL,local) |
||
888 | __ADD(AF_INET,inet) |
||
889 | __ADD(AF_AX25,ax25) |
||
890 | __ADD(AF_IPX,ipx) |
||
891 | __ADD(AF_APPLETALK,appletalk) |
||
892 | __ADD(AF_NETROM,netrom) |
||
893 | __ADD(AF_BRIDGE,bridge) |
||
894 | __ADD(AF_ATMPVC,atmpvc) |
||
895 | __ADD(AF_X25,x25) |
||
896 | __ADD(AF_INET6,inet6) |
||
897 | __ADD(AF_ROSE,rose) |
||
898 | __ADD(AF_DECnet,decnet) |
||
899 | __ADD(AF_NETBEUI,netbeui) |
||
900 | __ADD(AF_SECURITY,security) |
||
901 | __ADD(AF_KEY,key) |
||
902 | __ADD(AF_NETLINK,netlink) |
||
903 | __ADD(AF_ROUTE,route) |
||
904 | __ADD(AF_PACKET,packet) |
||
905 | __ADD(AF_ASH,ash) |
||
906 | __ADD(AF_ECONET,econet) |
||
907 | __ADD(AF_ATMSVC,atmsvc) |
||
908 | __ADD(AF_SNA,sna) |
||
909 | __ADD(AF_IRDA,irda) |
||
910 | __ADD(AF_PPPOX,pppox) |
||
911 | __ADD(AF_WANPIPE,wanpipe) |
||
912 | __ADD(AF_LLC,llc) |
||
913 | __ADD(AF_BLUETOOTH,bluetooth) |
||
914 | }; |
||
915 | |||
916 | char *nl_af2str(int family, char *buf, size_t size) |
||
917 | { |
||
918 | return __type2str(family, buf, size, afs, ARRAY_SIZE(afs)); |
||
919 | } |
||
920 | |||
921 | int nl_str2af(const char *name) |
||
922 | { |
||
923 | int fam = __str2type(name, afs, ARRAY_SIZE(afs)); |
||
924 | return fam >= 0 ? fam : AF_UNSPEC; |
||
925 | } |
||
926 | |||
927 | /** @} */ |
||
928 | |||
929 | /** @} */ |