Coverage Report

Created: 2023-12-08 06:56

/src/freeradius-server/src/lib/util/inet.c
Line
Count
Source (jump to first uncovered line)
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
/** Functions for parsing, printing, masking and retrieving IP addresses
17
 *
18
 * @file src/lib/util/inet.c
19
 *
20
 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
21
 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22
 */
23
#include <freeradius-devel/util/inet.h>
24
#include <freeradius-devel/util/misc.h>
25
#include <freeradius-devel/util/strerror.h>
26
#include <freeradius-devel/util/syserror.h>
27
#include <freeradius-devel/util/value.h>
28
29
#include <stdlib.h>
30
#include <ifaddrs.h>
31
#include <net/if_arp.h>
32
33
/*
34
 *  Linux
35
 */
36
#if defined(HAVE_LINUX_IF_PACKET_H)
37
#  include <linux/if_packet.h>
38
#  include <linux/if_ether.h>
39
/*
40
 *  Apple, *BSD
41
 */
42
#elif defined(HAVE_NET_IF_DL_H)
43
#  include <net/if_dl.h>     /* Needed for struct sockaddr_ll def */
44
/*
45
 *  emscripten/musl
46
 */
47
#elif defined(HAVE_NETPACKET_PACKET_H)
48
#  include <netpacket/packet.h>   /* Needed for struct sockaddr_ll def */
49
#endif
50
51
bool fr_reverse_lookups = false;    //!< IP -> hostname lookups?
52
bool fr_hostname_lookups = true;    //!< hostname -> IP lookups?
53
54
/** Determine if an address is the INADDR_ANY address for its address family
55
 *
56
 * @param ipaddr to check.
57
 * @return
58
 *  - 0 if it's not.
59
 *  - 1 if it is.
60
 *  - -1 on error.
61
 */
62
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
63
0
{
64
65
0
  if (ipaddr->af == AF_INET) {
66
0
    if (ipaddr->addr.v4.s_addr == htonl(INADDR_ANY)) {
67
0
      return 1;
68
0
    }
69
70
0
#ifdef HAVE_STRUCT_SOCKADDR_IN6
71
0
  } else if (ipaddr->af == AF_INET6) {
72
    /* Unconst for emscripten/musl */
73
0
    if (IN6_IS_ADDR_UNSPECIFIED(UNCONST(struct in6_addr *, &(ipaddr->addr.v6)))) {
74
0
      return 1;
75
0
    }
76
0
#endif
77
78
0
  } else {
79
0
    fr_strerror_const("Unknown address family");
80
0
    return -1;
81
0
  }
82
83
0
  return 0;
84
0
}
85
86
/** Determine if an address is a multicast address
87
 *
88
 * @param ipaddr to check.
89
 * @return
90
 *  - 0 if it's not.
91
 *  - 1 if it is.
92
 *  - -1 on error.
93
 */
94
int fr_ipaddr_is_multicast(fr_ipaddr_t const *ipaddr)
95
0
{
96
0
  if (ipaddr->af == AF_INET) {
97
    /*
98
     *  224.0.0.0 (3758096384) - 239.255.255.255 (4026531839)
99
     */
100
0
    if ((ipaddr->addr.v4.s_addr >= 3758096384) && (ipaddr->addr.v4.s_addr <= 4026531839)) return 1;
101
0
#ifdef HAVE_STRUCT_SOCKADDR_IN6
102
0
  } else if (ipaddr->af == AF_INET6) {
103
    /* Unconst for emscripten/musl */
104
0
    if (IN6_IS_ADDR_MULTICAST(UNCONST(struct in6_addr *, &(ipaddr->addr.v6)))) {
105
0
      return 1;
106
0
    }
107
0
#endif
108
109
0
  } else {
110
0
    fr_strerror_const("Unknown address family");
111
0
    return -1;
112
0
  }
113
114
0
  return 0;
115
0
}
116
117
/** Determine if an address is a prefix
118
 *
119
 * @param ipaddr to check.
120
 * @return
121
 *  - 0 if it's not.
122
 *  - 1 if it is.
123
 *  - -1 on error.
124
 */
125
int fr_ipaddr_is_prefix(fr_ipaddr_t const *ipaddr)
126
0
{
127
0
  switch (ipaddr->af) {
128
0
  case AF_INET:
129
0
    return (ipaddr->prefix < 32);
130
131
0
  case AF_INET6:
132
0
    return (ipaddr->prefix < 128);
133
134
0
  default:
135
0
    fr_strerror_const("Unknown address family");
136
0
    return -1;
137
0
  }
138
0
}
139
140
/** Mask off a portion of an IPv4 address
141
 *
142
 * @param ipaddr to mask.
143
 * @param prefix Number of contiguous bits to mask.
144
 * @return an ipv4 address with the host portion zeroed out.
145
 */
146
static struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
147
792
{
148
792
  uint32_t ret;
149
150
792
  if (prefix > 32) prefix = 32;
151
152
  /* Short circuit */
153
792
  if (prefix == 32) return *ipaddr;
154
155
680
  if (prefix == 0) ret = 0;
156
395
  else ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
157
158
680
  return (*(struct in_addr *)&ret);
159
792
}
160
161
/** Mask off a portion of an IPv6 address
162
 *
163
 * @param ipaddr to mask.
164
 * @param prefix Number of contiguous bits to mask.
165
 * @return an ipv6 address with the host portion zeroed out.
166
 */
167
static struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
168
977
{
169
977
  uint64_t const *p = (uint64_t const *) ipaddr;
170
977
  uint64_t addr;          /* Needed for alignment */
171
977
  uint64_t ret[2], *o = ret;
172
173
977
  if (prefix > 128) prefix = 128;
174
175
  /* Short circuit */
176
977
  if (prefix == 128) return *ipaddr;
177
178
910
  if (prefix >= 64) {
179
257
    prefix -= 64;
180
257
    memcpy(&addr, p, sizeof(addr));   /* Needed for aligned access (ubsan) */
181
257
    *o++ = 0xffffffffffffffffULL & addr;  /* lhs portion masked */
182
257
    p++;
183
653
  } else {
184
653
    ret[1] = 0;       /* rhs portion zeroed */
185
653
  }
186
187
  /* Max left shift is 63 else we get overflow */
188
910
  if (prefix > 0) {
189
441
    memcpy(&addr, p, sizeof(addr));   /* Needed for aligned access (ubsan) */
190
441
    *o = htonll(~((uint64_t)(0x0000000000000001ULL << (64 - prefix)) - 1)) & addr;
191
469
  } else {
192
469
    *o = 0;
193
469
  }
194
195
910
  return *(struct in6_addr *) &ret;
196
977
}
197
198
/** Zeroes out the host portion of an fr_ipaddr_t
199
 *
200
 * @param[in,out] addr to mask
201
 * @param[in] prefix Length of the network portion.
202
 */
