Coverage Report

Created: 2025-11-11 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/sockunion.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Socket union related function.
3
 * Copyright (c) 1997, 98 Kunihiro Ishiguro
4
 */
5
6
#include <zebra.h>
7
8
#include "prefix.h"
9
#include "vty.h"
10
#include "sockunion.h"
11
#include "memory.h"
12
#include "log.h"
13
#include "jhash.h"
14
#include "lib_errors.h"
15
#include "printfrr.h"
16
17
8
DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union");
18
8
19
8
const char *inet_sutop(const union sockunion *su, char *str)
20
8
{
21
0
  switch (su->sa.sa_family) {
22
0
  case AF_INET:
23
0
    inet_ntop(AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
24
0
    break;
25
0
  case AF_INET6:
26
0
    inet_ntop(AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
27
0
    break;
28
0
  }
29
0
  return str;
30
0
}
31
32
int str2sockunion(const char *str, union sockunion *su)
33
0
{
34
0
  int ret;
35
36
0
  if (str == NULL)
37
0
    return -1;
38
39
0
  memset(su, 0, sizeof(union sockunion));
40
41
0
  ret = inet_pton(AF_INET, str, &su->sin.sin_addr);
42
0
  if (ret > 0) /* Valid IPv4 address format. */
43
0
  {
44
0
    su->sin.sin_family = AF_INET;
45
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
46
    su->sin.sin_len = sizeof(struct sockaddr_in);
47
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
48
0
    return 0;
49
0
  }
50
0
  ret = inet_pton(AF_INET6, str, &su->sin6.sin6_addr);
51
0
  if (ret > 0) /* Valid IPv6 address format. */
52
0
  {
53
0
    su->sin6.sin6_family = AF_INET6;
54
#ifdef SIN6_LEN
55
    su->sin6.sin6_len = sizeof(struct sockaddr_in6);
56
#endif /* SIN6_LEN */
57
0
    return 0;
58
0
  }
59
0
  return -1;
60
0
}
61
62
const char *sockunion2str(const union sockunion *su, char *buf, size_t len)
63
1
{
64
1
  switch (sockunion_family(su)) {
65
0
  case AF_UNSPEC:
66
0
    snprintf(buf, len, "(unspec)");
67
0
    return buf;
68
1
  case AF_INET:
69
1
    return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len);
70
0
  case AF_INET6:
71
0
    return inet_ntop(AF_INET6, &su->sin6.sin6_addr, buf, len);
72
1
  }
73
0
  snprintf(buf, len, "(af %d)", sockunion_family(su));
74
0
  return buf;
75
1
}
76
77
union sockunion *sockunion_str2su(const char *str)
78
0
{
79
0
  union sockunion *su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
80
81
0
  if (!str2sockunion(str, su))
82
0
    return su;
83
84
0
  XFREE(MTYPE_SOCKUNION, su);
85
0
  return NULL;
86
0
}
87
88
/* Convert IPv4 compatible IPv6 address to IPv4 address. */
89
static void sockunion_normalise_mapped(union sockunion *su)
90
0
{
91
0
  struct sockaddr_in sin;
92
93
0
  if (su->sa.sa_family == AF_INET6
94
0
      && IN6_IS_ADDR_V4MAPPED(&su->sin6.sin6_addr)) {
95
0
    memset(&sin, 0, sizeof(sin));
96
0
    sin.sin_family = AF_INET;
97
0
    sin.sin_port = su->sin6.sin6_port;
98
0
    memcpy(&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
99
0
    memcpy(su, &sin, sizeof(struct sockaddr_in));
100
0
  }
101
0
}
102
103
/* return sockunion structure : this function should be revised. */
104
static const char *sockunion_log(const union sockunion *su, char *buf,
105
         size_t len)
106
0
{
107
0
  switch (su->sa.sa_family) {
108
0
  case AF_INET:
109
0
    return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len);
110
0
111
0
  case AF_INET6:
112
0
    return inet_ntop(AF_INET6, &(su->sin6.sin6_addr), buf, len);
113
0
114
0
  default:
115
0
    snprintf(buf, len, "af_unknown %d ", su->sa.sa_family);
116
0
    return buf;
117
0
  }
118
0
}
119
120
/* Return socket of sockunion. */
121
int sockunion_socket(const union sockunion *su)
122
0
{
123
0
  int sock;
124
125
0
  sock = socket(su->sa.sa_family, SOCK_STREAM, 0);
126
0
  if (sock < 0) {
127
0
    char buf[SU_ADDRSTRLEN];
128
0
    flog_err(EC_LIB_SOCKET, "Can't make socket for %s : %s",
129
0
       sockunion_log(su, buf, SU_ADDRSTRLEN),
130
0
       safe_strerror(errno));
131
0
    return -1;
132
0
  }
133
134
0
  return sock;
135
0
}
136
137
/* Return accepted new socket file descriptor. */
138
int sockunion_accept(int sock, union sockunion *su)
139
0
{
140
0
  socklen_t len;
141
0
  int client_sock;
142
143
0
  len = sizeof(union sockunion);
144
0
  client_sock = accept(sock, (struct sockaddr *)su, &len);
145
146
0
  sockunion_normalise_mapped(su);
147
0
  return client_sock;
148
0
}
149
150
/* Return sizeof union sockunion.  */
151
int sockunion_sizeof(const union sockunion *su)
152
0
{
153
0
  int ret;
154
155
0
  ret = 0;
156
0
  switch (su->sa.sa_family) {
157
0
  case AF_INET:
158
0
    ret = sizeof(struct sockaddr_in);
159
0
    break;
160
0
  case AF_INET6:
161
0
    ret = sizeof(struct sockaddr_in6);
162
0
    break;
163
0
  }
164
0
  return ret;
165
0
}
166
167
/* Performs a non-blocking connect().  */
168
enum connect_result sockunion_connect(int fd, const union sockunion *peersu,
169
              unsigned short port, ifindex_t ifindex)
170
0
{
171
0
  int ret;
172
0
  union sockunion su;
173
174
0
  memcpy(&su, peersu, sizeof(union sockunion));
175
176
0
  switch (su.sa.sa_family) {
177
0
  case AF_INET:
178
0
    su.sin.sin_port = port;
179
0
    break;
180
0
  case AF_INET6:
181
0
    su.sin6.sin6_port = port;
182
#ifdef KAME
183
    if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) {
184
      su.sin6.sin6_scope_id = ifindex;
185
      SET_IN6_LINKLOCAL_IFINDEX(su.sin6.sin6_addr, ifindex);
186
    }
187
#endif /* KAME */
188
0
    break;
189
0
  }
190
191
  /* Call connect function. */
192
0
  ret = connect(fd, (struct sockaddr *)&su, sockunion_sizeof(&su));
193
194
  /* Immediate success */
195
0
  if (ret == 0)
196
0
    return connect_success;
197
198
  /* If connect is in progress then return 1 else it's real error. */
199
0
  if (ret < 0) {
200
0
    if (errno != EINPROGRESS) {
201
0
      char str[SU_ADDRSTRLEN];
202
0
      zlog_info("can't connect to %s fd %d : %s",
203
0
          sockunion_log(&su, str, sizeof(str)), fd,
204
0
          safe_strerror(errno));
205
0
      return connect_error;
206
0
    }
207
0
  }
208
209
0
  return connect_in_progress;
210
0
}
211
212
/* Make socket from sockunion union. */
213
int sockunion_stream_socket(union sockunion *su)
214
0
{
215
0
  int sock;
216
217
0
  if (su->sa.sa_family == 0)
218
0
    su->sa.sa_family = AF_INET_UNION;
219
220
0
  sock = socket(su->sa.sa_family, SOCK_STREAM, 0);
221
222
0
  if (sock < 0)
223
0
    flog_err(EC_LIB_SOCKET,
224
0
       "can't make socket sockunion_stream_socket");
225
226
0
  return sock;
227
0
}
228
229
/* Bind socket to specified address. */
230
int sockunion_bind(int sock, union sockunion *su, unsigned short port,
231
       union sockunion *su_addr)
