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