203
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
204
1.47k
{
205
206
1.47k
  switch (addr->af) {
207
522
  case AF_INET:
208
522
    addr->addr.v4 = fr_inaddr_mask(&addr->addr.v4, prefix);
209
522
    break;
210
211
955
  case AF_INET6:
212
955
    addr->addr.v6 = fr_in6addr_mask(&addr->addr.v6, prefix);
213
955
    break;
214
215
0
  default:
216
0
    return;
217
1.47k
  }
218
1.47k
  addr->prefix = prefix;
219
1.47k
}
220
221
/** Wrappers for IPv4/IPv6 host to IP address lookup
222
 *
223
 * This function returns only one IP address, of the specified address family,
224
 * or the first address (of whatever family), if AF_UNSPEC is used.
225
 *
226
 * If fallback is specified and af is AF_INET, but not AF_INET records were
227
 * found and a record for AF_INET6 exists that record will be returned.
228
 *
229
 * If fallback is specified and af is AF_INET6, and a record with AF_INET4 exists
230
 * that record will be returned inseted.
231
 *
232
 * @param[out] out Where to write result.
233
 * @param[in] af To search for in preference.
234
 * @param[in] hostname to search for.
235
 * @param[in] fallback to the other address family, if no records matching af, found.
236
 * @return
237
 *  - 0 on success.
238
 *  - -1 on failure.
239
 */