232
0
{
233
0
  int size = 0;
234
0
  int ret;
235
236
0
  if (su->sa.sa_family == AF_INET) {
237
0
    size = sizeof(struct sockaddr_in);
238
0
    su->sin.sin_port = htons(port);
239
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
240
    su->sin.sin_len = size;
241
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
242
0
    if (su_addr == NULL)
243
0
      sockunion2ip(su) = htonl(INADDR_ANY);
244
0
  } else if (su->sa.sa_family == AF_INET6) {
245
0
    size = sizeof(struct sockaddr_in6);
246
0
    su->sin6.sin6_port = htons(port);
247
#ifdef SIN6_LEN
248
    su->sin6.sin6_len = size;
249
#endif /* SIN6_LEN */
250
0
    if (su_addr == NULL) {
251
0
#ifdef LINUX_IPV6
252
0
      memset(&su->sin6.sin6_addr, 0, sizeof(struct in6_addr));
253
#else
254
      su->sin6.sin6_addr = in6addr_any;
255
#endif /* LINUX_IPV6 */
256
0
    }
257
0
  }
258
259
0
  ret = bind(sock, (struct sockaddr *)su, size);
260
0
  if (ret < 0) {
261
0
    char buf[SU_ADDRSTRLEN];
262
0
    flog_err(EC_LIB_SOCKET, "can't bind socket for %s : %s",
263
0
       sockunion_log(su, buf, SU_ADDRSTRLEN),
264
0
       safe_strerror(errno));
265
0
  }
266
267
0
  return ret;
268
0
}
269
270
int sockopt_reuseaddr(int sock)
271
0
{
272
0
  int ret;
273
0
  int on = 1;
274
275
0
  ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
276
0
       sizeof(on));
