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