240
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
241
0
{
242
0
  int ret;
243
0
  struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
244
245
  /*
246
   *  Avoid alloc for IP addresses.  This helps us debug
247
   *  memory errors when using talloc.
248
   */
249
0
  if (!fr_hostname_lookups) {
250
0
#ifdef HAVE_STRUCT_SOCKADDR_IN6
251
0
    if (af == AF_UNSPEC) {
252
0
      char const *p;
253
254
0
      for (p = hostname; *p != '\0'; p++) {
255
0
        if ((*p == ':') ||
256
0
            (*p == '[') ||
257
0
            (*p == ']')) {
258
0
          af = AF_INET6;
259
0
          break;
260
0
        }
261
0
      }
262
0
    }
263
0
#endif
264
265
0
    if (af == AF_UNSPEC) af = AF_INET;
266
267
0
    if (inet_pton(af, hostname, &(out->addr)) == 0) {
268
0
      fr_strerror_printf("\"%s\" is not a valid IP address and "
269
0
             "hostname lookups are disabled", hostname);
270
0
      return -1;
271
0
    }
272
0
    out->af = af;
273
0
    out->prefix = 32;
274
0
    out->scope_id = 0;
275
276
0
    return 0;
277
0
  }
278
279
0
  memset(&hints, 0, sizeof(hints));
280
281
  /*
282
   *  If we're falling back we need both IPv4 and IPv6 records
283
   */
284
0
  if (fallback) {
285
0
    hints.ai_family = AF_UNSPEC;
286
0
  } else {
287
0
    hints.ai_family = af;
288
0
  }
289
290
0
  if ((ret = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
291
0
    switch (af) {
292
0
    default:
293
0
    case AF_UNSPEC:
294
0
      fr_strerror_printf("Failed resolving \"%s\" to IP address: %s",
295
0
             hostname, gai_strerror(ret));
296
0
      return -1;
297
298
0
    case AF_INET:
299
0
      fr_strerror_printf("Failed resolving \"%s\" to IPv4 address: %s",
300
0
             hostname, gai_strerror(ret));
301
0
      return -1;
302
303
0
    case AF_INET6:
304
0
      fr_strerror_printf("Failed resolving \"%s\" to IPv6 address: %s",
305
0
             hostname, gai_strerror(ret));
306
0
      return -1;
307
0
    }
308
0
  }
309
310
0
  for (ai = res; ai; ai = ai->ai_next) {
311
0
    if ((af == ai->ai_family) || (af == AF_UNSPEC)) break;
312
0
    if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
313
0
  }
314
315
0
  if (!ai) ai = alt;
316
0
  if (!ai) {
317
0
    fr_strerror_printf("Failed resolving \"%s\": No records matching requested address family returned",
318
0
           hostname);
319
0
    freeaddrinfo(res);
320
0
    return -1;
321
0
  }
322
323
0
  ret = fr_ipaddr_from_sockaddr(out, NULL, (struct sockaddr_storage *)ai->ai_addr, ai->ai_addrlen);
324
0
  freeaddrinfo(res);
325
0
  if (ret < 0) {
326
0
    fr_strerror_const("Failed converting sockaddr to ipaddr");
327
0
    return -1;
328
0
  }
329
330
0
  return 0;
331
0
}
332
333
/** Perform reverse resolution of an IP address
334
 *
335
 * Attempt to resolve an IP address to a DNS record (if dns lookups are enabled).
336
 *
337
 * @param[in] src address to resolve.
338
 * @param[out] out Where to write the resulting hostname.
339
 * @param[in] outlen length of the output buffer.
340
 */
341
char const *fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
342
0
{
343
0
  struct sockaddr_storage ss;
344
0
  int error;
345
0
  socklen_t salen;
346
347
  /*
348
   *  No DNS lookups
349
   */
350
0
  if (!fr_reverse_lookups) {
351
0
    return inet_ntop(src->af, &(src->addr), out, outlen);
352
0
  }
353
354
0
  if (fr_ipaddr_to_sockaddr(&ss, &salen, src, 0) < 0) return NULL;
355
356
0
  if ((error = getnameinfo((struct sockaddr *)&ss, salen, out, outlen, NULL, 0,
357
0
         NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
358
0
    fr_strerror_printf("fr_inet_ntoh: %s", gai_strerror(error));
359
0
    return NULL;
360
0
  }
361
0
  return out;
362
0
}
363
364
365
/** Parse a single octet of an IPv4 address string
366
 *
367
 * @param[out] out Where to write integer.
368
 * @param[in] str to parse.
369
 * @return
370
 *  - >= 0 on success (number of bytes parsed of in).
371
 *  - < 0 on error.
372
 */
373
static int ip_octet_from_str(uint32_t *out, char const *str)
374
2.33k
{
375
2.33k
  uint32_t octet;
376
2.33k
  char const *p = str;
377
378
2.33k
  if ((*p < '0') || (*p > '9')) return -1;
379
380
2.03k
  octet = 0;
381
382
4.99k
  while ((*p >= '0') && (*p <= '9')) {
383
3.05k
    octet *= 10;
384
3.05k
    octet += *p - '0';
385
3.05k
    p++;
386
387
3.05k
    if (octet > 255) return -1;
388
3.05k
  }
389
390
1.94k
  *out = octet;
391
1.94k
  return p - str;
392
2.03k
}
393
394
/** Parses the network portion of an IPv4 prefix into an in_addr
395
 *
396
 * @note output is in network order.
397
 *
398
 * Parses address strings in dotted quad notation.
399
 * Unlike inet_pton allows octets to be omitted, in which case their value is considered to be 0.
400
 * Unlike inet_aton treats integers as representing the highest octet of an IPv4 address, and
401
 * limits them to 255.
402
 *
403
 * Examples of acceptable strings:
404
 * - 192.168.0.0
405
 * - 192.168.0.0/24
406
 * - 192.168/16
407
 * - 192
408
 * - 192/8
409
 *
410
 * @param[out] out Where to write parsed address.
411
 * @param[in] str to parse.
412
 * @return
413
 *  - >= 0 on success (number of bytes parsed of in).
414
 *  - < 0 on error.
415
 */
416
static int ip_prefix_addr_from_str(struct in_addr *out, char const *str)
417
1.18k
{
418
1.18k
  int shift, length;
419
1.18k
  uint32_t octet;
420
1.18k
  uint32_t addr;
421
1.18k
  char const *p = str;
422
423
1.18k
  addr = 0;
424
1.18k
  out->s_addr = 0;
425
426
2.56k
  for (shift = 24; shift >= 0; shift -= 8) {
427
2.33k
    length = ip_octet_from_str(&octet, p);
428
2.33k
    if (length <= 0) return -1;
429
430
1.94k
    addr |= octet << shift;
431
1.94k
    p += length;
432
433
    /*
434
     *  EOS or / means we're done.
435
     */
436
1.94k
    if (!*p || (*p == '/')) break;
437
438
    /*
439
     *  We require dots between octets.
440
     */
441
1.51k
    if (*p != '.') return -1;
442
1.38k
    p++;
443
1.38k
  }
444
445
655
  out->s_addr = htonl(addr);
446
655
  return p - str;
447
1.18k
}
448
449
/** Parse an IPv4 address or IPv4 prefix in presentation format (and others)
450
 *
451
 * @param[out] out  Where to write the ip address value.
452
 * @param[in] value to parse, may be:
453
 *      - dotted quad [+ prefix]
454
 *      - integer
455
 *      - octal number
456
 *      - '*' (INADDR_ANY)
457
 *      - FQDN if resolve is true.
458
 * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
459
 * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
460
 * @param[in] fallback  to IPv6 resolution if no A records can be found.
461
 * @param[in] mask_bits If true, set address bits to zero.
462
 * @return
463
 *  - 0 if ip address was parsed successfully.
464
 *  - -1 on failure.
465
 */
466
int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask_bits)
467
3.48k
{
468
3.48k
  char    *p;
469
3.48k
  unsigned int  mask;
470
3.48k
  char const  *end;
471
3.48k
  char    *eptr;
472
3.48k
  char    buffer[256];  /* As per RFC1035 */
473
3.48k
  int   ret;
474
475
  /*
476
   *  Zero out output so we don't have invalid fields
477
   *  like scope_id hanging around with garbage values.
478
   */
479
3.48k
  memset(out, 0, sizeof(*out));
480
481
3.48k
  end = value + inlen;
482
3.48k
  while ((value < end) && isspace((uint8_t) *value)) value++;
483
3.48k
  if (value == end) {
484
0
    fr_strerror_const("Empty IPv4 address string is invalid");
485
0
    return -1;
486
0
  }
487
3.48k
  inlen = end - value;
488
489
  /*
490
   *  Copy to intermediary buffer if we were given a length
491
   */
492
3.48k
  if (inlen >= 0) {
493
3.48k
    if (inlen >= (ssize_t)sizeof(buffer)) {
494
36
      fr_strerror_printf("Invalid IPv4 address string \"%pV\"", fr_box_strvalue_len(value, inlen));
495
36
      return -1;
496
36
    }
497
3.44k
    memcpy(buffer, value, inlen);
498
3.44k
    buffer[inlen] = '\0';
499
3.44k
    value = buffer;
500
3.44k
  }
501
502
3.44k
  p = strchr(value, '/');
503
504
  /*
505
   *  192.0.2.2 is parsed as if it was /32
506
   */
507
3.44k
  if (!p) {
508
2.22k
    out->prefix = 32;
509
2.22k
    out->af = AF_INET;
510
511
    /*
512
     *  Allow '*' as the wildcard address usually 0.0.0.0
513
     */
514
2.22k
    if ((value[0] == '*') && (value[1] == '\0')) {
515
99
      out->addr.v4.s_addr = htonl(INADDR_ANY);
516
517
    /*
518
     *  Convert things which are obviously integers to IP addresses
519
     *
520
     *  We assume the number is the bigendian representation of the
521
     *  IP address.
522
     */
523
2.12k
    } else if (is_integer(value) || ((value[0] == '0') && (value[1] == 'x'))) {
524
630
      out->addr.v4.s_addr = htonl(strtoul(value, NULL, 0));
525
526
1.49k
    } else if (!resolve) {
527
1.49k
      unsigned int a, b, c, d;
528
1.49k
      int num;
529
1.49k
      char rest;
530
531
1.49k
      a = b = c = d = 0;
532
533
1.49k
      num = sscanf(value, "%u.%u.%u.%u%c", &a, &b, &c, &d, &rest);
534
1.49k
      if ((num == 0) || (num == 5) ||
535
1.49k
          (a > 255) || (b > 255) || (c > 255) || (d > 255)) {
536
1.02k
        fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value);
537
1.02k
        return -1;
538
1.02k
      }
539
540
469
      out->addr.v4.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
541
542
469
    } else if (fr_inet_hton(out, AF_INET, value, fallback) < 0) return -1;
543
544
1.19k
    return 0;
545
2.22k
  }
546
547
  /*
548
   *     Otherwise parse the prefix
549
   */
550
1.22k
  if ((size_t)(p - value) >= INET_ADDRSTRLEN) {
551
42
               fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
552
42
               return -1;
553
42
  }
554
555
  /*
556
   *  Copy the IP portion into a temporary buffer if we haven't already.
557
   */
558
1.18k
  if (inlen < 0) memcpy(buffer, value, p - value);
559
560
  /*
561
   *  We need a special function here, as inet_pton doesn't like
562
   *  address strings with octets omitted, and inet_aton treats
563
   *  127 as an integer value, and sets the lowest octet of the
564
   *  prefix to 127 instead of the highest.
565
   *
566
   *  @todo we should allow hostnames to be parsed as prefixes.
567
   */
568
1.18k
  buffer[p - value] = '\0';
569
1.18k
  ret = ip_prefix_addr_from_str(&out->addr.v4, buffer);
570
1.18k
  buffer[p - value] = '/';  /* Set back to '/' to produce proper errors */
571
572
1.18k
  if (ret <= 0) {
573
525
    fr_strerror_printf("Failed to parse IPv4 prefix string \"%s\"", value);
574
525
    return -1;
575
525
  }
576
577
655
  mask = strtoul(p + 1, &eptr, 10);
578
655
  if (mask > 32) {
579
179
    fr_strerror_printf("Invalid IPv4 mask length \"%s\".  Should be between 0-32", p);
580
179
    return -1;
581
179
  }
582
583
476
  if (eptr[0] != '\0') {
584
106
    fr_strerror_printf("Failed to parse IPv4 prefix string \"%s\", "
585
106
           "got garbage after mask length \"%s\"", value, eptr);
586
106
    return -1;
587
106
  }
588
589
370
  if (mask_bits && (mask < 32)) {
590
270
    out->addr.v4 = fr_inaddr_mask(&out->addr.v4, mask);
591
270
  }
592
593
370
  out->prefix = (uint8_t) mask;
594
370
  out->af = AF_INET;
595
596
370
  return 0;
597
476
}
598
599
/** Parse an IPv6 address or IPv6 prefix in presentation format (and others)
600
 *
601
 * @param[out] out  Where to write the ip address value.
602
 * @param[in] value to parse, may be:
603
 *        - IPv6 hexits [+ prefix].
604
 *        - '*' wildcard.
605
 *        - FQDN if resolve is true.
606
 * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
607
 * @param[in] resolve If true and value doesn't look like an IP address,
608
 *      try and resolve value as a hostname.
609
 * @param[in] fallback  to IPv4 resolution if no AAAA records can be found.
610
 * @param[in] mask  If true, set address bits to zero.
611
 * @return
612
 *  - 0 if ip address was parsed successfully.
613
 *  - -1 on failure.
614
 */
615
int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
616
167
{
617
167
  char    *p;
618
167
  char const  *end;
619
167
  unsigned int  prefix;
620
167
  char    *eptr;
621
167
  char    buffer[256];  /* As per RFC1035 */
622
167
  int   ret;
623
624
  /*
625
   *  Zero out output so we don't have fields
626
   *  like scope_id hanging around with garbage values.
627
   */
628
167
  memset(out, 0, sizeof(*out));
629
630
167
  if (inlen < 0) inlen = strlen(value);
631
632
167
  end = value + inlen;
633
167
  while ((value < end) && isspace((uint8_t) *value)) value++;
634
167
  if (value == end) {
635
0
    fr_strerror_const("Empty IPv6 address string is invalid");
636
0
    return -1;
637
0
  }
638
167
  inlen = end - value;  /* always >0 due to the above check for value==end */
639
640
  /*
641
   *  Copy to intermediary buffer.
642
   */
643
167
  if (inlen >= (ssize_t)sizeof(buffer)) {
644
37
    fr_strerror_printf("Invalid IPv6 address string \"%pV\"", fr_box_strvalue_len(value, inlen));
645
37
    return -1;
646
37
  }
647
648
130
  memcpy(buffer, value, inlen);
649
130
  buffer[inlen] = '\0';
650
130
  value = buffer;
651
652
130
  p = strchr(value, '/');
653
130
  if (!p) {
654
49
    out->prefix = 128;
655
49
    out->af = AF_INET6;
656
657
    /*
658
     *  Allow scopes for non-prefix values.
659
     */
660
49
    p = strchr(value, '%');
661
49
    if (p) *(p++) = '\0';
662
663
    /*
664
     *  Allow '*' as the wildcard address
665
     */
666
49
    if ((value[0] == '*') && (value[1] == '\0')) {
667
17
      out->addr.v6 = (struct in6_addr)IN6ADDR_ANY_INIT;
668
32
    } else if (!resolve) {
669
32
      if (inet_pton(AF_INET6, value, out->addr.v6.s6_addr) <= 0) {
670
29
        fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
671
29
        return -1;
672
29
      }
673
32
    } else if (fr_inet_hton(out, AF_INET6, value, fallback) < 0) return -1;
674
675
    /*
676
     *  No scope, or just '%'.  That's fine.
677
     */
678
20
    if (!p || !*p) return 0;
679
680
    /*
681
     *  Parse scope.
682
     */
683
3
    prefix = strtoul(p, &eptr, 10);
684
3
    if (prefix > UINT32_MAX) {
685
0
      fr_strerror_printf("Invalid scope ID \"%s\".  Should be between 0-2^32-1", p);
686
0
      return -1;
687
0
    }
688
3
    if (eptr[0] != '\0') {
689
1
      fr_strerror_printf("Failed to parse scope \"%s\", "
690
1
             "got garbage after numerical scope value \"%s\"", p, eptr);
691
1
      return -1;
692
1
    }
693
694
2
    return 0;
695
3
  }
696
697
81
  if ((p - value) >= INET6_ADDRSTRLEN) {
698
1
    fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
699
1
    return -1;
700
1
  }
701
702
  /*
703
   *  Copy string to temporary buffer if we didn't do it earlier
704
   */
705
80
  if (inlen < 0) memcpy(buffer, value, p - value);
706
707
80
  if (!resolve) {
708
80
    buffer[p - value] = '\0';
709
80
    ret = inet_pton(AF_INET6, buffer, out->addr.v6.s6_addr);
710
80
    buffer[p - value] = '/';
711
80
    if (ret <= 0) {
712
10
      fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
713
10
      return -1;
714
10
    }
715
80
  } else {
716
0
    buffer[p - value] = '\0';
717
0
    ret = fr_inet_hton(out, AF_INET6, buffer, fallback);
718
0
    buffer[p - value] = '/';
719
0
    if (ret < 0) return -1;
720
0
  }
721
722
70
  prefix = strtoul(p + 1, &eptr, 10);
723
70
  if (prefix > 128) {
724
43
    fr_strerror_printf("Invalid IPv6 mask length \"%s\".  Should be between 0-128", p);
725
43
    return -1;
726
43
  }
727
27
  if (eptr[0] != '\0') {
728
4
    fr_strerror_printf("Failed to parse IPv6 address string \"%s\", "
729
4
           "got garbage after mask length \"%s\"", value, eptr);
730
4
    return -1;
731
4
  }
732
733
23
  if (mask && (prefix < 128)) {
734
22
    struct in6_addr addr;
735
736
22
    addr = fr_in6addr_mask(&out->addr.v6, prefix);
737
22
    memcpy(out->addr.v6.s6_addr, addr.s6_addr, sizeof(out->addr.v6.s6_addr));
738
22
  }
739
740
23
  out->af = AF_INET6;
741
23
  out->prefix = (uint8_t) prefix;
742
743
23
  return 0;
744
27
}
745
746
/** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser
747
 *
748
 * @param[out] out  Where to write the ip address value.
749
 * @param[in] value to parse.
750
 * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
751
 * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value
752
 *      as a hostname.
753
 * @param[in] af  If the address type is not obvious from the format, and resolve is true,
754
 *      the DNS record (A or AAAA) we require.  Also controls which parser we pass
755
 *      the address to if we have no idea what it is.
756
 *      - AF_UNSPEC - Use the server default IP family.
757
 *      - AF_INET - Treat value as an IPv4 address.
758
 *      - AF_INET6 - Treat value as in IPv6 address.
759
 * @param[in] mask If true, set address bits to zero.
760
 * @return
761
 *  - 0 if ip address was parsed successfully.
762
 *  - -1 on failure.
763
 */
764
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
765
156
{
766
156
  size_t len, i;
767
156
  bool hostname = true;
768
156
  bool ipv4 = true;
769
156
  bool ipv6 = true;
770
156
  char const *end;
771
772
156
  end = value + inlen;
773
156
  while ((value < end) && isspace((uint8_t) *value)) value++;
774
156
  if (value == end) {
775
0
    fr_strerror_const("Empty IPv4 address string is invalid");
776
0
    return -1;
777
0
  }
778
156
  inlen = end - value;
779
780
156
  len = (inlen >= 0) ? (size_t)inlen : strlen(value);
781
782
2.17k
  for (i = 0; i < len; i++) {
783
    /*
784
     *  These are valid for IPv4, IPv6, and host names.
785
     */
786
2.09k
    if ((value[i] >= '0') && (value[i] <= '9')) {
787
899
      continue;
788
899
    }
789
790
    /*
791
     *  These are invalid for IPv4, but OK for IPv6
792
     *  and host names.
793
     */
794
1.19k
    if ((value[i] >= 'a') && (value[i] <= 'f')) {
795
388
      ipv4 = false;
796
388
      continue;
797
388
    }
798
799
    /*
800
     *  These are invalid for IPv4, but OK for IPv6
801
     *  and host names.
802
     */
803
805
    if ((value[i] >= 'A') && (value[i] <= 'F')) {
804
216
      ipv4 = false;
805
216
      continue;
806
216
    }
807
808
    /*
809
     *  This is only valid for IPv6 addresses.
810
     */
811
589
    if (value[i] == ':') {
812
247
      ipv4 = false;
813
247
      hostname = false;
814
247
      continue;
815
247
    }
816
817
    /*
818
     *  Valid for IPv4 and host names, not for IPv6.
819
     */
820
342
    if (value[i] == '.') {
821
219
      ipv6 = false;
822
219
      continue;
823
219
    }
824
825
    /*
826
     *  Netmasks are allowed by us, and MUST come at
827
     *  the end of the address.
828
     */
829
123
    if (value[i] == '/') {
830
74
      break;
831
74
    }
832
833
    /*
834
     *  Any characters other than what are checked for
835
     *  above can't be IPv4 or IPv6 addresses.
836
     */
837
49
    ipv4 = false;
838
49
    ipv6 = false;
839
49
  }
840
841
  /*
842
   *  It's not an IPv4 or IPv6 address.  It MUST be a host
843
   *  name.
844
   */
845
156
  if (!ipv4 && !ipv6) {
846
    /*
847
     *  Not an IPv4 or IPv6 address, and we weren't
848
     *  asked to do DNS resolution, we can't do it.
849
     */
850
20
    if (!resolve) {
851
20
      fr_strerror_const("Not IPv4/6 address, and asked not to resolve");
852
20
      return -1;
853
20
    }
854
855
    /*
856
     *  It's not a hostname, either, so bail out
857
     *  early.
858
     */
859
0
    if (!hostname) {
860
0
      fr_strerror_const("Invalid address");
861
0
      return -1;
862
0
    }
863
0
  }
864
865
  /*
866
   *  The name has a ':' in it.  Therefore it must be an
867
   *  IPv6 address.  Error out if the caller specified IPv4.
868
   *  Otherwise, force IPv6.
869
   */
870
136
  if (ipv6 && !hostname) {
871
35
    if (af == AF_INET) {
872
0
      fr_strerror_const("Invalid address");
873
0
      return -1;
874
0
    }
875
876
35
    af = AF_INET6;
877
35
  }
878
879
  /*
880
   *  Use whatever the caller specified, OR what we
881
   *  insinuated above from looking at the name string.
882
   */
883
136
  switch (af) {
884
101
  case AF_UNSPEC:
885
101
    return fr_inet_pton4(out, value, inlen, resolve, true, mask);
886
887
0
  case AF_INET:
888
0
    return fr_inet_pton4(out, value, inlen, resolve, false, mask);
889
890
35
  case AF_INET6:
891
35
    return fr_inet_pton6(out, value, inlen, resolve, false, mask);
892
893
0
  default:
894
0
    break;
895
136
  }
896
897
  /*
898
   *  No idea what it is...
899
   */
900
0
  fr_strerror_printf("Invalid address family %i", af);
901
0
  return -1;
902
136
}
903
904
/** Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
905
 *
906
 * @param[out] out  Where to write the ip address value.
907
 * @param[out] port_out Where to write the port (0 if no port found).
908
 * @param[in] value to parse.
909
 * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
910
 * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value
911
 *      as a hostname.
912
 * @param[in] af  If the address type is not obvious from the format, and resolve is true,
913
 *      the DNS record (A or AAAA) we require.  Also controls which parser we pass
914
 *      the address to if we have no idea what it is.
915
 *      - AF_UNSPEC - Use the server default IP family.
916
 *      - AF_INET - Treat value as an IPv4 address.
917
 *      - AF_INET6 - Treat value as in IPv6 address.
918
 * @param[in] mask If true, set address bits to zero.
919
 * @return
920
 *  - 0 if ip address was parsed successfully.
921
 *  - -1 on failure.
922
 */
923
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value,
924
          ssize_t inlen, int af, bool resolve, bool mask)