277
0
  if (ret < 0) {
278
0
    flog_err(
279
0
      EC_LIB_SOCKET,
280
0
      "can't set sockopt SO_REUSEADDR to socket %d errno=%d: %s",
281
0
      sock, errno, safe_strerror(errno));
282
0
    return -1;
283
0
  }
284
0
  return 0;
285
0
}
286
287
#ifdef SO_REUSEPORT
288
int sockopt_reuseport(int sock)
289
0
{
290
0
  int ret;
291
0
  int on = 1;
292
293
0
  ret = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&on,
294
0
       sizeof(on));
295
0
  if (ret < 0) {
296
0
    flog_err(EC_LIB_SOCKET,
297
0
       "can't set sockopt SO_REUSEPORT to socket %d", sock);
298
0
    return -1;
299
0
  }
300
0
  return 0;
301
0
}
302
#else
303
int sockopt_reuseport(int sock)
304
{
305
  return 0;
306
}
307
#endif /* 0 */
308
309
int sockopt_ttl(int family, int sock, int ttl)
310
0
{
311
0
  int ret;
312
313
0
#ifdef IP_TTL
314
0
  if (family == AF_INET) {
315
0
    ret = setsockopt(sock, IPPROTO_IP, IP_TTL, (void *)&ttl,
316
0
         sizeof(int));
317
0
    if (ret < 0) {
318
0
      flog_err(EC_LIB_SOCKET,
319
0
         "can't set sockopt IP_TTL %d to socket %d",
320
0
         ttl, sock);
321
0
      return -1;
322
0
    }
323
0
    return 0;
324
0
  }
325
0
#endif /* IP_TTL */
326
0
  if (family == AF_INET6) {
327
0
    ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
328
0
         (void *)&ttl, sizeof(int));
329
0
    if (ret < 0) {
330
0
      flog_err(
331
0
        EC_LIB_SOCKET,
332
0
        "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
333
0
        ttl, sock);
334
0
      return -1;
335
0
    }
336
0
    return 0;
337
0
  }
338
0
  return 0;
