Coverage Report

Created: 2026-03-31 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libstrongswan/networking/host.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2006-2014 Tobias Brunner
3
 * Copyright (C) 2006 Daniel Roethlisberger
4
 * Copyright (C) 2005-2006 Martin Willi
5
 * Copyright (C) 2005 Jan Hutter
6
 *
7
 * Copyright (C) secunet Security Networks AG
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU General Public License as published by the
11
 * Free Software Foundation; either version 2 of the License, or (at your
12
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
13
 *
14
 * This program is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17
 * for more details.
18
 */
19
20
#include "host.h"
21
22
#include <utils/debug.h>
23
#include <library.h>
24
25
0
#define IPV4_LEN   4
26
0
#define IPV6_LEN  16
27
28
typedef struct private_host_t private_host_t;
29
30
/**
31
 * Private Data of a host object.
32
 */
33
struct private_host_t {
34
  /**
35
   * Public data
36
   */
37
  host_t public;
38
39
  /**
40
   * low-lewel structure, which stores the address
41
   */
42
  union {
43
    /** generic type */
44
    struct sockaddr address;
45
    /** maximum sockaddr size */
46
    struct sockaddr_storage address_max;
47
    /** IPv4 address */
48
    struct sockaddr_in address4;
49
    /** IPv6 address */
50
    struct sockaddr_in6 address6;
51
  };
52
  /**
53
   * length of address structure
54
   */
55
  socklen_t socklen;
56
};
57
58
/**
59
 * Update the sockaddr internal sa_len option, if available
60
 */
61
static inline void update_sa_len(private_host_t *this)
62
5.72k
{
63
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
64
  this->address.sa_len = this->socklen;
65
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
66
5.72k
}
67
68
METHOD(host_t, get_sockaddr, sockaddr_t*,
69
  private_host_t *this)
70
0
{
71
0
  return &(this->address);
72
0
}
73
74
METHOD(host_t, get_sockaddr_len, socklen_t*,
75
  private_host_t *this)
76
0
{
77
0
  return &(this->socklen);
78
0
}
79
80
METHOD(host_t, is_anyaddr, bool,
81
  private_host_t *this)
82
0
{
83
0
  static const uint8_t zeroes[IPV6_LEN];
84
85
0
  switch (this->address.sa_family)
86
0
  {
87
0
    case AF_INET:
88
0
    {
89
0
      return memeq(zeroes, &(this->address4.sin_addr.s_addr), IPV4_LEN);
90
0
    }
91
0
    case AF_INET6:
92
0
    {
93
0
      return memeq(zeroes, &(this->address6.sin6_addr.s6_addr), IPV6_LEN);
94
0
    }
95
0
    default:
96
0
    {
97
0
      return FALSE;
98
0
    }
99
0
  }
100
0
}
101
102
/**
103
 * Described in header.
104
 */
105
int host_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
106
           const void *const *args)
107
0
{
108
0
  private_host_t *this = *((private_host_t**)(args[0]));
109
0
  char buffer[INET6_ADDRSTRLEN + 16];
110
111
0
  if (this == NULL)
112
0
  {
113
0
    snprintf(buffer, sizeof(buffer), "(null)");
114
0
  }
115
0
  else if (is_anyaddr(this) && !spec->plus && !spec->hash)
116
0
  {
117
0
    snprintf(buffer, sizeof(buffer), "%%any%s",
118
0
         this->address.sa_family == AF_INET6 ? "6" : "");
119
0
  }
120
0
  else
121
0
  {
122
0
    void *address;
123
0
    uint16_t port;
124
0
    int len;
125
126
0
    address = &this->address6.sin6_addr;
127
0
    port = this->address6.sin6_port;
128
129
0
    switch (this->address.sa_family)
130
0
    {
131
0
      case AF_INET:
132
0
        address = &this->address4.sin_addr;
133
0
        port = this->address4.sin_port;
134
        /* fall */
135
0
      case AF_INET6:
136
137
0
        if (inet_ntop(this->address.sa_family, address,
138
0
                buffer, sizeof(buffer)) == NULL)
139
0
        {
140
0
          snprintf(buffer, sizeof(buffer),
141
0
               "(address conversion failed)");
142
0
        }
143
0
        else if (spec->hash && port)
144
0
        {
145
0
          len = strlen(buffer);
146
0
          snprintf(buffer + len, sizeof(buffer) - len,
147
0
               "[%d]", ntohs(port));
148
0
        }
149
0
        break;
150
0
      default:
151
0
        snprintf(buffer, sizeof(buffer), "(family not supported)");
152
0
        break;
153
0
    }
154
0
  }
155
0
  if (spec->minus)
156
0
  {
157
0
    return print_in_hook(data, "%-*s", spec->width, buffer);
158
0
  }
159
0
  return print_in_hook(data, "%*s", spec->width, buffer);
160
0
}
161
162
METHOD(host_t, get_address, chunk_t,
163
  private_host_t *this)