925
0
{
926
0
  char const  *p = value, *q;
927
0
  char    *end;
928
0
  unsigned long port;
929
0
  char    buffer[6];
930
0
  size_t    len;
931
932
0
  *port_out = 0;
933
934
0
  len = (inlen >= 0) ? (size_t)inlen : strlen(value);
935
936
0
  if (*p == '[') {
937
0
    if (!(q = memchr(p + 1, ']', len - 1))) {
938
0
      fr_strerror_const("Missing closing ']' for IPv6 address");
939
0
      return -1;
940
0
    }
941
942
    /*
943
     *  inet_pton doesn't like the address being wrapped in []
944
     */
945
0
    if (fr_inet_pton6(out, p + 1, (q - p) - 1, false, false, mask) < 0) return -1;
946
947
0
    if (q[1] == ':') {
948
0
      q++;
949
0
      goto do_port;
950
0
    }
951
952
0
    return 0;
953
0
  }
954
955
  /*
956
   *  Host, IPv4 or IPv6 with no port
957
   */
958
0
  q = memchr(p, ':', len);
959
0
  if (!q) return fr_inet_pton(out, p, len, af, resolve, mask);
960
961
  /*
962
   *  IPv4 or host, with port
963
   */
964
0
  if (fr_inet_pton(out, p, (q - p), af, resolve, mask) < 0) return -1;
965
0
do_port:
966
  /*
967
   *  Valid ports are a maximum of 5 digits, so if the
968
   *  input length indicates there are more than 5 chars
969
   *  after the ':' then there's an issue.
970
   */
971
0
  if (len > (size_t) ((q + sizeof(buffer)) - value)) {
972
0
  error:
973
0
    fr_strerror_const("IP string contains trailing garbage after port delimiter");
974
0
    return -1;
975
0
  }
976
977
0
  p = q + 1;      /* Move to first digit */
978
979
0
  strlcpy(buffer, p, (len - (p - value)) + 1);
980
0
  port = strtoul(buffer, &end, 10);
981
0
  if (*end != '\0') goto error; /* Trailing garbage after integer */
982
983
0
  if ((port > UINT16_MAX) || (port == 0)) {
984
0
    fr_strerror_printf("Port %lu outside valid port range 1-" STRINGIFY(UINT16_MAX), port);
985
0
    return -1;
986
0
  }
987
0
  *port_out = port;
988
989
0
  return 0;
990
0
}
991
992
/** Print the address portion of a #fr_ipaddr_t
993
 *
994
 * @note Includes the textual scope_id name (eth0, en0 etc...) if supported.
995
 *
996
 * @param[out] out Where to write the resulting IP string.
997
 *  Should be at least FR_IPADDR_STRLEN bytes.
998
 * @param[in] outlen of output buffer.
999
 * @param[in] addr to convert to presentation format.
1000
 * @return
1001
 *  - NULL on error (use fr_syserror(errno)).
1002
 *  - a pointer to out on success.
1003
 */