339
0
}
340
341
int sockopt_minttl(int family, int sock, int minttl)
342
0
{
343
0
#ifdef IP_MINTTL
344
0
  if (family == AF_INET) {
345
0
    int ret = setsockopt(sock, IPPROTO_IP, IP_MINTTL, &minttl,
346
0
             sizeof(minttl));
347
0
    if (ret < 0)
348
0
      flog_err(
349
0
        EC_LIB_SOCKET,
350
0
        "can't set sockopt IP_MINTTL to %d on socket %d: %s",
351
0
        minttl, sock, safe_strerror(errno));
352
0
    return ret;
353
0
  }
354
0
#endif /* IP_MINTTL */
355
0
#ifdef IPV6_MINHOPCOUNT
356
0
  if (family == AF_INET6) {
357
0
    int ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
358
0
             &minttl, sizeof(minttl));
359
0
    if (ret < 0)
360
0
      flog_err(
361
0
        EC_LIB_SOCKET,
362
0
        "can't set sockopt IPV6_MINHOPCOUNT to %d on socket %d: %s",
363
0
        minttl, sock, safe_strerror(errno));
364
0
    return ret;
365
0
  }
366
0
#endif
367
368
0
  errno = EOPNOTSUPP;
369
0
  return -1;
370
0
}
371
372
int sockopt_v6only(int family, int sock)
373
0
{
374
0
  int ret, on = 1;
375
376
0
#ifdef IPV6_V6ONLY
377
0
  if (family == AF_INET6) {
378
0
    ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on,
379
0
         sizeof(int));
380
0
    if (ret < 0) {
381
0
      flog_err(EC_LIB_SOCKET,
382
0
         "can't set sockopt IPV6_V6ONLY to socket %d",
383
0
         sock);
384
0
      return -1;
385
0
    }
386
0
    return 0;
387
0
  }
388
0
#endif /* IPV6_V6ONLY */
389
0
  return 0;
390
0
}
391
392
/* If same family and same prefix return 1. */
393
int sockunion_same(const union sockunion *su1, const union sockunion *su2)
394
0
{
395
0
  int ret = 0;
396
397
0
  if (su1->sa.sa_family != su2->sa.sa_family)
398
0
    return 0;
399
400
0
  switch (su1->sa.sa_family) {
401
0
  case AF_INET:
402
0
    ret = memcmp(&su1->sin.sin_addr, &su2->sin.sin_addr,
403
0
           sizeof(struct in_addr));
404
0
    break;
405
0
  case AF_INET6:
406
0
    ret = memcmp(&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
407
0
           sizeof(struct in6_addr));
408
0
    if ((ret == 0) && IN6_IS_ADDR_LINKLOCAL(&su1->sin6.sin6_addr)) {
409
      /* compare interface indices */
410
0
      if (su1->sin6.sin6_scope_id && su2->sin6.sin6_scope_id)
411
0
        ret = (su1->sin6.sin6_scope_id
412
0
               == su2->sin6.sin6_scope_id)
413
0
                ? 0
414
0
                : 1;
415
0
    }
416
0
    break;
417
0
  }
418
0
  if (ret == 0)
419
0
    return 1;
420
0
  else
421
0
    return 0;
422
0
}
423
424
unsigned int sockunion_hash(const union sockunion *su)
425
1
{
426
1
  switch (sockunion_family(su)) {
427
1
  case AF_INET:
428
1
    return jhash_1word(su->sin.sin_addr.s_addr, 0);
429
0
  case AF_INET6:
430
0
    return jhash2(su->sin6.sin6_addr.s6_addr32,
431
0
            array_size(su->sin6.sin6_addr.s6_addr32), 0);
432
1
  }
433
0
  return 0;
434
1
}
435
436
size_t family2addrsize(int family)
437
0
{
438
0
  switch (family) {
439
0
  case AF_INET:
440
0
    return sizeof(struct in_addr);
441
0
  case AF_INET6:
442
0
    return sizeof(struct in6_addr);
443
0
  }
444
0
  return 0;
445
0
}
446
447
size_t sockunion_get_addrlen(const union sockunion *su)
448
0
{
449
0
  return family2addrsize(sockunion_family(su));
450
0
}
451
452
const uint8_t *sockunion_get_addr(const union sockunion *su)
453
0
{
454
0
  switch (sockunion_family(su)) {
455
0
  case AF_INET:
456
0
    return (const uint8_t *)&su->sin.sin_addr.s_addr;
457
0
  case AF_INET6:
458
0
    return (const uint8_t *)&su->sin6.sin6_addr;
459
0
  }
460
0
  return NULL;
461
0
}
462
463
void sockunion_set(union sockunion *su, int family, const uint8_t *addr,
464
       size_t bytes)
