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