164
0
{
165
0
  chunk_t address = chunk_empty;
166
167
0
  switch (this->address.sa_family)
168
0
  {
169
0
    case AF_INET:
170
0
    {
171
0
      address.ptr = (char*)&(this->address4.sin_addr.s_addr);
172
0
      address.len = IPV4_LEN;
173
0
      return address;
174
0
    }
175
0
    case AF_INET6:
176
0
    {
177
0
      address.ptr = (char*)&(this->address6.sin6_addr.s6_addr);
178
0
      address.len = IPV6_LEN;
179
0
      return address;
180
0
    }
181
0
    default:
182
0
    {
183
      /* return empty chunk */
184
0
      return address;
185
0
    }
186
0
  }
187
0
}
188
189
METHOD(host_t, get_family, int,
190
  private_host_t *this)
191
0
{
192
0
  return this->address.sa_family;
193
0
}
194
195
METHOD(host_t, get_port, uint16_t,
196
  private_host_t *this)
197
0
{
198
0
  switch (this->address.sa_family)
199
0
  {
200
0
    case AF_INET:
201
0
    {
202
0
      return ntohs(this->address4.sin_port);
203
0
    }
204
0
    case AF_INET6:
205
0
    {
206
0
      return ntohs(this->address6.sin6_port);
207
0
    }
208
0
    default:
209
0
    {
210
0
      return 0;
211
0
    }
212
0
  }
213
0
}
214
215
METHOD(host_t, set_port, void,
216
  private_host_t *this, uint16_t port)
217
0
{
218
0
  switch (this->address.sa_family)
219
0
  {
220
0
    case AF_INET:
221
0
    {
222
0
      this->address4.sin_port = htons(port);
223
0
      break;
224
0
    }
225
0
    case AF_INET6:
226
0
    {
227
0
      this->address6.sin6_port = htons(port);
228
0
      break;
229
0
    }
230
0
    default:
231
0
    {
232
0
      break;
233
0
    }
234
0
  }
235
0
}
236
237
METHOD(host_t, clone_, host_t*,
238
  private_host_t *this)
239
0
{
240
0
  private_host_t *new;
241
242
0
  new = malloc_thing(private_host_t);
243
0
  memcpy(new, this, sizeof(private_host_t));
244
245
0
  return &new->public;
246
0
}
247
248
/**
249
 * Implements host_t.ip_equals
250
 */
251
static bool ip_equals(private_host_t *this, private_host_t *other)
252
0
{
253
0
  if (this->address.sa_family != other->address.sa_family)
254
0
  {
255
    /* 0.0.0.0 and 0::0 are equal */
256
0
    return (is_anyaddr(this) && is_anyaddr(other));
257
0
  }
258
259
0
  switch (this->address.sa_family)
260
0
  {
261
0
    case AF_INET:
262
0
    {
263
0
      return memeq(&this->address4.sin_addr, &other->address4.sin_addr,
264
0
             sizeof(this->address4.sin_addr));
265
0
    }
266
0
    case AF_INET6:
267
0
    {
268
0
      return memeq(&this->address6.sin6_addr, &other->address6.sin6_addr,
269
0
             sizeof(this->address6.sin6_addr));
270
0
    }
271
0
    default:
272
0
      break;
273
0
  }
274
0
  return FALSE;
275
0
}
276
277
/**
278
 * Implements host_t.equals
279
 */
280
static bool equals(private_host_t *this, private_host_t *other)
281
0
{
282
0
  if (!ip_equals(this, other))
283
0
  {
284
0
    return FALSE;
285
0
  }
286
287
0
  switch (this->address.sa_family)
288
0
  {
289
0
    case AF_INET:
290
0
    {
291
0
      return (this->address4.sin_port == other->address4.sin_port);
292
0
    }
293
0
    case AF_INET6:
294
0
    {
295
0
      return (this->address6.sin6_port == other->address6.sin6_port);
296
0
    }
297
0
    default:
298
0
      break;
299
0
  }
300
0
  return FALSE;
301
0
}
302
303
METHOD(host_t, destroy, void,
304
  private_host_t *this)