465
0
{
466
0
  if (family2addrsize(family) != bytes)
467
0
    return;
468
469
0
  sockunion_family(su) = family;
470
0
  switch (family) {
471
0
  case AF_INET:
472
0
    memcpy(&su->sin.sin_addr.s_addr, addr, bytes);
473
0
    break;
474
0
  case AF_INET6:
475
0
    memcpy(&su->sin6.sin6_addr, addr, bytes);
476
0
    break;
477
0
  }
478
0
}
479
480
/* After TCP connection is established.  Get local address and port. */
481
union sockunion *sockunion_getsockname(int fd)
482
0
{
483
0
  int ret;
484
0
  socklen_t len;
485
0
  union {
486
0
    struct sockaddr sa;
487
0
    struct sockaddr_in sin;
488
0
    struct sockaddr_in6 sin6;
489
0
    char tmp_buffer[128];
490
0
  } name;
491
0
  union sockunion *su;
492
493
0
  memset(&name, 0, sizeof(name));
494
0
  len = sizeof(name);
495
496
0
  ret = getsockname(fd, (struct sockaddr *)&name, &len);
497
0
  if (ret < 0) {
498
0
    flog_err(EC_LIB_SOCKET,
499
0
       "Can't get local address and port by getsockname: %s",
500
0
       safe_strerror(errno));
501
0
    return NULL;
502
0
  }
503
504
0
  if (name.sa.sa_family == AF_INET) {
505
0
    su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
506
0
    memcpy(su, &name, sizeof(struct sockaddr_in));
507
0
    return su;
508
0
  }
509
0
  if (name.sa.sa_family == AF_INET6) {
510
0
    su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
511
0
    memcpy(su, &name, sizeof(struct sockaddr_in6));
512
0
    sockunion_normalise_mapped(su);
513
0
    return su;
514
0
  }
515
516
0
  flog_err(
517
0
    EC_LIB_SOCKET,
518
0
    "Unexpected AFI received(%d) for sockunion_getsockname call for fd: %d",
519
0
    name.sa.sa_family, fd);
520
0
  return NULL;
521
0
}
522
523
/* After TCP connection is established.  Get remote address and port. */
524
union sockunion *sockunion_getpeername(int fd)
525
0
{
526
0
  int ret;
527
0
  socklen_t len;
528
0
  union {
529
0
    struct sockaddr sa;
530
0
    struct sockaddr_in sin;
531
0
    struct sockaddr_in6 sin6;
532
0
    char tmp_buffer[128];
533
0
  } name;
534
0
  union sockunion *su;
535
536
0
  memset(&name, 0, sizeof(name));
537
0
  len = sizeof(name);
538
0
  ret = getpeername(fd, (struct sockaddr *)&name, &len);
539
0
  if (ret < 0) {
540
0
    flog_err(EC_LIB_SOCKET, "Can't get remote address and port: %s",
541
0
       safe_strerror(errno));
542
0
    return NULL;
543
0
  }
544
545
0
  if (name.sa.sa_family == AF_INET) {
546
0
    su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
547
0
    memcpy(su, &name, sizeof(struct sockaddr_in));
548
0
    return su;
549
0
  }
550
0
  if (name.sa.sa_family == AF_INET6) {
551
0
    su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
552
0
    memcpy(su, &name, sizeof(struct sockaddr_in6));
553
0
    sockunion_normalise_mapped(su);
554
0
    return su;
555
0
  }
556
557
0
  flog_err(
558
0
    EC_LIB_SOCKET,
559
0
    "Unexpected AFI received(%d) for sockunion_getpeername call for fd: %d",
560
0
    name.sa.sa_family, fd);
561
0
  return NULL;
562
0
}
563
564
/* Print sockunion structure */
565
static void __attribute__((unused)) sockunion_print(const union sockunion *su)
566
0
{
567
0
  if (su == NULL)
568
0
    return;
569
0
570
0
  switch (su->sa.sa_family) {
571
0
  case AF_INET:
572
0
    printf("%pI4\n", &su->sin.sin_addr);
573
0
    break;
574
0
  case AF_INET6:
575
0
    printf("%pI6\n", &su->sin6.sin6_addr);
576
0
    break;
577
0
#ifdef AF_LINK
578
0
  case AF_LINK: {
579
0
    struct sockaddr_dl *sdl;
580
0
581
0
    sdl = (struct sockaddr_dl *)&(su->sa);
582
0
    printf("link#%d\n", sdl->sdl_index);
583
0
  } break;
584
0
#endif /* AF_LINK */
585
0
  default:
586
0
    printf("af_unknown %d\n", su->sa.sa_family);
587
0
    break;
588
0
  }
589
0
}
590
591
int in6addr_cmp(const struct in6_addr *addr1, const struct in6_addr *addr2)
592
0
{
593
0
  unsigned int i;
594
0
  const uint8_t *p1, *p2;
595
596
0
  p1 = (const uint8_t *)addr1;
597
0
  p2 = (const uint8_t *)addr2;
598
599
0
  for (i = 0; i < sizeof(struct in6_addr); i++) {
600
0
    if (p1[i] > p2[i])
601
0
      return 1;
602
0
    else if (p1[i] < p2[i])
603
0
      return -1;
604
0
  }
605
0
  return 0;
606
0
}
607
608
int sockunion_cmp(const union sockunion *su1, const union sockunion *su2)
609
0
{
610
0
  if (su1->sa.sa_family > su2->sa.sa_family)
611
0
    return 1;
612
0
  if (su1->sa.sa_family < su2->sa.sa_family)
613
0
    return -1;
614
615
0
  if (su1->sa.sa_family == AF_INET) {
616
0
    if (ntohl(sockunion2ip(su1)) == ntohl(sockunion2ip(su2)))
617
0
      return 0;
618
0
    if (ntohl(sockunion2ip(su1)) > ntohl(sockunion2ip(su2)))
619
0
      return 1;
620
0
    else
621
0
      return -1;
622
0
  }
623
0
  if (su1->sa.sa_family == AF_INET6)
624
0
    return in6addr_cmp(&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
625
0
  return 0;
626
0
}
627
628
/* Duplicate sockunion. */
629
union sockunion *sockunion_dup(const union sockunion *su)
630
0
{
631
0
  union sockunion *dup =
632
0
    XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
633
0
  memcpy(dup, su, sizeof(union sockunion));
634
0
  return dup;
635
0
}
636
637
void sockunion_free(union sockunion *su)
638
0
{
639
0
  XFREE(MTYPE_SOCKUNION, su);
640
0
}
641
642
void sockunion_init(union sockunion *su)
643
1
{
644
1
  memset(su, 0, sizeof(union sockunion));
645
1
}
646
647
printfrr_ext_autoreg_p("SU", printfrr_psu);
648
static ssize_t printfrr_psu(struct fbuf *buf, struct printfrr_eargs *ea,
649
          const void *ptr)
650
0
{
651
0
  const union sockunion *su = ptr;
652
0
  bool include_port = false, include_scope = false;
653
0
  bool endflags = false;
654
0
  ssize_t ret = 0;
655
0
  char cbuf[INET6_ADDRSTRLEN];
656
657
0
  if (!su)
658
0
    return bputs(buf, "(null)");
659
660
0
  while (!endflags) {
661
0
    switch (*ea->fmt) {
662
0
    case 'p':
663
0
      ea->fmt++;
664
0
      include_port = true;
665
0
      break;
666
0
    case 's':
667
0
      ea->fmt++;
668
0
      include_scope = true;
669
0
      break;
670
0
    default:
671
0
      endflags = true;
672
0
      break;
673
0
    }
674
0
  }
675
676
0
  switch (sockunion_family(su)) {
677
0
  case AF_UNSPEC:
678
0
    ret += bputs(buf, "(unspec)");
679
0
    break;
680
0
  case AF_INET:
681
0
    inet_ntop(AF_INET, &su->sin.sin_addr, cbuf, sizeof(cbuf));
682
0
    ret += bputs(buf, cbuf);
683
0
    if (include_port)
684
0
      ret += bprintfrr(buf, ":%d", ntohs(su->sin.sin_port));
685
0
    break;
686
0
  case AF_INET6:
687
0
    if (include_port)
688
0
      ret += bputch(buf, '[');
689
0
    inet_ntop(AF_INET6, &su->sin6.sin6_addr, cbuf, sizeof(cbuf));
690
0
    ret += bputs(buf, cbuf);
691
0
    if (include_scope && su->sin6.sin6_scope_id)
692
0
      ret += bprintfrr(buf, "%%%u",
693
0
           (unsigned int)su->sin6.sin6_scope_id);
694
0
    if (include_port)
695
0
      ret += bprintfrr(buf, "]:%d",
696
0
           ntohs(su->sin6.sin6_port));
697
0
    break;
698
0
  case AF_UNIX: {
699
0
    int len;
700
0
#ifdef __linux__
701
0
    if (su->sun.sun_path[0] == '\0' && su->sun.sun_path[1]) {
702
0
      len = strnlen(su->sun.sun_path + 1,
703
0
              sizeof(su->sun.sun_path) - 1);
704
0
      ret += bprintfrr(buf, "@%*pSE", len,
705
0
           su->sun.sun_path + 1);
706
0
      break;
707
0
    }
708
0
#endif
709
0
    len = strnlen(su->sun.sun_path, sizeof(su->sun.sun_path));
710
0
    ret += bprintfrr(buf, "%*pSE", len, su->sun.sun_path);
711
0
    break;
712
0
  }
713
0
  default:
714
0
    ret += bprintfrr(buf, "(af %d)", sockunion_family(su));
715
0
  }
716
717
0
  return ret;
718
0
}
719
720
int sockunion_is_null(const union sockunion *su)
721
0
{
722
0
  unsigned char null_s6_addr[16] = {0};
723
724
0
  switch (sockunion_family(su)) {
725
0
  case AF_UNSPEC:
726
0
    return 1;
727
0
  case AF_INET:
728
0
    return (su->sin.sin_addr.s_addr == 0);
729
0
  case AF_INET6:
730
0
    return !memcmp(su->sin6.sin6_addr.s6_addr, null_s6_addr,
731
0
             sizeof(null_s6_addr));
732
0
  default:
733
0
    return 0;
734
0
  }
735
0
}
736
737
printfrr_ext_autoreg_i("PF", printfrr_pf);
738
static ssize_t printfrr_pf(struct fbuf *buf, struct printfrr_eargs *ea,
739
         uintmax_t val)
740
0
{
741
0
  switch (val) {
742
0
  case AF_INET:
743
0
    return bputs(buf, "AF_INET");
744
0
  case AF_INET6:
745
0
    return bputs(buf, "AF_INET6");
746
0
  case AF_UNIX:
747
0
    return bputs(buf, "AF_UNIX");
748
0
#ifdef AF_PACKET
749
0
  case AF_PACKET:
750
0
    return bputs(buf, "AF_PACKET");
751
0
#endif
752
0
#ifdef AF_NETLINK
753
0
  case AF_NETLINK:
754
0
    return bputs(buf, "AF_NETLINK");
755
0
#endif
756
0
  }
757
0
  return bprintfrr(buf, "AF_(%ju)", val);
758
0
}
759
760
printfrr_ext_autoreg_i("SO", printfrr_so);
761
static ssize_t printfrr_so(struct fbuf *buf, struct printfrr_eargs *ea,
762
         uintmax_t val)
763
0
{
764
0
  switch (val) {
765
0
  case SOCK_STREAM:
766
0
    return bputs(buf, "SOCK_STREAM");
767
0
  case SOCK_DGRAM:
768
0
    return bputs(buf, "SOCK_DGRAM");
769
0
  case SOCK_SEQPACKET:
770
0
    return bputs(buf, "SOCK_SEQPACKET");
771
0
#ifdef SOCK_RAW
772
0
  case SOCK_RAW:
773
0
    return bputs(buf, "SOCK_RAW");
774
0
#endif
775
0
#ifdef SOCK_PACKET
776
0
  case SOCK_PACKET:
777
0
    return bputs(buf, "SOCK_PACKET");
778
0
#endif
779
0
  }
780
0
  return bprintfrr(buf, "SOCK_(%ju)", val);
781
0
}