1004
char *fr_inet_ntop(char out[static FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
1005
1.11k
{
1006
1.11k
  char  *p;
1007
1.11k
  size_t  len;
1008
1009
1.11k
  out[0] = '\0';
1010
1011
1.11k
  if (inet_ntop(addr->af, &addr->addr, out, outlen) == NULL) {
1012
0
    fr_strerror_printf("%s", fr_syserror(errno));
1013
0
    return NULL;
1014
0
  }
1015
1016
1.11k
  if ((addr->af == AF_INET) || (addr->scope_id == 0)) return out;
1017
1018
0
  p = out + strlen(out);
1019
1020
0
#ifdef WITH_IFINDEX_NAME_RESOLUTION
1021
0
  {
1022
0
    char buffer[IFNAMSIZ];
1023
0
    char *ifname;
1024
1025
0
    ifname = fr_ifname_from_ifindex(buffer, addr->scope_id);
1026
0
    if (ifname) {
1027
0
      len = snprintf(p, outlen - (p - out), "%%%s", ifname);
1028
0
      if (is_truncated(len + (p - out), outlen)) {
1029
0
        fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
1030
0
               (p - out) + len, outlen);
1031
0
        return NULL;
1032
0
      }
1033
0
      return out;
1034
0
    }
1035
1036
0
  }
1037
0
#endif
1038
1039
0
  len = snprintf(p, outlen - (p - out), "%%%u", addr->scope_id);
1040
0
  if (is_truncated(len + (p - out), outlen)) {
1041
0
    fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
1042
0
           (p - out) + len, outlen);
1043
0
    return NULL;
1044
0
  }
1045
1046
0
  return out;
1047
0
}
1048
1049
/** Print a #fr_ipaddr_t as a CIDR style network prefix
1050
 *
1051
 * @param[out] out Where to write the resulting prefix string.
1052
 *  Should be at least FR_IPADDR_PREFIX_STRLEN bytes.
1053
 * @param[in] outlen of output buffer.
1054
 * @param[in] addr to convert to presentation format.
1055
 * @return
1056
 *  - NULL on error (use fr_syserror(errno)).
1057
 *  - a pointer to out on success.
1058
 */