305
5.72k
{
306
5.72k
  free(this);
307
5.72k
}
308
309
/**
310
 * Creates an empty host_t object
311
 */
312
static private_host_t *host_create_empty(void)
313
5.72k
{
314
5.72k
  private_host_t *this;
315
316
5.72k
  INIT(this,
317
5.72k
    .public = {
318
5.72k
      .get_sockaddr = _get_sockaddr,
319
5.72k
      .get_sockaddr_len = _get_sockaddr_len,
320
5.72k
      .clone = _clone_,
321
5.72k
      .get_family = _get_family,
322
5.72k
      .get_address = _get_address,
323
5.72k
      .get_port = _get_port,
324
5.72k
      .set_port = _set_port,
325
5.72k
      .ip_equals = (bool (*)(host_t *,host_t *))ip_equals,
326
5.72k
      .equals = (bool (*)(host_t *,host_t *)) equals,
327
5.72k
      .is_anyaddr = _is_anyaddr,
328
5.72k
      .destroy = _destroy,
329
5.72k
    },
330
5.72k
  );
331
332
5.72k
  return this;
333
5.72k
}
334
335
/*
336
 * Create a %any host with port
337
 */
338
static host_t *host_create_any_port(int family, uint16_t port)
339
0
{
340
0
  host_t *this;
341
342
0
  this = host_create_any(family);
343
0
  this->set_port(this, port);
344
0
  return this;
345
0
}
346
347
/*
348
 * Described in header.
349
 */
350
host_t *host_create_from_string_and_family(char *string, int family,
351
                       uint16_t port)
352
5.72k
{
353
5.72k
  union {
354
5.72k
    struct sockaddr_in v4;
355
5.72k
    struct sockaddr_in6 v6;
356
5.72k
  } addr;
357
358
5.72k
  if (!string)
359
0
  {
360
0
    return NULL;
361
0
  }
362
5.72k
  if (streq(string, "%any"))
363
0
  {
364
0
    return host_create_any_port(family ? family : AF_INET, port);
365
0
  }
366
5.72k
  if (family == AF_UNSPEC || family == AF_INET)
367
5.72k
  {
368
5.72k
    if (streq(string, "%any4") || streq(string, "0.0.0.0"))
369
0
    {
370
0
      return host_create_any_port(AF_INET, port);
371
0
    }
372
5.72k
  }
373
5.72k
  if (family == AF_UNSPEC || family == AF_INET6)
374
5.72k
  {
375
5.72k
    if (streq(string, "%any6") || streq(string, "::"))
376
0
    {
377
0
      return host_create_any_port(AF_INET6, port);
378
0
    }
379
5.72k
  }
380
5.72k
  switch (family)
381
5.72k
  {
382
5.72k
    case AF_UNSPEC:
383
5.72k
      if (strchr(string, '.'))
384
5.72k
      {
385
5.72k
        goto af_inet;
386
5.72k
      }
387
      /* FALL */
388
0
    case AF_INET6:
389
0
      memset(&addr.v6, 0, sizeof(addr.v6));
390
0
      if (inet_pton(AF_INET6, string, &addr.v6.sin6_addr) != 1)
391
0
      {
392
0
        return NULL;
393
0
      }
394
0
      addr.v6.sin6_port = htons(port);
395
0
      addr.v6.sin6_family = AF_INET6;
396
0
      return host_create_from_sockaddr((sockaddr_t*)&addr);
397
0
    case AF_INET:
398
0
      if (strchr(string, ':'))
399
0
      { /* do not try to convert v6 addresses for v4 family */
400
0
        return NULL;
401
0
      }
402
5.72k
    af_inet:
403
5.72k
      memset(&addr.v4, 0, sizeof(addr.v4));
404
5.72k
      if (inet_pton(AF_INET, string, &addr.v4.sin_addr) != 1)
405
0
      {
406
0
        return NULL;
407
0
      }
408
5.72k
      addr.v4.sin_port = htons(port);
409
5.72k
      addr.v4.sin_family = AF_INET;
410
5.72k
      return host_create_from_sockaddr((sockaddr_t*)&addr);
411
0
    default:
412
0
      return NULL;
413
5.72k
  }
414
5.72k
}
415
416
/*
417
 * Described in header.
418
 */
