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