1059
char *fr_inet_ntop_prefix(char out[static FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
1060
1.11k
{
1061
1.11k
  char  *p;
1062
1.11k
  size_t  len;
1063
1064
1.11k
  if (fr_inet_ntop(out, outlen, addr) == NULL) return NULL;
1065
1066
1.11k
  p = out + strlen(out);
1067
1068
1.11k
  len = snprintf(p, outlen - (p - out), "/%i", addr->prefix);
1069
1.11k
  if (is_truncated(len + (p - out), outlen)) {
1070
0
    fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
1071
0
           (p - out) + len, outlen);
1072
0
    return NULL;
1073
0
  }
1074
1075
1.11k
  return out;
1076
1.11k
}
1077
1078
/** Print an interface-id in standard colon notation
1079
 *
1080
 * @param[out] out Where to write the resulting interface-id string.
1081
 * @param[in] outlen of output buffer.
1082
 * @param[in] ifid to print.
1083
 * @return a pointer to out.
1084
 */
1085
char *fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
1086
0
{
1087
0
  snprintf(out, outlen, "%x:%x:%x:%x",
1088
0
     fr_nbo_to_uint16(ifid),     fr_nbo_to_uint16(ifid + 2),
1089
0
     fr_nbo_to_uint16(ifid + 4), fr_nbo_to_uint16(ifid + 6));
1090
0
  return out;
1091
0
}
1092
1093
/** Convert interface-id in colon notation to 8 byte binary form
1094
 *
1095
 * @param[out] out Where to write the binary interface-id.
1096
 * @param[in] ifid_str to parse.
1097
 * @return a pointer to out.
1098
 */
1099
uint8_t *fr_inet_ifid_pton(uint8_t out[static 8], char const *ifid_str)
1100
30
{
1101
30
  static char const xdigits[] = "0123456789abcdef";
1102
30
  char const *p, *pch;
1103
30
  int num_id = 0, val = 0, idx = 0;
1104
1105
123
  for (p = ifid_str; ; ++p) {
1106
123
    if (*p == ':' || *p == '\0') {
1107
48
      if (num_id <= 0)
1108
8
        return NULL;
1109
1110
      /*
1111
       *  Drop 'val' into the array.
1112
       */
1113
40
      out[idx] = (val >> 8) & 0xff;
1114
40
      out[idx + 1] = val & 0xff;
1115
40
      if (*p == '\0') {
1116
        /*
1117
         *  Must have all entries before
1118
         *  end of the string.
1119
         */
1120
14
        if (idx != 6)
1121
12
          return NULL;
1122
2
        break;
1123
14
      }
1124
26
      val = 0;
1125
26
      num_id = 0;
1126
26
      if ((idx += 2) > 6)
1127
1
        return NULL;
1128
75
    } else if ((pch = strchr(xdigits, tolower((uint8_t) *p))) != NULL) {
1129
69
      if (++num_id > 4)
1130
1
        return NULL;
1131
      /*
1132
       *  Dumb version of 'scanf'
1133
       */
1134
68
      val <<= 4;
1135
68
      val |= (pch - xdigits);
1136
68
    } else
1137
6
      return NULL;
1138
123
  }
1139
2
  return out;
1140
30
}
1141
1142
#ifdef SIOCGIFADDR
1143
/** Retrieve the primary IP address associated with an interface
1144
 *
1145
 * @param[out] out The primary IP address associated with the named interface.
1146
 * @param[in] af of IP address to retrieve (AF_INET or AF_INET6).
1147
 * @param[in] name of interface.
1148
 * @return
1149
 *  - 0 on success.
1150
 *  - -1 on failure.
1151
 */
1152
int fr_ipaddr_from_ifname(fr_ipaddr_t *out, int af, char const *name)
1153
{
1154
  int     fd;
1155
  struct ifreq    if_req;
1156
  fr_ipaddr_t   ipaddr;
1157
1158
  memset(&if_req, 0, sizeof(if_req));
1159
  memset(out, 0, sizeof(*out));
1160
1161
  /*
1162
   *  Set the interface we're resolving, and the address family.
1163
   */
1164
  if_req.ifr_addr.sa_family = af;
1165
  strlcpy(if_req.ifr_name, name, sizeof(if_req.ifr_name));
1166
1167
  fd = socket(AF_INET, SOCK_DGRAM, 0);
1168
  if (fd < 0) {
1169
    fr_strerror_printf("Failed opening temporary socket for SIOCGIFADDR: %s", fr_syserror(errno));
1170
  error:
1171
    close(fd);
1172
    return -1;
1173
  }
1174
  if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1175
    fr_strerror_printf("Failed determining address for interface %s: %s", name, fr_syserror(errno));
1176
    goto error;
1177
  }
1178
1179
  /*
1180
   *  There's nothing in the ifreq struct that gives us the length
1181
   *  of the sockaddr struct, so we just use sizeof here.
1182
   *  sockaddr2ipaddr uses the address family anyway, so we should
1183
   *  be OK.
1184
   */
1185
  if (fr_ipaddr_from_sockaddr(&ipaddr, NULL,
1186
            (struct sockaddr_storage *)&if_req.ifr_addr,
1187
            sizeof(if_req.ifr_addr)) < 0) goto error;
1188
  *out = ipaddr;
1189
1190
  close(fd);
1191
1192
  return 0;
1193
}
1194
#else
1195
int fr_ipaddr_from_ifname(UNUSED fr_ipaddr_t *out, UNUSED int af, char const *name)
1196
0
{
1197
0
  fr_strerror_printf("No support for SIOCGIFADDR, can't determine IP address of %s", name);
1198
0
  return -1;
1199
0
}
1200
#endif
1201
1202
#ifdef WITH_IFINDEX_NAME_RESOLUTION
1203
/** Resolve ifindex to interface name
1204
 *
1205
 * @param[out] out Buffer to use to store the name, must be at least IFNAMSIZ bytes.
1206
 * @param[in] ifindex to resolve to name.
1207
 * @return
1208
 *  - NULL on error.
1209
 *  - a pointer to out on success.
1210
 */
1211
char *fr_ifname_from_ifindex(char out[static IFNAMSIZ], int ifindex)
1212
0
{
1213
0
#ifdef HAVE_IF_INDEXTONAME
1214
0
  if (!if_indextoname(ifindex, out)) {
1215
0
    fr_strerror_printf("Failed resolving interface index %i to name", ifindex);
1216
0
    return NULL;
1217
0
  }
1218
#else
1219
  struct ifreq  if_req;
1220
  int   fd;
1221
1222
  memset(&if_req, 0, sizeof(if_req));
1223
  if_req.ifr_ifindex = ifindex;
1224
1225
  fd = socket(AF_INET, SOCK_DGRAM, 0);
1226
  if (fd < 0) {
1227
    fr_strerror_printf("Failed opening temporary socket for SIOCGIFADDR: %s", fr_syserror(errno));
1228
  error:
1229
    close(fd);
1230
    return NULL;
1231
  }
1232
1233
  /*
1234
   *  First we resolve the interface index to the interface name
1235
   *  Which is pretty inefficient, but it seems the only way to
1236
   *  identify interfaces for SIOCG* operations is with the interface
1237
   *  name.
1238
   */
1239
  if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1240
    fr_strerror_printf("Failed resolving interface index %i to name: %s", ifindex, fr_syserror(errno));
1241
    goto error;
1242
  }
