All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
inet.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License, version 2 of the
4  * License as published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software
13  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14  */
15 
16 /**
17  * $Id: ed80ebf93d2cc5717b54e17f63706710602c2ea4 $
18  * @file inet.c
19  * @brief Functions to parse, print, mask and retrieve IP addresses
20  *
21  * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22  * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  */
24 #include <freeradius-devel/inet.h>
25 #include <freeradius-devel/libradius.h>
26 #include <ctype.h>
27 
28 bool fr_dns_lookups = false; //!< IP -> hostname lookups?
29 bool fr_hostname_lookups = true; //!< hostname -> IP lookups?
30 
31 /** Mask off a portion of an IPv4 address
32  *
33  * @param ipaddr to mask.
34  * @param prefix Number of contiguous bits to mask.
35  * @return an ipv4 address with the host portion zeroed out.
36  */
37 static struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
38 {
39  uint32_t ret;
40 
41  if (prefix > 32) prefix = 32;
42 
43  /* Short circuit */
44  if (prefix == 32) return *ipaddr;
45 
46  if (prefix == 0) ret = 0;
47  else ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
48 
49  return (*(struct in_addr *)&ret);
50 }
51 
52 /** Mask off a portion of an IPv6 address
53  *
54  * @param ipaddr to mask.
55  * @param prefix Number of contiguous bits to mask.
56  * @return an ipv6 address with the host portion zeroed out.
57  */
58 static struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
59 {
60  uint64_t const *p = (uint64_t const *) ipaddr;
61  uint64_t ret[2], *o = ret;
62 
63  if (prefix > 128) prefix = 128;
64 
65  /* Short circuit */
66  if (prefix == 128) return *ipaddr;
67 
68  if (prefix >= 64) {
69  prefix -= 64;
70  *o++ = 0xffffffffffffffffULL & *p++; /* lhs portion masked */
71  } else {
72  ret[1] = 0; /* rhs portion zeroed */
73  }
74 
75  /* Max left shift is 63 else we get overflow */
76  if (prefix > 0) {
77  *o = htonll(~((uint64_t)(0x0000000000000001ULL << (64 - prefix)) - 1)) & *p;
78  } else {
79  *o = 0;
80  }
81 
82  return *(struct in6_addr *) &ret;
83 }
84 
85 /** Zeroes out the host portion of an fr_ipaddr_t
86  *
87  * @param[in,out] addr to mask
88  * @param[in] prefix Length of the network portion.
89  */
90 void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
91 {
92 
93  switch (addr->af) {
94  case AF_INET:
95  addr->ipaddr.ip4addr = fr_inaddr_mask(&addr->ipaddr.ip4addr, prefix);
96  break;
97 
98  case AF_INET6:
99  addr->ipaddr.ip6addr = fr_in6addr_mask(&addr->ipaddr.ip6addr, prefix);
100  break;
101 
102  default:
103  return;
104  }
105  addr->prefix = prefix;
106 }
107 
108 /** Wrappers for IPv4/IPv6 host to IP address lookup
109  *
110  * This function returns only one IP address, of the specified address family,
111  * or the first address (of whatever family), if AF_UNSPEC is used.
112  *
113  * If fallback is specified and af is AF_INET, but not AF_INET records were
114  * found and a record for AF_INET6 exists that record will be returned.
115  *
116  * If fallback is specified and af is AF_INET6, and a record with AF_INET4 exists
117  * that record will be returned inseted.
118  *
119  * @param[out] out Where to write result.
120  * @param[in] af To search for in preference.
121  * @param[in] hostname to search for.
122  * @param[in] fallback to the other address family, if no records matching af, found.
123  * @return
124  * - 0 on success.
125  * - -1 on failure.
126  */
127 int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
128 {
129  int rcode;
130  struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
131 
132  /*
133  * Avoid malloc for IP addresses. This helps us debug
134  * memory errors when using talloc.
135  */
136 #ifdef TALLOC_DEBUG
137  if (true) {
138 #else
139  if (!fr_hostname_lookups) {
140 #endif
141 #ifdef HAVE_STRUCT_SOCKADDR_IN6
142  if (af == AF_UNSPEC) {
143  char const *p;
144 
145  for (p = hostname; *p != '\0'; p++) {
146  if ((*p == ':') ||
147  (*p == '[') ||
148  (*p == ']')) {
149  af = AF_INET6;
150  break;
151  }
152  }
153  }
154 #endif
155 
156  if (af == AF_UNSPEC) af = AF_INET;
157 
158  if (!inet_pton(af, hostname, &(out->ipaddr))) return -1;
159 
160  out->af = af;
161  return 0;
162  }
163 
164  memset(&hints, 0, sizeof(hints));
165 
166  /*
167  * If we're falling back we need both IPv4 and IPv6 records
168  */
169  if (fallback) {
170  hints.ai_family = AF_UNSPEC;
171  } else {
172  hints.ai_family = af;
173  }
174 
175  if ((rcode = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
176  switch (af) {
177  default:
178  case AF_UNSPEC:
179  fr_strerror_printf("Failed resolving \"%s\" to IP address: %s",
180  hostname, gai_strerror(rcode));
181  return -1;
182 
183  case AF_INET:
184  fr_strerror_printf("Failed resolving \"%s\" to IPv4 address: %s",
185  hostname, gai_strerror(rcode));
186  return -1;
187 
188  case AF_INET6:
189  fr_strerror_printf("Failed resolving \"%s\" to IPv6 address: %s",
190  hostname, gai_strerror(rcode));
191  return -1;
192  }
193  }
194 
195  for (ai = res; ai; ai = ai->ai_next) {
196  if ((af == ai->ai_family) || (af == AF_UNSPEC)) break;
197  if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
198  }
199 
200  if (!ai) ai = alt;
201  if (!ai) {
202  fr_strerror_printf("fr_inet_hton failed to find requested information for host %.100s", hostname);
203  freeaddrinfo(res);
204  return -1;
205  }
206 
207  rcode = fr_ipaddr_from_sockaddr((struct sockaddr_storage *)ai->ai_addr,
208  ai->ai_addrlen, out, NULL);
209  freeaddrinfo(res);
210  if (!rcode) {
211  fr_strerror_printf("Failed converting sockaddr to ipaddr");
212  return -1;
213  }
214 
215  return 0;
216 }
217 
218 /** Perform reverse resolution of an IP address
219  *
220  * Attempt to resolve an IP address to a DNS record (if dns lookups are enabled).
221  *
222  * @param[in] src address to resolve.
223  * @param[out] out Where to write the resulting hostname.
224  * @param[in] outlen length of the output buffer.
225  */
226 char const *fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
227 {
228  struct sockaddr_storage ss;
229  int error;
230  socklen_t salen;
231 
232  /*
233  * No DNS lookups
234  */
235  if (!fr_dns_lookups) {
236  return inet_ntop(src->af, &(src->ipaddr), out, outlen);
237  }
238 
239  if (!fr_ipaddr_to_sockaddr(src, 0, &ss, &salen)) {
240  return NULL;
241  }
242 
243  if ((error = getnameinfo((struct sockaddr *)&ss, salen, out, outlen, NULL, 0,
244  NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
245  fr_strerror_printf("fr_inet_ntoh: %s", gai_strerror(error));
246  return NULL;
247  }
248  return out;
249 }
250 
251 
252 /** Parse a single octet of an IPv4 address string
253  *
254  * @param[out] out Where to write integer.
255  * @param[in] str to parse.
256  * @return
257  * - >= 0 on success (number of bytes parsed of in).
258  * - < 0 on error.
259  */
260 static int ip_octet_from_str(uint32_t *out, char const *str)
261 {
262  uint32_t octet;
263  char const *p = str;
264 
265  if ((*p < '0') || (*p > '9')) return -1;
266 
267  octet = 0;
268 
269  while ((*p >= '0') && (*p <= '9')) {
270  octet *= 10;
271  octet += *p - '0';
272  p++;
273 
274  if (octet > 255) return -1;
275  }
276 
277  *out = octet;
278  return p - str;
279 }
280 
281 /** Parses the network portion of an IPv4 prefix into an in_addr
282  *
283  * @note output is in network order.
284  *
285  * Parses address strings in dotted quad notation.
286  * Unlike inet_pton allows octets to be omitted, in which case their value is considered to be 0.
287  * Unlike inet_aton treats integers as representing the highest octet of an IPv4 address, and
288  * limits them to 255.
289  *
290  * Examples of acceptable strings:
291  * - 192.168.0.0
292  * - 192.168.0.0/24
293  * - 192.168/16
294  * - 192
295  * - 192/8
296  *
297  * @param[out] out Where to write parsed address.
298  * @param[in] str to parse.
299  * @return
300  * - >= 0 on success (number of bytes parsed of in).
301  * - < 0 on error.
302  */
303 static int ip_prefix_addr_from_str(struct in_addr *out, char const *str)
304 {
305  int shift, length;
306  uint32_t octet;
307  uint32_t addr;
308  char const *p = str;
309 
310  addr = 0;
311  out->s_addr = 0;
312 
313  for (shift = 24; shift >= 0; shift -= 8) {
314  length = ip_octet_from_str(&octet, p);
315  if (length <= 0) return -1;
316 
317  addr |= octet << shift;
318  p += length;
319 
320  /*
321  * EOS or / means we're done.
322  */
323  if (!*p || (*p == '/')) break;
324 
325  /*
326  * We require dots between octets.
327  */
328  if (*p != '.') return -1;
329  p++;
330  }
331 
332  out->s_addr = htonl(addr);
333  return p - str;
334 }
335 
336 /** Parse an IPv4 address or IPv4 prefix in presentation format (and others)
337  *
338  * @param out Where to write the ip address value.
339  * @param value to parse, may be dotted quad [+ prefix], or integer, or octal number, or '*' (INADDR_ANY).
340  * @param inlen Length of value, if value is \0 terminated inlen may be -1.
341  * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
342  * @param fallback to IPv6 resolution if no A records can be found.
343  * @param mask_bits If true, set address bits to zero.
344  * @return
345  * - 0 if ip address was parsed successfully.
346  * - -1 on failure.
347  */
348 int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask_bits)
349 {
350  char *p;
351  unsigned int mask;
352  char *eptr;
353 
354  /* Dotted quad + / + [0-9]{1,2} */
355  char buffer[INET_ADDRSTRLEN + 3];
356 
357  /*
358  * Copy to intermediary buffer if we were given a length
359  */
360  if (inlen >= 0) {
361  if (inlen >= (ssize_t)sizeof(buffer)) {
362  fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
363  return -1;
364  }
365  memcpy(buffer, value, inlen);
366  buffer[inlen] = '\0';
367  value = buffer;
368  }
369 
370  p = strchr(value, '/');
371 
372  /*
373  * 192.0.2.2 is parsed as if it was /32
374  */
375  if (!p) {
376  out->prefix = 32;
377  out->af = AF_INET;
378 
379  /*
380  * Allow '*' as the wildcard address usually 0.0.0.0
381  */
382  if ((value[0] == '*') && (value[1] == '\0')) {
383  out->ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
384 
385  /*
386  * Convert things which are obviously integers to IP addresses
387  *
388  * We assume the number is the bigendian representation of the
389  * IP address.
390  */
391  } else if (is_integer(value) || ((value[0] == '0') && (value[1] == 'x'))) {
392  out->ipaddr.ip4addr.s_addr = htonl(strtoul(value, NULL, 0));
393 
394  } else if (!resolve) {
395  if (inet_pton(AF_INET, value, &out->ipaddr.ip4addr.s_addr) <= 0) {
396  fr_strerror_printf("Failed to parse IPv4 addreess string \"%s\"", value);
397  return -1;
398  }
399  } else if (fr_inet_hton(out, AF_INET, value, fallback) < 0) return -1;
400 
401  return 0;
402  }
403 
404  /*
405  * Otherwise parse the prefix
406  */
407  if ((size_t)(p - value) >= INET_ADDRSTRLEN) {
408  fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
409  return -1;
410  }
411 
412  /*
413  * Copy the IP portion into a temporary buffer if we haven't already.
414  */
415  if (inlen < 0) memcpy(buffer, value, p - value);
416  buffer[p - value] = '\0';
417 
418  /*
419  * We need a special function here, as inet_pton doesn't like
420  * address strings with octets omitted, and inet_aton treats
421  * 127 as an integer value, and sets the lowest octet of the
422  * prefix to 127 instead of the highest.
423  *
424  * @todo we should allow hostnames to be parsed as prefixes.
425  */
426  if (ip_prefix_addr_from_str(&out->ipaddr.ip4addr, buffer) <= 0) {
427  fr_strerror_printf("Failed to parse IPv4 prefix string \"%s\"", value);
428  return -1;
429  }
430 
431  mask = strtoul(p + 1, &eptr, 10);
432  if (mask > 32) {
433  fr_strerror_printf("Invalid IPv4 mask length \"%s\". Should be between 0-32", p);
434  return -1;
435  }
436 
437  if (eptr[0] != '\0') {
438  fr_strerror_printf("Failed to parse IPv4 prefix string \"%s\", "
439  "got garbage after mask length \"%s\"", value, eptr);
440  return -1;
441  }
442 
443  if (mask_bits && (mask < 32)) {
444  out->ipaddr.ip4addr = fr_inaddr_mask(&out->ipaddr.ip4addr, mask);
445  }
446 
447  out->prefix = (uint8_t) mask;
448  out->af = AF_INET;
449 
450  return 0;
451 }
452 
453 /** Parse an IPv6 address or IPv6 prefix in presentation format (and others)
454  *
455  * @param out Where to write the ip address value.
456  * @param value to parse.
457  * @param inlen Length of value, if value is \0 terminated inlen may be -1.
458  * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
459  * @param fallback to IPv4 resolution if no AAAA records can be found.
460  * @param mask If true, set address bits to zero.
461  * @return
462  * - 0 if ip address was parsed successfully.
463  * - -1 on failure.
464  */
465 int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
466 {
467  char const *p;
468  unsigned int prefix;
469  char *eptr;
470 
471  /* IPv6 + / + [0-9]{1,3} */
472  char buffer[INET6_ADDRSTRLEN + 4];
473 
474  /*
475  * Copy to intermediary buffer if we were given a length
476  */
477  if (inlen >= 0) {
478  if (inlen >= (ssize_t)sizeof(buffer)) {
479  fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
480  return -1;
481  }
482  memcpy(buffer, value, inlen);
483  buffer[inlen] = '\0';
484  value = buffer;
485  }
486 
487  p = strchr(value, '/');
488  if (!p) {
489  out->prefix = 128;
490  out->af = AF_INET6;
491 
492  /*
493  * Allow '*' as the wildcard address
494  */
495  if ((value[0] == '*') && (value[1] == '\0')) {
496  memset(out->ipaddr.ip6addr.s6_addr, 0, sizeof(out->ipaddr.ip6addr.s6_addr));
497  } else if (!resolve) {
498  if (inet_pton(AF_INET6, value, out->ipaddr.ip6addr.s6_addr) <= 0) {
499  fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
500  return -1;
501  }
502  } else if (fr_inet_hton(out, AF_INET6, value, fallback) < 0) return -1;
503 
504  return 0;
505  }
506 
507  if ((p - value) >= INET6_ADDRSTRLEN) {
508  fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
509  return -1;
510  }
511 
512  /*
513  * Copy string to temporary buffer if we didn't do it earlier
514  */
515  if (inlen < 0) memcpy(buffer, value, p - value);
516  buffer[p - value] = '\0';
517 
518  if (!resolve) {
519  if (inet_pton(AF_INET6, buffer, out->ipaddr.ip6addr.s6_addr) <= 0) {
520  fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
521  return -1;
522  }
523  } else if (fr_inet_hton(out, AF_INET6, buffer, fallback) < 0) return -1;
524 
525  prefix = strtoul(p + 1, &eptr, 10);
526  if (prefix > 128) {
527  fr_strerror_printf("Invalid IPv6 mask length \"%s\". Should be between 0-128", p);
528  return -1;
529  }
530  if (eptr[0] != '\0') {
531  fr_strerror_printf("Failed to parse IPv6 address string \"%s\", "
532  "got garbage after mask length \"%s\"", value, eptr);
533  return -1;
534  }
535 
536  if (mask && (prefix < 128)) {
537  struct in6_addr addr;
538 
539  addr = fr_in6addr_mask(&out->ipaddr.ip6addr, prefix);
540  memcpy(out->ipaddr.ip6addr.s6_addr, addr.s6_addr, sizeof(out->ipaddr.ip6addr.s6_addr));
541  }
542 
543  out->prefix = (uint8_t) prefix;
544  out->af = AF_INET6;
545 
546  return 0;
547 }
548 
549 /** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser
550  *
551  * @param[out] out Where to write the ip address value.
552  * @param[in] value to parse.
553  * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
554  * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value as a
555  * hostname.
556  * @param[in] af If the address type is not obvious from the format, and resolve is true, the DNS
557  * record (A or AAAA) we require. Also controls which parser we pass the address to if
558  * we have no idea what it is.
559  * @param[in] mask If true, set address bits to zero.
560  * @return
561  * - 0 if ip address was parsed successfully.
562  * - -1 on failure.
563  */
564 int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
565 {
566  size_t len, i;
567 
568  len = (inlen >= 0) ? (size_t)inlen : strlen(value);
569  for (i = 0; i < len; i++) switch (value[i]) {
570  /*
571  * ':' is illegal in domain names and IPv4 addresses.
572  * Must be v6 and cannot be a domain.
573  */
574  case ':':
575  return fr_inet_pton6(out, value, inlen, false, false, mask);
576 
577  /*
578  * Chars which don't really tell us anything
579  */
580  case '.':
581  case '/':
582  continue;
583 
584  default:
585  /*
586  * Outside the range of IPv4 chars, must be a domain
587  * Use A record in preference to AAAA record.
588  */
589  if ((value[i] < '0') || (value[i] > '9')) {
590  if (!resolve) {
591  fr_strerror_printf("Not IPv4/6 address, and asked not to resolve");
592  return -1;
593  }
594  switch (af) {
595  case AF_UNSPEC:
596  return fr_inet_pton4(out, value, inlen, resolve, true, mask);
597 
598  case AF_INET:
599  return fr_inet_pton4(out, value, inlen, resolve, false, mask);
600 
601  case AF_INET6:
602  return fr_inet_pton6(out, value, inlen, resolve, false, mask);
603 
604  default:
605  fr_strerror_printf("Invalid address family %i", af);
606  return -1;
607  }
608  }
609  break;
610  }
611 
612  /*
613  * All chars were in the IPv4 set [0-9/.], must be an IPv4
614  * address.
615  */
616  return fr_inet_pton4(out, value, inlen, false, false, mask);
617 }
618 
619 /** Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
620  *
621  * @param[out] out Where to write the ip address value.
622  * @param[out] port_out Where to write the port (0 if no port found).
623  * @param[in] value to parse.
624  * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
625  * @param[in] af If the address type is not obvious from the format, and resolve is true, the DNS
626  * record (A or AAAA) we require. Also controls which parser we pass the address to if
627  * we have no idea what it is.
628  * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value as a
629  * hostname.
630  * @param[in] mask If true, set address bits to zero.
631  */
632 int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value,
633  ssize_t inlen, int af, bool resolve, bool mask)
634 {
635  char const *p = value, *q;
636  char *end;
637  unsigned long port;
638  char buffer[6];
639  size_t len;
640 
641  *port_out = 0;
642 
643  len = (inlen >= 0) ? (size_t)inlen : strlen(value);
644 
645  if (*p == '[') {
646  if (!(q = memchr(p + 1, ']', len - 1))) {
647  fr_strerror_printf("Missing closing ']' for IPv6 address");
648  return -1;
649  }
650 
651  /*
652  * inet_pton doesn't like the address being wrapped in []
653  */
654  if (fr_inet_pton6(out, p + 1, (q - p) - 1, false, false, mask) < 0) return -1;
655 
656  if (q[1] == ':') {
657  q++;
658  goto do_port;
659  }
660 
661  return 0;
662  }
663 
664  /*
665  * Host, IPv4 or IPv6 with no port
666  */
667  q = memchr(p, ':', len);
668  if (!q) return fr_inet_pton(out, p, len, af, resolve, mask);
669 
670  /*
671  * IPv4 or host, with port
672  */
673  if (fr_inet_pton(out, p, (q - p), af, resolve, mask) < 0) return -1;
674 do_port:
675  /*
676  * Valid ports are a maximum of 5 digits, so if the
677  * input length indicates there are more than 5 chars
678  * after the ':' then there's an issue.
679  */
680  if (inlen > ((q + sizeof(buffer)) - value)) {
681  error:
682  fr_strerror_printf("IP string contains trailing garbage after port delimiter");
683  return -1;
684  }
685 
686  p = q + 1; /* Move to first digit */
687 
688  strlcpy(buffer, p, (len - (p - value)) + 1);
689  port = strtoul(buffer, &end, 10);
690  if (*end != '\0') goto error; /* Trailing garbage after integer */
691 
692  if ((port > UINT16_MAX) || (port == 0)) {
693  fr_strerror_printf("Port %lu outside valid port range 1-" STRINGIFY(UINT16_MAX), port);
694  return -1;
695  }
696  *port_out = port;
697 
698  return 0;
699 }
700 
701 /** Print the address portion of a #fr_ipaddr_t
702  *
703  * @note Includes the textual zone_id name (eth0, en0 etc...) if supported.
704  *
705  * @param[out] out Where to write the resulting IP string.
706  * Should be at least FR_IPADDR_STRLEN bytes.
707  * @param[in] outlen of output buffer.
708  * @param[in] addr to convert to presentation format.
709  * @return
710  * - NULL on error (use fr_syserror(errno)).
711  * - a pointer to out on success.
712  */
713 char *fr_inet_ntop(char out[FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t *addr)
714 {
715  char *p;
716  size_t len;
717 
718  if (inet_ntop(addr->af, &addr->ipaddr, out, outlen) == NULL) return NULL;
719 
720  if ((addr->af == AF_INET) || (addr->zone_id == 0)) return out;
721 
722  p = out + strlen(out);
723 
724 #ifdef WITH_IFINDEX_NAME_RESOLUTION
725  {
726  char buffer[IFNAMSIZ];
727  char *ifname;
728 
729  ifname = fr_ifname_from_ifindex(buffer, addr->zone_id);
730  if (ifname) {
731  len = snprintf(p, outlen - (p - out), "%%%s", ifname);
732  if (is_truncated(len + (p - out), outlen)) {
733  fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
734  (p - out) + len, outlen);
735  return NULL;
736  }
737  }
738  return out;
739  }
740 #endif
741 
742  len = snprintf(p, outlen - (p - out), "%%%i", addr->zone_id);
743  if (is_truncated(len + (p - out), outlen)) {
744  fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
745  (p - out) + len, outlen);
746  return NULL;
747  }
748 
749  return out;
750 }
751 
752 /** Print a #fr_ipaddr_t as a CIDR style network prefix
753  *
754  * @param[out] out Where to write the resulting prefix string.
755  * Should be at least FR_IPADDR_PREFIX_STRLEN bytes.
756  * @param[in] outlen of output buffer.
757  * @param[in] addr to convert to presentation format.
758  * @return
759  * - NULL on error (use fr_syserror(errno)).
760  * - a pointer to out on success.
761  */
762 char *fr_inet_ntop_prefix(char out[FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t *addr)
763 {
764  char *p;
765  size_t len;
766 
767  if (fr_inet_ntop(out, outlen, addr) == NULL) return NULL;
768 
769  p = out + strlen(out);
770 
771  len = snprintf(p, outlen - (p - out), "/%i", addr->prefix);
772  if (is_truncated(len + (p - out), outlen)) {
773  fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
774  (p - out) + len, outlen);
775  return NULL;
776  }
777 
778  return out;
779 }
780 
781 /** Print an interface-id in standard colon notation
782  *
783  * @param[out] out Where to write the resulting interface-id string.
784  * @param[in] outlen of output buffer.
785  * @param[in] ifid to print.
786  * @return a pointer to out.
787  */
788 char *fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
789 {
790  snprintf(out, outlen, "%x:%x:%x:%x",
791  (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
792  (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
793  return out;
794 }
795 
796 /** Convert interface-id in colon notation to 8 byte binary form
797  *
798  * @param[out] out Where to write the binary interface-id.
799  * @param[in] ifid_str to parse.
800  * @return a pointer to out.
801  */
802 uint8_t *fr_inet_ifid_pton(uint8_t out[8], char const *ifid_str)
803 {
804  static char const xdigits[] = "0123456789abcdef";
805  char const *p, *pch;
806  int num_id = 0, val = 0, idx = 0;
807 
808  for (p = ifid_str; ; ++p) {
809  if (*p == ':' || *p == '\0') {
810  if (num_id <= 0)
811  return NULL;
812 
813  /*
814  * Drop 'val' into the array.
815  */
816  out[idx] = (val >> 8) & 0xff;
817  out[idx + 1] = val & 0xff;
818  if (*p == '\0') {
819  /*
820  * Must have all entries before
821  * end of the string.
822  */
823  if (idx != 6)
824  return NULL;
825  break;
826  }
827  val = 0;
828  num_id = 0;
829  if ((idx += 2) > 6)
830  return NULL;
831  } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
832  if (++num_id > 4)
833  return NULL;
834  /*
835  * Dumb version of 'scanf'
836  */
837  val <<= 4;
838  val |= (pch - xdigits);
839  } else
840  return NULL;
841  }
842  return out;
843 }
844 
845 #ifdef SIOCGIFADDR
846 /** Retrieve the primary IP address associated with an interface
847  *
848  * @param[out] out The primary IP address associated with the named interface.
849  * @param[in] af of IP address to retrieve (AF_INET or AF_INET6).
850  * @param[in] name of interface.
851  * @return
852  * - 0 on success.
853  * - -1 on failure.
854  */
855 int fr_ipaddr_from_ifname(fr_ipaddr_t *out, int af, char const *name)
856 {
857  int fd;
858  struct ifreq if_req;
859  fr_ipaddr_t ipaddr;
860 
861  memset(&if_req, 0, sizeof(if_req));
862  memset(out, 0, sizeof(*out));
863 
864  /*
865  * Set the interface we're resolving, and the address family.
866  */
867  if_req.ifr_addr.sa_family = af;
868  strlcpy(if_req.ifr_name, name, sizeof(if_req.ifr_name));
869 
870  fd = socket(AF_INET, SOCK_DGRAM, 0);
871  if (fd < 0) {
872  fr_strerror_printf("Failed opening temporary socket for SIOCGIFADDR: %s", fr_syserror(errno));
873  error:
874  close(fd);
875  return -1;
876  }
877  if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
878  fr_strerror_printf("Failed determining address for interface %s: %s", name, fr_syserror(errno));
879  goto error;
880  }
881 
882  /*
883  * There's nothing in the ifreq struct that gives us the length
884  * of the sockaddr struct, so we just use sizeof here.
885  * sockaddr2ipaddr uses the address family anyway, so we should
886  * be OK.
887  */
888  if (fr_ipaddr_from_sockaddr((struct sockaddr_storage *)&if_req.ifr_addr,
889  sizeof(if_req.ifr_addr), &ipaddr, NULL) == 0) goto error;
890  *out = ipaddr;
891 
892  close(fd);
893 
894  return 0;
895 }
896 #else
897 int fr_ipaddr_from_ifname(UNUSED fr_ipaddr_t *out, UNUSED int af, char const *name)
898 {
899  fr_strerror_printf("No support for SIOCGIFADDR, can't determine IP address of %s", name);
900  return -1;
901 }
902 #endif
903 
904 #ifdef WITH_IFINDEX_NAME_RESOLUTION
905 /** Resolve if_index to interface name
906  *
907  * @param[out] out Buffer to use to store the name, must be at least IFNAMSIZ bytes.
908  * @parma[in] if_index to resolve to name.
909  * @return
910  * - NULL on error.
911  * - a pointer to out on success.
912  */
913 char *fr_ifname_from_ifindex(char out[IFNAMSIZ], int if_index)
914 {
915 #ifdef HAVE_IF_INDEXTONAME
916  if (!if_indextoname(if_index, out)) {
917  fr_strerror_printf("Failed resolving interface index %i to name", if_index);
918  return NULL;
919  }
920 #else
921  struct ifreq if_req;
922  int fd;
923 
924  memset(&if_req, 0, sizeof(if_req));
925  if_req.ifr_ifindex = if_index;
926 
927  fd = socket(AF_INET, SOCK_DGRAM, 0);
928  if (fd < 0) {
929  fr_strerror_printf("Failed opening temporary socket for SIOCGIFADDR: %s", fr_syserror(errno));
930  error:
931  close(fd);
932  return NULL;
933  }
934 
935  /*
936  * First we resolve the interface index to the interface name
937  * Which is pretty inefficient, but it seems the only way to
938  * identify interfaces for SIOCG* operations is with the interface
939  * name.
940  */
941  if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
942  fr_strerror_printf("Failed resolving interface index %i to name: %s", if_index, fr_syserror(errno));
943  goto error;
944  }
945  strlcpy(out, if_req.ifr_name, IFNAMSIZ);
946  close(fd);
947 #endif
948  return out;
949 }
950 #endif
951 
952 #ifdef WITH_IFINDEX_IPADDR_RESOLUTION
953 /** Returns the primary IP address for a given interface index
954  *
955  * @note Intended to be used with udpfromto (recvfromto) to retrieve the
956  * source IP address to use when responding to broadcast packets.
957  *
958  * @note Will likely be quite slow due to the number of system calls.
959  *
960  * @param[out] out Where to write the primary IP address.
961  * @param[in] fd File descriptor of any datagram or raw socket.
962  * @param[in] af to get interface for.
963  * @param[in] if_index of interface to get IP address for.
964  * @return
965  * - 0 on success.
966  * - -1 on failure.
967  */
968 int fr_ipaddr_from_ifindex(fr_ipaddr_t *out, int fd, int af, int if_index)
969 {
970  struct ifreq if_req;
971  fr_ipaddr_t ipaddr;
972 
973  memset(&if_req, 0, sizeof(if_req));
974  memset(out, 0, sizeof(*out));
975 
976 #ifdef SIOCGIFNAME
977  if_req.ifr_ifindex = if_index;
978  /*
979  * First we resolve the interface index to the interface name
980  * Which is pretty inefficient, but it seems the only way to
981  * identify interfaces for SIOCG* operations is with the interface
982  * name.
983  */
984  if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
985  fr_strerror_printf("Failed resolving interface index %i to name: %s", if_index, fr_syserror(errno));
986  return -1;
987  }
988 #elsif defined(HAVE_IF_INDEXTONAME)
989  if (!if_indextoname(if_index, if_req.ifr_name)) {
990  fr_strerror_printf("Failed resolving interface index %i to name", if_index);
991  return -1;
992  }
993 #else
994 # error Need SIOCGIFNAME or if_indextoname
995 #endif
996 
997  /*
998  * Name should now be present in if_req, so we just need to
999  * set the address family.
1000  */
1001  if_req.ifr_addr.sa_family = af;
1002 
1003  if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1004  fr_strerror_printf("Failed determining address for interface %s: %s",
1005  if_req.ifr_name, fr_syserror(errno));
1006  return -1;
1007  }
1008 
1009  /*
1010  * There's nothing in the ifreq struct that gives us the length
1011  * of the sockaddr struct, so we just use sizeof here.
1012  * sockaddr2ipaddr uses the address family anyway, so we should
1013  * be OK.
1014  */
1015  if (fr_ipaddr_from_sockaddr((struct sockaddr_storage *)&if_req.ifr_addr,
1016  sizeof(if_req.ifr_addr), &ipaddr, NULL) == 0) return -1;
1017  *out = ipaddr;
1018 
1019  return 0;
1020 }
1021 #endif
1022 
1023 /** Compare two ip addresses
1024  *
1025  */
1026 int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
1027 {
1028  if (a->af < b->af) return -1;
1029  if (a->af > b->af) return +1;
1030 
1031  if (a->prefix < b->prefix) return -1;
1032  if (a->prefix > b->prefix) return +1;
1033 
1034  switch (a->af) {
1035  case AF_INET:
1036  return memcmp(&a->ipaddr.ip4addr,
1037  &b->ipaddr.ip4addr,
1038  sizeof(a->ipaddr.ip4addr));
1039 
1040 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1041  case AF_INET6:
1042  if (a->zone_id < b->zone_id) return -1;
1043  if (a->zone_id > b->zone_id) return +1;
1044 
1045  return memcmp(&a->ipaddr.ip6addr,
1046  &b->ipaddr.ip6addr,
1047  sizeof(a->ipaddr.ip6addr));
1048 #endif
1049 
1050  default:
1051  break;
1052  }
1053 
1054  return -1;
1055 }
1056 
1057 int fr_ipaddr_to_sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port,
1058  struct sockaddr_storage *sa, socklen_t *salen)
1059 {
1060  memset(sa, 0, sizeof(*sa));
1061 
1062  if (ipaddr->af == AF_INET) {
1063  struct sockaddr_in s4;
1064 
1065  *salen = sizeof(s4);
1066 
1067  memset(&s4, 0, sizeof(s4));
1068  s4.sin_family = AF_INET;
1069  s4.sin_addr = ipaddr->ipaddr.ip4addr;
1070  s4.sin_port = htons(port);
1071  memset(sa, 0, sizeof(*sa));
1072  memcpy(sa, &s4, sizeof(s4));
1073 
1074 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1075  } else if (ipaddr->af == AF_INET6) {
1076  struct sockaddr_in6 s6;
1077 
1078  *salen = sizeof(s6);
1079 
1080  memset(&s6, 0, sizeof(s6));
1081  s6.sin6_family = AF_INET6;
1082  s6.sin6_addr = ipaddr->ipaddr.ip6addr;
1083  s6.sin6_port = htons(port);
1084  s6.sin6_scope_id = ipaddr->zone_id;
1085  memset(sa, 0, sizeof(*sa));
1086  memcpy(sa, &s6, sizeof(s6));
1087 #endif
1088  } else {
1089  return 0;
1090  }
1091 
1092  return 1;
1093 }
1094 
1095 int fr_ipaddr_from_sockaddr(struct sockaddr_storage const *sa, socklen_t salen,
1096  fr_ipaddr_t *ipaddr, uint16_t *port)
1097 {
1098  memset(ipaddr, 0, sizeof(*ipaddr));
1099 
1100  if (sa->ss_family == AF_INET) {
1101  struct sockaddr_in s4;
1102 
1103  if (salen < sizeof(s4)) {
1104  fr_strerror_printf("IPv4 address is too small");
1105  return 0;
1106  }
1107 
1108  memcpy(&s4, sa, sizeof(s4));
1109  ipaddr->af = AF_INET;
1110  ipaddr->prefix = 32;
1111  ipaddr->ipaddr.ip4addr = s4.sin_addr;
1112  if (port) *port = ntohs(s4.sin_port);
1113 
1114 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1115  } else if (sa->ss_family == AF_INET6) {
1116  struct sockaddr_in6 s6;
1117 
1118  if (salen < sizeof(s6)) {
1119  fr_strerror_printf("IPv6 address is too small");
1120  return 0;
1121  }
1122 
1123  memcpy(&s6, sa, sizeof(s6));
1124  ipaddr->af = AF_INET6;
1125  ipaddr->prefix = 128;
1126  ipaddr->ipaddr.ip6addr = s6.sin6_addr;
1127  if (port) *port = ntohs(s6.sin6_port);
1128  ipaddr->zone_id = s6.sin6_scope_id;
1129 #endif
1130 
1131  } else {
1132  fr_strerror_printf("Unsupported address famility %d",
1133  sa->ss_family);
1134  return 0;
1135  }
1136 
1137  return 1;
1138 }
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
Definition: inet.c:226
char const * gai_strerror(int ecode)
Definition: getaddrinfo.c:227
int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask_bits)
Parse an IPv4 address or IPv4 prefix in presentation format (and others)
Definition: inet.c:348
static struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
Mask off a portion of an IPv6 address.
Definition: inet.c:58
static struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
Mask off a portion of an IPv4 address.
Definition: inet.c:37
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:47
static char const * name
int fr_ipaddr_from_sockaddr(struct sockaddr_storage const *sa, socklen_t salen, fr_ipaddr_t *ipaddr, uint16_t *port)
Definition: inet.c:1095
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
Definition: inet.c:90
static int ip_prefix_addr_from_str(struct in_addr *out, char const *str)
Parses the network portion of an IPv4 prefix into an in_addr.
Definition: inet.c:303
#define UNUSED
Definition: libradius.h:134
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:538
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
uint8_t length
Definition: proto_bfd.c:203
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
Definition: inet.c:127
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
Definition: radwho.c:149
static int ip_octet_from_str(uint32_t *out, char const *str)
Parse a single octet of an IPv4 address string.
Definition: inet.c:260
char * fr_inet_ntop_prefix(char out[FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t *addr)
Print a fr_ipaddr_t as a CIDR style network prefix.
Definition: inet.c:762
int fr_ipaddr_from_ifname(UNUSED fr_ipaddr_t *out, UNUSED int af, char const *name)
Definition: inet.c:897
bool fr_dns_lookups
IP -> hostname lookups?
Definition: inet.c:28
#define FR_IPADDR_STRLEN
Like INET6_ADDRSTRLEN but includes space for the textual Zone ID.
Definition: inet.h:67
bool is_integer(char const *value)
Check whether the string is all numbers.
Definition: misc.c:350
#define is_truncated(_ret, _max)
Definition: libradius.h:204
int af
Address family.
Definition: inet.h:42
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
Definition: inet.c:632
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser...
Definition: inet.c:564
static uint32_t mask
Definition: rbmonkey.c:75
bool fr_hostname_lookups
hostname -> IP lookups?
Definition: inet.c:29
#define STRINGIFY(x)
Definition: build.h:34
union fr_ipaddr_t::@1 ipaddr
int fr_ipaddr_to_sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port, struct sockaddr_storage *sa, socklen_t *salen)
Definition: inet.c:1057
char * fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
Print an interface-id in standard colon notation.
Definition: inet.c:788
void freeaddrinfo(struct addrinfo *ai)
Definition: getaddrinfo.c:247
int inet_pton(int af, char const *src, void *dst)
Definition: missing.c:522
uint8_t * fr_inet_ifid_pton(uint8_t out[8], char const *ifid_str)
Convert interface-id in colon notation to 8 byte binary form.
Definition: inet.c:802
#define val(x)
Definition: timestr.c:37
static char const * prefix
Definition: mainconfig.c:81
uint32_t zone_id
A host may have multiple link-local interfaces the scope ID allows the application to specify which o...
Definition: inet.h:48
int getnameinfo(struct sockaddr const *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, unsigned int flags)
Definition: getaddrinfo.c:379
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv6 address or IPv6 prefix in presentation format (and others)
Definition: inet.c:465
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
IPv4/6 prefix.
Definition: inet.h:41
int getaddrinfo(char const *hostname, char const *servname, struct addrinfo const *hints, struct addrinfo **res)
Definition: getaddrinfo.c:259
char * fr_inet_ntop(char out[FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t *addr)
Print the address portion of a fr_ipaddr_t.
Definition: inet.c:713
int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition: inet.c:1026
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
Definition: inet.h:71