419
host_t *host_create_from_string(char *string, uint16_t port)
420
5.72k
{
421
5.72k
  return host_create_from_string_and_family(string, AF_UNSPEC, port);
422
5.72k
}
423
424
/*
425
 * Described in header.
426
 */
427
host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
428
5.72k
{
429
5.72k
  private_host_t *this = host_create_empty();
430
431
5.72k
  switch (sockaddr->sa_family)
432
5.72k
  {
433
5.72k
    case AF_INET:
434
5.72k
    {
435
5.72k
      memcpy(&this->address4, (struct sockaddr_in*)sockaddr,
436
5.72k
           sizeof(struct sockaddr_in));
437
5.72k
      this->socklen = sizeof(struct sockaddr_in);
438
5.72k
      update_sa_len(this);
439
5.72k
      return &this->public;
440
0
    }
441
0
    case AF_INET6:
442
0
    {
443
0
      memcpy(&this->address6, (struct sockaddr_in6*)sockaddr,
444
0
           sizeof(struct sockaddr_in6));
445
0
      this->socklen = sizeof(struct sockaddr_in6);
446
0
      update_sa_len(this);
447
0
      return &this->public;
448
0
    }
449
0
    default:
450
0
      break;
451
5.72k
  }
452
0
  free(this);
453
0
  return NULL;
454
5.72k
}
455
456
/*
457
 * Described in header.
458
 */
459
host_t *host_create_from_dns(char *string, int af, uint16_t port)
460
0
{
461
0
  host_t *this;
462
463
0
  this = host_create_from_string_and_family(string, af, port);
464
0
  if (!this && string && string[0] != '%')
465
0
  {
466
0
    this = lib->hosts->resolve(lib->hosts, string, af);
467
0
  }
468
0
  if (this)
469
0
  {
470
0
    this->set_port(this, port);
471
0
  }
472
0
  return this;
473
0
}
474
475
/*
476
 * Described in header.
477
 */
478
host_t *host_create_from_chunk(int family, chunk_t address, uint16_t port)
479
0
{
480
0
  private_host_t *this;
481
482
0
  switch (family)
483
0
  {
484
0
    case AF_INET:
485
0
      if (address.len < IPV4_LEN)
486
0
      {
487
0
        return NULL;
488
0
      }
489
0
      address.len = IPV4_LEN;
490
0
      break;
491
0
    case AF_INET6:
492
0
      if (address.len < IPV6_LEN)
493
0
      {
494
0
        return NULL;
495
0
      }
496
0
      address.len = IPV6_LEN;
497
0
      break;
498
0
    case AF_UNSPEC:
499
0
      switch (address.len)
500
0
      {
501
0
        case IPV4_LEN:
502
0
          family = AF_INET;
503
0
          break;
504
0
        case IPV6_LEN:
505
0
          family = AF_INET6;
506
0
          break;
507
0
        default:
508
0
          return NULL;
509
0
      }
510
0
      break;
511
0
    default:
512
0
      return NULL;
513
0
  }
514
0
  this = host_create_empty();
515
0
  this->address.sa_family = family;
516
0
  switch (family)
517
0
  {
518
0
    case AF_INET:
519
0
      memcpy(&this->address4.sin_addr.s_addr, address.ptr, address.len);
520
0
      this->address4.sin_port = htons(port);
521
0
      this->socklen = sizeof(struct sockaddr_in);
522
0
      break;
523
0
    case AF_INET6:
524
0
      memcpy(&this->address6.sin6_addr.s6_addr, address.ptr, address.len);
525
0
      this->address6.sin6_port = htons(port);
526
0
      this->socklen = sizeof(struct sockaddr_in6);
527
0
      break;
528
0
  }
529
0
  update_sa_len(this);
530
0
  return &this->public;
531
0
}
532
533
/*
534
 * Described in header.
535
 */