1243
  strlcpy(out, if_req.ifr_name, IFNAMSIZ);
1244
  close(fd);
1245
#endif
1246
0
  return out;
1247
0
}
1248
#endif
1249
1250
#ifdef WITH_IFINDEX_IPADDR_RESOLUTION
1251
/** Returns the primary IP address for a given interface index
1252
 *
1253
 * @note Intended to be used with udpfromto (recvfromto) to retrieve the
1254
 *  source IP address to use when responding to broadcast packets.
1255
 *
1256
 * @note Will likely be quite slow due to the number of system calls.
1257
 *
1258
 * @param[out] out Where to write the primary IP address.
1259
 * @param[in] fd File descriptor of any datagram or raw socket.
1260
 * @param[in] af to get interface for.
1261
 * @param[in] ifindex of interface to get IP address for.
1262
 * @return
1263
 *  - 0 on success.
1264
 *  - -1 on failure.
1265
 */
1266
int fr_ipaddr_from_ifindex(fr_ipaddr_t *out, int fd, int af, int ifindex)
1267
{
1268
  struct ifreq    if_req;
1269
  fr_ipaddr_t   ipaddr;
1270
1271
  memset(&if_req, 0, sizeof(if_req));
1272
  memset(out, 0, sizeof(*out));
1273
1274
#ifdef SIOCGIFNAME
1275
  if_req.ifr_ifindex = ifindex;
1276
  /*
1277
   *  First we resolve the interface index to the interface name
1278
   *  Which is pretty inefficient, but it seems the only way to
1279
   *  identify interfaces for SIOCG* operations is with the interface
1280
   *  name.
1281
   */
1282
  if (ioctl(fd, SIOCGIFNAME, &if_req) < 0) {
1283
    fr_strerror_printf("Failed resolving interface index %i to name: %s", ifindex, fr_syserror(errno));
1284
    return -1;
1285
  }
1286
#elif defined(HAVE_IF_INDEXTONAME)
1287
  if (!if_indextoname(ifindex, if_req.ifr_name)) {
1288
    fr_strerror_printf("Failed resolving interface index %i to name", ifindex);
1289
    return -1;
1290
  }
1291
#else
1292
#  error Need SIOCGIFNAME or if_indextoname
1293
#endif
1294
1295
  /*
1296
   *  Name should now be present in if_req, so we just need to
1297
   *  set the address family.
1298
   */
1299
  if_req.ifr_addr.sa_family = af;
1300
1301
  if (ioctl(fd, SIOCGIFADDR, &if_req) < 0) {
1302
    fr_strerror_printf("Failed determining address for interface %s: %s",
1303
           if_req.ifr_name, fr_syserror(errno));
1304
    return -1;
1305
  }
1306
1307
  /*
1308
   *  There's nothing in the ifreq struct that gives us the length
1309
   *  of the sockaddr struct, so we just use sizeof here.
1310
   *  sockaddr2ipaddr uses the address family anyway, so we should
1311
   *  be OK.
1312
   */
1313
  if (fr_ipaddr_from_sockaddr(&ipaddr, NULL,
1314
            (struct sockaddr_storage *)&if_req.ifr_addr,
1315
            sizeof(if_req.ifr_addr)) < 0) return -1;
1316
  *out = ipaddr;
1317
1318
  return 0;
1319
}
1320
#endif
1321
1322
/** Compare two ip addresses
1323
 *
1324
 * @param[in] a   First ip to compare.
1325
 * @param[in] b   Second ip to compare.
1326
 * @return
1327
 *  - 1 if a > b
1328
 *  - 0 if a == b
1329
 *  - -1 if a < b
1330
 *  - -2 on error.
1331
 */
1332
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
1333
0
{
1334
0
  int ret;
1335
0
  size_t len;
1336
1337
0
  CMP_RETURN(a, b, af);
1338
0
  CMP_RETURN(a, b, prefix);
1339
1340
  /*
1341
   *  We only care about prefix bytes.
1342
   *
1343
   *  Host bytes should be masked on ingestion
1344
   *  for prefix types.
1345
   */
1346
0
  len = ((a->prefix + 7) & -8) >> 3;
1347
0
  switch (a->af) {
1348
0
  case AF_INET:
1349
0
    ret = memcmp(&a->addr.v4, &b->addr.v4, len);
1350
0
    return CMP(ret, 0);
1351
1352
0
#ifdef HAVE_STRUCT_SOCKADDR_IN6
1353
0
  case AF_INET6:
1354
0
    CMP_RETURN(a, b, scope_id);
1355
0
    ret = memcmp(&a->addr.v6, &b->addr.v6, len);
1356
0
    return CMP(ret, 0);
1357
0
#endif
1358
1359
0
  default:
1360
0
    fr_strerror_printf("Invalid address family %u", a->af);
1361
0
    return -2;
1362
0
  }
1363
0
}
1364
1365
/** Convert our internal ip address representation to a sockaddr
1366
 *
1367
 * @param[out] sa where to write out the sockaddr,
1368
 *      must be large enough to hold
1369
 *      sizeof(s6).
1370
 * @param[out] salen  Length of the sockaddr struct.
1371
 * @param[in] ipaddr  IP address to convert.
1372
 * @param[in] port  Port to convert.
1373
1374
 * @return
1375
 *  - 0 on success.
1376
 *  - -1 on failure.
1377
 */
1378
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen,
1379
        fr_ipaddr_t const *ipaddr, uint16_t port)
1380
0
{
1381
0
  memset(sa, 0, sizeof(*sa));
1382
1383
0
  if (ipaddr->af == AF_INET) {
1384
0
    struct sockaddr_in s4;
1385
1386
0
    *salen = sizeof(s4);
1387
1388
0
    memset(&s4, 0, sizeof(s4));
1389
0
    s4.sin_family = AF_INET;
1390
0
    s4.sin_addr = ipaddr->addr.v4;
1391
0
    s4.sin_port = htons(port);
1392
0
    memset(sa, 0, sizeof(*sa));
1393
0
    memcpy(sa, &s4, sizeof(s4));
1394
1395
0
#ifdef HAVE_STRUCT_SOCKADDR_IN6
1396
0
  } else if (ipaddr->af == AF_INET6) {
1397
0
    struct sockaddr_in6 s6;
1398
1399
0
    *salen = sizeof(s6);
1400
1401
0
    memset(&s6, 0, sizeof(s6));
1402
0
    s6.sin6_family = AF_INET6;
1403
0
    s6.sin6_addr = ipaddr->addr.v6;
1404
0
    s6.sin6_port = htons(port);
1405
0
    s6.sin6_scope_id = ipaddr->scope_id;
1406
0
    memset(sa, 0, sizeof(*sa));
1407
0
    memcpy(sa, &s6, sizeof(s6));
1408
0
#endif
1409
0
  } else {
1410
0
    fr_strerror_printf("Unsupported address family %d", ipaddr->af);
1411
0
    return -1;
1412
0
  }
1413
1414
0
  return 0;
1415
0
}
1416
1417
/** Convert sockaddr to our internal ip address representation
1418
 *
1419
 * @param[out] ipaddr Where to write the ipaddr.
1420
 * @param[out] port Where to write the port.
1421
 * @param[in] sa  struct to convert.
1422
 * @param[in] salen Length of the sockaddr struct.
1423
 * @return
1424
 *  - 0 on success.
1425
 *  - -1 on failure.
1426
 */
