1
/* Socket union related function.
2
* Copyright (c) 1997, 98 Kunihiro Ishiguro
4
* This file is part of GNU Zebra.
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
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.
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
26
#include "sockunion.h"
31
#ifndef HAVE_INET_ATON
33
inet_aton (const char *cp, struct in_addr *inaddr)
36
register u_long addr = 0;
37
register u_long val = 0, base = 10;
41
register char c = *cp;
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');
55
addr = addr << 8 | val;
64
addr <<= 8 * (3 - dots);
66
inaddr->s_addr = htonl (addr);
69
#endif /* ! HAVE_INET_ATON */
72
#ifndef HAVE_INET_PTON
74
inet_pton (int family, const char *strptr, void *addrptr)
76
if (family == AF_INET)
78
struct in_addr in_val;
80
if (inet_aton (strptr, &in_val))
82
memcpy (addrptr, &in_val, sizeof (struct in_addr));
90
#endif /* ! HAVE_INET_PTON */
92
#ifndef HAVE_INET_NTOP
94
inet_ntop (int family, const void *addrptr, char *strptr, size_t len)
96
unsigned char *p = (unsigned char *) addrptr;
98
if (family == AF_INET)
100
char temp[INET_ADDRSTRLEN];
102
snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
104
if (strlen(temp) >= len)
109
strcpy(strptr, temp);
113
errno = EAFNOSUPPORT;
116
#endif /* ! HAVE_INET_NTOP */
119
inet_sutop (union sockunion *su, char *str)
121
switch (su->sa.sa_family)
124
inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
128
inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
130
#endif /* HAVE_IPV6 */
136
str2sockunion (char *str, union sockunion *su)
140
memset (su, 0, sizeof (union sockunion));
142
ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
143
if (ret > 0) /* Valid IPv4 address format. */
145
su->sin.sin_family = AF_INET;
147
su->sin.sin_len = sizeof(struct sockaddr_in);
148
#endif /* HAVE_SIN_LEN */
152
ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
153
if (ret > 0) /* Valid IPv6 address format. */
155
su->sin6.sin6_family = AF_INET6;
157
su->sin6.sin6_len = sizeof(struct sockaddr_in6);
158
#endif /* SIN6_LEN */
161
#endif /* HAVE_IPV6 */
166
sockunion2str (union sockunion *su, char *buf, size_t len)
168
if (su->sa.sa_family == AF_INET)
169
return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len);
171
else if (su->sa.sa_family == AF_INET6)
172
return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len);
173
#endif /* HAVE_IPV6 */
178
sockunion_str2su (char *str)
183
su = XMALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
184
memset (su, 0, sizeof (union sockunion));
186
ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
187
if (ret > 0) /* Valid IPv4 address format. */
189
su->sin.sin_family = AF_INET;
191
su->sin.sin_len = sizeof(struct sockaddr_in);
192
#endif /* HAVE_SIN_LEN */
196
ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
197
if (ret > 0) /* Valid IPv6 address format. */
199
su->sin6.sin6_family = AF_INET6;
201
su->sin6.sin6_len = sizeof(struct sockaddr_in6);
202
#endif /* SIN6_LEN */
205
#endif /* HAVE_IPV6 */
207
XFREE (MTYPE_SOCKUNION, su);
212
sockunion_su2str (union sockunion *su)
214
char str[INET6_ADDRSTRLEN];
216
switch (su->sa.sa_family)
219
inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str));
223
inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str));
225
#endif /* HAVE_IPV6 */
230
/* Return socket of sockunion. */
232
sockunion_socket (union sockunion *su)
236
sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
239
zlog (NULL, LOG_WARNING, "Can't make socket : %s", strerror (errno));
246
/* Return accepted new socket file descriptor. */
248
sockunion_accept (int sock, union sockunion *su)
253
len = sizeof (union sockunion);
254
client_sock = accept (sock, (struct sockaddr *) su, &len);
256
/* Convert IPv4 compatible IPv6 address to IPv4 address. */
258
if (su->sa.sa_family == AF_INET6)
260
if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
262
struct sockaddr_in sin;
264
memset (&sin, 0, sizeof (struct sockaddr_in));
265
sin.sin_family = AF_INET;
266
memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
267
memcpy (su, &sin, sizeof (struct sockaddr_in));
270
#endif /* HAVE_IPV6 */
275
/* Return sizeof union sockunion. */
277
sockunion_sizeof (union sockunion *su)
282
switch (su->sa.sa_family)
285
ret = sizeof (struct sockaddr_in);
289
ret = sizeof (struct sockaddr_in6);
291
#endif /* AF_INET6 */
296
/* return sockunion structure : this function should be revised. */
298
sockunion_log (union sockunion *su)
300
static char buf[SU_ADDRSTRLEN];
302
switch (su->sa.sa_family)
305
snprintf (buf, SU_ADDRSTRLEN, "%s", inet_ntoa (su->sin.sin_addr));
309
snprintf (buf, SU_ADDRSTRLEN, "%s",
310
inet_ntop (AF_INET6, &(su->sin6.sin6_addr), buf, SU_ADDRSTRLEN));
312
#endif /* HAVE_IPV6 */
314
snprintf (buf, SU_ADDRSTRLEN, "af_unknown %d ", su->sa.sa_family);
320
/* sockunion_connect returns
323
1 : connect is in progress */
325
sockunion_connect (int fd, union sockunion *peersu, unsigned short port,
326
unsigned int ifindex)
332
memcpy (&su, peersu, sizeof (union sockunion));
334
switch (su.sa.sa_family)
337
su.sin.sin_port = port;
341
su.sin6.sin6_port = port;
343
if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex)
345
#ifdef HAVE_SIN6_SCOPE_ID
346
/* su.sin6.sin6_scope_id = ifindex; */
348
su.sin6.sin6_scope_id = ifindex;
350
#endif /* HAVE_SIN6_SCOPE_ID */
352
SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex);
357
#endif /* HAVE_IPV6 */
360
/* Make socket non-block. */
361
val = fcntl (fd, F_GETFL, 0);
362
fcntl (fd, F_SETFL, val|O_NONBLOCK);
364
/* Call connect function. */
365
ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su));
367
/* Immediate success */
370
fcntl (fd, F_SETFL, val);
371
return connect_success;
374
/* If connect is in progress then return 1 else it's real error. */
377
if (errno != EINPROGRESS)
379
zlog_info ("can't connect to %s fd %d : %s",
380
sockunion_log (&su), fd, strerror (errno));
381
return connect_error;
385
fcntl (fd, F_SETFL, val);
387
return connect_in_progress;
390
/* Make socket from sockunion union. */
392
sockunion_stream_socket (union sockunion *su)
396
if (su->sa.sa_family == 0)
397
su->sa.sa_family = AF_INET_UNION;
399
sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
402
zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket");
407
/* Bind socket to specified address. */
409
sockunion_bind (int sock, union sockunion *su, unsigned short port,
410
union sockunion *su_addr)
415
if (su->sa.sa_family == AF_INET)
417
size = sizeof (struct sockaddr_in);
418
su->sin.sin_port = htons (port);
420
su->sin.sin_len = size;
421
#endif /* HAVE_SIN_LEN */
423
su->sin.sin_addr.s_addr = htonl (INADDR_ANY);
426
else if (su->sa.sa_family == AF_INET6)
428
size = sizeof (struct sockaddr_in6);
429
su->sin6.sin6_port = htons (port);
431
su->sin6.sin6_len = size;
432
#endif /* SIN6_LEN */
435
#if defined(LINUX_IPV6) || defined(NRL)
436
memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr));
438
su->sin6.sin6_addr = in6addr_any;
439
#endif /* LINUX_IPV6 */
442
#endif /* HAVE_IPV6 */
445
ret = bind (sock, (struct sockaddr *)su, size);
447
zlog (NULL, LOG_WARNING, "can't bind socket : %s", strerror (errno));
453
sockopt_reuseaddr (int sock)
458
ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
459
(void *) &on, sizeof (on));
462
zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
470
sockopt_reuseport (int sock)
475
ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT,
476
(void *) &on, sizeof (on));
479
zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
486
sockopt_reuseport (int sock)
493
sockopt_ttl (int family, int sock, int ttl)
498
if (family == AF_INET)
500
ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
501
(void *) &ttl, sizeof (int));
504
zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock);
511
if (family == AF_INET6)
513
ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
514
(void *) &ttl, sizeof (int));
517
zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
523
#endif /* HAVE_IPV6 */
527
/* If same family and same prefix return 1. */
529
sockunion_same (union sockunion *su1, union sockunion *su2)
533
if (su1->sa.sa_family != su2->sa.sa_family)
536
switch (su1->sa.sa_family)
539
ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr,
540
sizeof (struct in_addr));
544
ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
545
sizeof (struct in6_addr));
547
#endif /* HAVE_IPV6 */
555
/* After TCP connection is established. Get local address and port. */
557
sockunion_getsockname (int fd)
564
struct sockaddr_in sin;
566
struct sockaddr_in6 sin6;
567
#endif /* HAVE_IPV6 */
568
char tmp_buffer[128];
572
memset (&name, 0, sizeof name);
575
ret = getsockname (fd, (struct sockaddr *)&name, &len);
578
zlog_warn ("Can't get local address and port by getsockname: %s",
583
if (name.sa.sa_family == AF_INET)
585
su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
586
memcpy (su, &name, sizeof (struct sockaddr_in));
590
if (name.sa.sa_family == AF_INET6)
592
su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
593
memcpy (su, &name, sizeof (struct sockaddr_in6));
595
if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
597
struct sockaddr_in sin;
599
sin.sin_family = AF_INET;
600
memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
601
sin.sin_port = su->sin6.sin6_port;
602
memcpy (su, &sin, sizeof (struct sockaddr_in));
606
#endif /* HAVE_IPV6 */
610
/* After TCP connection is established. Get remote address and port. */
612
sockunion_getpeername (int fd)
619
struct sockaddr_in sin;
621
struct sockaddr_in6 sin6;
622
#endif /* HAVE_IPV6 */
623
char tmp_buffer[128];
627
memset (&name, 0, sizeof name);
629
ret = getpeername (fd, (struct sockaddr *)&name, &len);
632
zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s",
637
if (name.sa.sa_family == AF_INET)
639
su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
640
memcpy (su, &name, sizeof (struct sockaddr_in));
644
if (name.sa.sa_family == AF_INET6)
646
su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
647
memcpy (su, &name, sizeof (struct sockaddr_in6));
649
if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
651
struct sockaddr_in sin;
653
sin.sin_family = AF_INET;
654
memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
655
sin.sin_port = su->sin6.sin6_port;
656
memcpy (su, &sin, sizeof (struct sockaddr_in));
660
#endif /* HAVE_IPV6 */
664
/* Print sockunion structure */
666
sockunion_print (union sockunion *su)
671
switch (su->sa.sa_family)
674
printf ("%s\n", inet_ntoa (su->sin.sin_addr));
681
printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr),
685
#endif /* HAVE_IPV6 */
690
struct sockaddr_dl *sdl;
692
sdl = (struct sockaddr_dl *)&(su->sa);
693
printf ("link#%d\n", sdl->sdl_index);
698
printf ("af_unknown %d\n", su->sa.sa_family);
705
in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2)
710
p1 = (u_char *)addr1;
711
p2 = (u_char *)addr2;
713
for (i = 0; i < sizeof (struct in6_addr); i++)
717
else if (p1[i] < p2[i])
722
#endif /* HAVE_IPV6 */
725
sockunion_cmp (union sockunion *su1, union sockunion *su2)
727
if (su1->sa.sa_family > su2->sa.sa_family)
729
if (su1->sa.sa_family < su2->sa.sa_family)
732
if (su1->sa.sa_family == AF_INET)
734
if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr))
736
if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr))
742
if (su1->sa.sa_family == AF_INET6)
743
return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
744
#endif /* HAVE_IPV6 */
748
/* Duplicate sockunion. */
750
sockunion_dup (union sockunion *su)
752
union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
753
memcpy (dup, su, sizeof (union sockunion));
758
sockunion_free (union sockunion *su)
760
XFREE (MTYPE_SOCKUNION, su);