536
bool host_create_from_range(char *string, host_t **from, host_t **to)
537
0
{
538
0
  char *sep, *pos;
539
540
0
  sep = strchr(string, '-');
541
0
  if (!sep)
542
0
  {
543
0
    return FALSE;
544
0
  }
545
0
  for (pos = sep+1; *pos && *pos == ' '; pos++)
546
0
  {
547
    /* trim spaces before to address*/
548
0
  }
549
0
  *to = host_create_from_string(pos, 0);
550
0
  if (!*to)
551
0
  {
552
0
    return FALSE;
553
0
  }
554
0
  for (pos = sep-1; pos > string && *pos == ' '; pos--)
555
0
  {
556
    /* trim spaces behind from address */
557
0
  }
558
0
  pos = strndup(string, pos - string + 1);
559
0
  *from = host_create_from_string_and_family(pos, (*to)->get_family(*to), 0);
560
0
  free(pos);
561
0
  if (!*from)
562
0
  {
563
0
    (*to)->destroy(*to);
564
0
    return FALSE;
565
0
  }
566
0
  return TRUE;
567
0
}
568
569
/*
570
 * Described in header.
571
 */
572
host_t *host_create_from_subnet(char *string, int *bits)
573
0
{
574
0
  char *pos, buf[64];
575
0
  host_t *net;
576
577
0
  pos = strchr(string, '/');
578
0
  if (pos)
579
0
  {
580
0
    if (pos - string >= sizeof(buf))
581
0
    {
582
0
      return NULL;
583
0
    }
584
0
    strncpy(buf, string, pos - string);
585
0
    buf[pos - string] = '\0';
586
0
    *bits = atoi(pos + 1);
587
0
    return host_create_from_string(buf, 0);
588
0
  }
589
0
  net = host_create_from_string(string, 0);
590
0
  if (net)
591
0
  {
592
0
    if (net->get_family(net) == AF_INET)
593
0
    {
594
0
      *bits = 32;
595
0
    }
596
0
    else
597
0
    {
598
0
      *bits = 128;
599
0
    }
600
0
  }
601
0
  return net;
602
0
}
603
604
/*
605
 * See header.
606
 */
607
host_t *host_create_netmask(int family, int netbits)
608
0
{
609
0
  private_host_t *this;
610
0
  int bits, bytes, len = 0;
611
0
  char *target;
612
613
0
  switch (family)
614
0
  {
615
0
    case AF_INET:
616
0
      if (netbits < 0 || netbits > 32)
617
0
      {
618
0
        return NULL;
619
0
      }
620
0
      this = host_create_empty();
621
0
      this->socklen = sizeof(struct sockaddr_in);
622
0
      target = (char*)&this->address4.sin_addr;
623
0
      len = 4;
624
0
      break;
625
0
    case AF_INET6:
626
0
      if (netbits < 0 || netbits > 128)
627
0
      {
628
0
        return NULL;
629
0
      }
630
0
      this = host_create_empty();
631
0
      this->socklen = sizeof(struct sockaddr_in6);
632
0
      target = (char*)&this->address6.sin6_addr;
633
0
      len = 16;
634
0
      break;
635
0
    default:
636
0
      return NULL;
637
0
  }
638
639
0
  memset(&this->address_max, 0, sizeof(struct sockaddr_storage));
640
0
  this->address.sa_family = family;
641
0
  update_sa_len(this);
642
643
0
  bytes = netbits / 8;
644
0
  bits = 8 - (netbits & 0x07);
645
646
0
  memset(target, 0xff, bytes);
647
0
  if (bytes < len)
648
0
  {
649
0
    memset(target + bytes, 0x00, len - bytes);
650
0
    target[bytes] = (uint8_t)(0xff << bits);
651
0
  }
652
0
  return &this->public;
653
0
}
654
655
/*
656
 * Described in header.
657
 */
658
host_t *host_create_any(int family)
659
0
{
660
0
  private_host_t *this = host_create_empty();
661
662
0
  memset(&this->address_max, 0, sizeof(struct sockaddr_storage));
663
0
  this->address.sa_family = family;
664
665
0
  switch (family)
666
0
  {
667
0
    case AF_INET:
668
0
    {
669
0
      this->socklen = sizeof(struct sockaddr_in);
670
0
      update_sa_len(this);
671
0
      return &(this->public);
672
0
    }
673
0
    case AF_INET6:
674
0
    {
675
0
      this->socklen = sizeof(struct sockaddr_in6);
676
0
      update_sa_len(this);
677
0
      return &this->public;
678
0
    }
679
0
    default:
680
0
      break;
681
0
  }
682
0
  free(this);
683
  return NULL;
684
0
}