1427
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port,
1428
          struct sockaddr_storage const *sa, socklen_t salen)
1429
0
{
1430
0
  memset(ipaddr, 0, sizeof(*ipaddr));
1431
1432
0
  if (sa->ss_family == AF_INET) {
1433
0
    struct sockaddr_in s4;
1434
1435
0
    if (salen < sizeof(s4)) {
1436
0
      fr_strerror_const("IPv4 address is too small");
1437
0
      return 0;
1438
0
    }
1439
1440
0
    memcpy(&s4, sa, sizeof(s4));
1441
0
    ipaddr->af = AF_INET;
1442
0
    ipaddr->prefix = 32;
1443
0
    ipaddr->addr.v4 = s4.sin_addr;
1444
0
    if (port) *port = ntohs(s4.sin_port);
1445
0
    ipaddr->scope_id = 0;
1446
1447
0
#ifdef HAVE_STRUCT_SOCKADDR_IN6
1448
0
  } else if (sa->ss_family == AF_INET6) {
1449
0
    struct sockaddr_in6 s6;
1450
1451
0
    if (salen < sizeof(s6)) {
1452
0
      fr_strerror_const("IPv6 address is too small");
1453
0
      return 0;
1454
0
    }
1455
1456
0
    memcpy(&s6, sa, sizeof(s6));
1457
0
    ipaddr->af = AF_INET6;
1458
0
    ipaddr->prefix = 128;
1459
0
    ipaddr->addr.v6 = s6.sin6_addr;
1460
0
    if (port) *port = ntohs(s6.sin6_port);
1461
0
    ipaddr->scope_id = s6.sin6_scope_id;
1462
0
#endif
1463
1464
0
  } else {
1465
0
    fr_strerror_printf("Unsupported address family %d", sa->ss_family);
1466
0
    return -1;
1467
0
  }
1468
1469
0
  return 0;
1470
0
}
1471
1472
char *fr_ipaddr_to_interface(TALLOC_CTX *ctx, fr_ipaddr_t *ipaddr)
1473
0
{
1474
0
  struct ifaddrs *list = NULL;
1475
0
  struct ifaddrs *i;
1476
0
  char *interface = NULL;
1477
1478
  /*
1479
   *  Bind manually to an IP used by the named interface.
1480
   */
1481
0
  if (getifaddrs(&list) < 0) return NULL;
1482
1483
0
  for (i = list; i != NULL; i = i->ifa_next) {
1484
0
    int scope_id;
1485
0
    fr_ipaddr_t my_ipaddr;
1486
1487
0
    if (!i->ifa_addr || !i->ifa_name || (ipaddr->af != i->ifa_addr->sa_family)) continue;
1488
1489
0
    fr_ipaddr_from_sockaddr(&my_ipaddr, NULL,
1490
0
          (struct sockaddr_storage *)i->ifa_addr, sizeof(struct sockaddr_in6));
1491
1492
    /*
1493
     *  my_ipaddr will have a scope_id, but the input
1494
     *  ipaddr won't have one.  We therefore set the
1495
     *  local one to zero, so that we can do correct
1496
     *  IP address comparisons.
1497
     *
1498
     *  If the comparison succeeds, then we return
1499
     *  both the interface name, and we update the
1500
     *  input ipaddr with the correct scope_id.
1501
     */
1502
0
    scope_id = my_ipaddr.scope_id;
1503
0
    my_ipaddr.scope_id = 0;
1504
0
    if (fr_ipaddr_cmp(ipaddr, &my_ipaddr) == 0) {
1505
0
      interface = talloc_strdup(ctx, i->ifa_name);
1506
0
      ipaddr->scope_id = scope_id;
1507
0
      break;
1508
0
    }
1509
0
  }
1510
1511
0
  freeifaddrs(list);
1512
0
  return interface;
1513
0
}
1514
1515
int fr_interface_to_ipaddr(char const *interface, fr_ipaddr_t *ipaddr, int af, bool link_local)
1516
0
{
1517
0
  struct ifaddrs *list = NULL;
1518
0
  struct ifaddrs *i;
1519
0
  int ret = -1;
1520
1521
0
  if (getifaddrs(&list) < 0) return -1;
1522
1523
0
  for (i = list; i != NULL; i = i->ifa_next) {
1524
0
    fr_ipaddr_t my_ipaddr;
1525
0
    struct sockaddr_storage sa;
1526
1527
0
    if (!i->ifa_addr || !i->ifa_name || ((af != AF_UNSPEC) && (af != i->ifa_addr->sa_family))) continue;
1528
0
    if (strcmp(i->ifa_name, interface) != 0) continue;
1529
1530
0
    memcpy(&sa, i->ifa_addr,  sizeof(struct sockaddr_in6)); /* ifa->ifa_addr may not be aligned properly */
1531
1532
0
    fr_ipaddr_from_sockaddr(&my_ipaddr, NULL, &sa, sizeof(struct sockaddr_in6));
1533
1534
    /*
1535
     *  If they ask for a link local address, then give
1536
     *  it to them.
1537
     */
1538
0
    if (link_local) {
1539
0
      if (my_ipaddr.af != AF_INET6) continue;
1540
0
      if (!IN6_IS_ADDR_LINKLOCAL(&my_ipaddr.addr.v6)) continue;
1541
0
    }
1542
1543
0
    *ipaddr = my_ipaddr;
1544
0
    ret = 0;
1545
0
    break;
1546
0
  }
1547
1548
0
  freeifaddrs(list);
1549
0
  return ret;
1550
0
}
1551
1552
/*
1553
 *  AF_PACKET on Linux
1554
 *  AF_LINK on BSD
1555
 */
1556
#ifndef AF_LINK
1557
0
#define AF_LINK AF_PACKET
1558
#endif
1559
1560
int fr_interface_to_ethernet(char const *interface, fr_ethernet_t *ethernet)
1561
0
{
1562
0
  struct ifaddrs *list = NULL;
1563
0
  struct ifaddrs *i;
1564
0
  int ret = -1;
1565
1566
0
  if (getifaddrs(&list) < 0) return -1;
1567
1568
0
  for (i = list; i != NULL; i = i->ifa_next) {
1569
0
    if (!i->ifa_addr || !i->ifa_name || (i->ifa_addr->sa_family != AF_LINK)) continue;
1570
0
    if (strcmp(i->ifa_name, interface) != 0) continue;
1571
1572
0
#if defined(__linux__) || defined(__EMSCRIPTEN__)
1573
0
    {
1574
0
      struct sockaddr_ll *ll;
1575
1576
0
      ll = (struct sockaddr_ll *) i->ifa_addr;
1577
0
      if ((ll->sll_hatype != 1) || (ll->sll_halen != 6)) continue;
1578
1579
0
      memcpy(ethernet->addr, ll->sll_addr, 6);
1580
0
    }
1581
#else
1582
    {
1583
      struct sockaddr_dl *ll;
1584
1585
      ll = (struct sockaddr_dl *) i->ifa_addr;
1586
      if (ll->sdl_alen != 6) continue;
1587
1588
      memcpy(ethernet->addr, LLADDR(ll), 6);
1589
    }
1590
#endif
1591
0
    ret = 0;
1592
0
    break;
1593
0
  }
1594
1595
0
  freeifaddrs(list);
1596
0
  return ret;
1597
0
}