Line data Source code
1 : /* setsockopt functions
2 : * Copyright (C) 1999 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 : #include "log.h"
24 : #include "sockopt.h"
25 : #include "sockunion.h"
26 :
27 : int
28 0 : setsockopt_so_recvbuf (int sock, int size)
29 : {
30 : int ret;
31 :
32 0 : if ( (ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *)
33 : &size, sizeof (int))) < 0)
34 0 : zlog_err ("fd %d: can't setsockopt SO_RCVBUF to %d: %s",
35 0 : sock,size,safe_strerror(errno));
36 :
37 0 : return ret;
38 : }
39 :
40 : int
41 0 : setsockopt_so_sendbuf (const int sock, int size)
42 : {
43 0 : int ret = setsockopt (sock, SOL_SOCKET, SO_SNDBUF,
44 : (char *)&size, sizeof (int));
45 :
46 0 : if (ret < 0)
47 0 : zlog_err ("fd %d: can't setsockopt SO_SNDBUF to %d: %s",
48 0 : sock, size, safe_strerror (errno));
49 :
50 0 : return ret;
51 : }
52 :
53 : int
54 0 : getsockopt_so_sendbuf (const int sock)
55 : {
56 : u_int32_t optval;
57 0 : socklen_t optlen = sizeof (optval);
58 0 : int ret = getsockopt (sock, SOL_SOCKET, SO_SNDBUF,
59 : (char *)&optval, &optlen);
60 0 : if (ret < 0)
61 : {
62 0 : zlog_err ("fd %d: can't getsockopt SO_SNDBUF: %d (%s)",
63 0 : sock, errno, safe_strerror (errno));
64 0 : return ret;
65 : }
66 0 : return optval;
67 : }
68 :
69 : static void *
70 0 : getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
71 : {
72 : struct cmsghdr *cmsg;
73 0 : void *ptr = NULL;
74 :
75 0 : for (cmsg = ZCMSG_FIRSTHDR(msgh);
76 : cmsg != NULL;
77 0 : cmsg = CMSG_NXTHDR(msgh, cmsg))
78 0 : if (cmsg->cmsg_level == level && cmsg->cmsg_type)
79 0 : return (ptr = CMSG_DATA(cmsg));
80 :
81 0 : return NULL;
82 : }
83 :
84 : #ifdef HAVE_IPV6
85 : /* Set IPv6 packet info to the socket. */
86 : int
87 45 : setsockopt_ipv6_pktinfo (int sock, int val)
88 : {
89 : int ret;
90 :
91 : #ifdef IPV6_RECVPKTINFO /*2292bis-01*/
92 45 : ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
93 45 : if (ret < 0)
94 0 : zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", safe_strerror (errno));
95 : #else /*RFC2292*/
96 : ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
97 : if (ret < 0)
98 : zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", safe_strerror (errno));
99 : #endif /* INIA_IPV6 */
100 45 : return ret;
101 : }
102 :
103 : /* Set multicast hops val to the socket. */
104 : int
105 0 : setsockopt_ipv6_checksum (int sock, int val)
106 : {
107 : int ret;
108 :
109 : #ifdef GNU_LINUX
110 0 : ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
111 : #else
112 : ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
113 : #endif /* GNU_LINUX */
114 0 : if (ret < 0)
115 0 : zlog_warn ("can't setsockopt IPV6_CHECKSUM");
116 0 : return ret;
117 : }
118 :
119 : /* Set multicast hops val to the socket. */
120 : int
121 45 : setsockopt_ipv6_multicast_hops (int sock, int val)
122 : {
123 : int ret;
124 :
125 45 : ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
126 45 : if (ret < 0)
127 0 : zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
128 45 : return ret;
129 : }
130 :
131 : /* Set multicast hops val to the socket. */
132 : int
133 45 : setsockopt_ipv6_unicast_hops (int sock, int val)
134 : {
135 : int ret;
136 :
137 45 : ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
138 45 : if (ret < 0)
139 0 : zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
140 45 : return ret;
141 : }
142 :
143 : int
144 45 : setsockopt_ipv6_hoplimit (int sock, int val)
145 : {
146 : int ret;
147 :
148 : #ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/
149 45 : ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
150 45 : if (ret < 0)
151 0 : zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT");
152 : #else /*RFC2292*/
153 : ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
154 : if (ret < 0)
155 : zlog_warn ("can't setsockopt IPV6_HOPLIMIT");
156 : #endif
157 45 : return ret;
158 : }
159 :
160 : /* Set multicast loop zero to the socket. */
161 : int
162 45 : setsockopt_ipv6_multicast_loop (int sock, int val)
163 : {
164 : int ret;
165 :
166 45 : ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
167 : sizeof (val));
168 45 : if (ret < 0)
169 0 : zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
170 45 : return ret;
171 : }
172 :
173 : static int
174 0 : getsockopt_ipv6_ifindex (struct msghdr *msgh)
175 : {
176 : struct in6_pktinfo *pktinfo;
177 :
178 0 : pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO);
179 :
180 0 : return pktinfo->ipi6_ifindex;
181 : }
182 :
183 : int
184 0 : setsockopt_ipv6_tclass(int sock, int tclass)
185 : {
186 0 : int ret = 0;
187 :
188 : #ifdef IPV6_TCLASS /* RFC3542 */
189 0 : ret = setsockopt (sock, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof (tclass));
190 0 : if (ret < 0)
191 0 : zlog_warn ("Can't set IPV6_TCLASS option for fd %d to %#x: %s",
192 0 : sock, tclass, safe_strerror(errno));
193 : #endif
194 0 : return ret;
195 : }
196 : #endif /* HAVE_IPV6 */
197 :
198 : /*
199 : * Process multicast socket options for IPv4 in an OS-dependent manner.
200 : * Supported options are IP_{ADD,DROP}_MEMBERSHIP.
201 : *
202 : * Many operating systems have a limit on the number of groups that
203 : * can be joined per socket (where each group and local address
204 : * counts). This impacts OSPF, which joins groups on each interface
205 : * using a single socket. The limit is typically 20, derived from the
206 : * original BSD multicast implementation. Some systems have
207 : * mechanisms for increasing this limit.
208 : *
209 : * In many 4.4BSD-derived systems, multicast group operations are not
210 : * allowed on interfaces that are not UP. Thus, a previous attempt to
211 : * leave the group may have failed, leaving it still joined, and we
212 : * drop/join quietly to recover. This may not be necessary, but aims to
213 : * defend against unknown behavior in that we will still return an error
214 : * if the second join fails. It is not clear how other systems
215 : * (e.g. Linux, Solaris) behave when leaving groups on down interfaces,
216 : * but this behavior should not be harmful if they behave the same way,
217 : * allow leaves, or implicitly leave all groups joined to down interfaces.
218 : */
219 : int
220 0 : setsockopt_ipv4_multicast(int sock,
221 : int optname,
222 : unsigned int mcast_addr,
223 : unsigned int ifindex)
224 : {
225 : #ifdef HAVE_RFC3678
226 : struct group_req gr;
227 : struct sockaddr_in *si;
228 : int ret;
229 0 : memset (&gr, 0, sizeof(gr));
230 0 : si = (struct sockaddr_in *)&gr.gr_group;
231 0 : gr.gr_interface = ifindex;
232 0 : si->sin_family = AF_INET;
233 : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
234 : si->sin_len = sizeof(struct sockaddr_in);
235 : #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
236 0 : si->sin_addr.s_addr = mcast_addr;
237 0 : ret = setsockopt(sock, IPPROTO_IP, (optname == IP_ADD_MEMBERSHIP) ?
238 : MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
239 0 : if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
240 : {
241 0 : setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
242 0 : ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr));
243 : }
244 0 : return ret;
245 :
246 : #elif defined(HAVE_STRUCT_IP_MREQN_IMR_IFINDEX) && !defined(__FreeBSD__)
247 : struct ip_mreqn mreqn;
248 : int ret;
249 :
250 : assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
251 : memset (&mreqn, 0, sizeof(mreqn));
252 :
253 : mreqn.imr_multiaddr.s_addr = mcast_addr;
254 : mreqn.imr_ifindex = ifindex;
255 :
256 : ret = setsockopt(sock, IPPROTO_IP, optname,
257 : (void *)&mreqn, sizeof(mreqn));
258 : if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
259 : {
260 : /* see above: handle possible problem when interface comes back up */
261 : char buf[1][INET_ADDRSTRLEN];
262 : zlog_info("setsockopt_ipv4_multicast attempting to drop and "
263 : "re-add (fd %d, mcast %s, ifindex %u)",
264 : sock,
265 : inet_ntop(AF_INET, &mreqn.imr_multiaddr,
266 : buf[0], sizeof(buf[0])), ifindex);
267 : setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
268 : (void *)&mreqn, sizeof(mreqn));
269 : ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
270 : (void *)&mreqn, sizeof(mreqn));
271 : }
272 : return ret;
273 :
274 : /* Example defines for another OS, boilerplate off other code in this
275 : function, AND handle optname as per other sections for consistency !! */
276 : /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
277 : /* Add your favourite OS here! */
278 :
279 : #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */
280 : /* standard BSD API */
281 :
282 : struct in_addr m;
283 : struct ip_mreq mreq;
284 : int ret;
285 :
286 : assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
287 :
288 : m.s_addr = htonl(ifindex);
289 :
290 : memset (&mreq, 0, sizeof(mreq));
291 : mreq.imr_multiaddr.s_addr = mcast_addr;
292 : mreq.imr_interface = m;
293 :
294 : ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq));
295 : if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
296 : {
297 : /* see above: handle possible problem when interface comes back up */
298 : char buf[1][INET_ADDRSTRLEN];
299 : zlog_info("setsockopt_ipv4_multicast attempting to drop and "
300 : "re-add (fd %d, mcast %s, ifindex %u)",
301 : sock,
302 : inet_ntop(AF_INET, &mreq.imr_multiaddr,
303 : buf[0], sizeof(buf[0])), ifindex);
304 : setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
305 : (void *)&mreq, sizeof(mreq));
306 : ret = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
307 : (void *)&mreq, sizeof(mreq));
308 : }
309 : return ret;
310 :
311 : #else
312 : #error "Unsupported multicast API"
313 : #endif /* #if OS_TYPE */
314 :
315 : }
316 :
317 : /*
318 : * Set IP_MULTICAST_IF socket option in an OS-dependent manner.
319 : */
320 : int
321 0 : setsockopt_ipv4_multicast_if(int sock,
322 : unsigned int ifindex)
323 : {
324 :
325 : #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
326 : struct ip_mreqn mreqn;
327 0 : memset (&mreqn, 0, sizeof(mreqn));
328 :
329 0 : mreqn.imr_ifindex = ifindex;
330 0 : return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn));
331 :
332 : /* Example defines for another OS, boilerplate off other code in this
333 : function */
334 : /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
335 : /* Add your favourite OS here! */
336 : #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK)
337 : struct in_addr m;
338 :
339 : m.s_addr = htonl(ifindex);
340 :
341 : return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m));
342 : #else
343 : #error "Unsupported multicast API"
344 : #endif
345 : }
346 :
347 : static int
348 0 : setsockopt_ipv4_ifindex (int sock, int val)
349 : {
350 : int ret;
351 :
352 : #if defined (IP_PKTINFO)
353 0 : if ((ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val))) < 0)
354 0 : zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s",
355 0 : sock,val,safe_strerror(errno));
356 : #elif defined (IP_RECVIF)
357 : if ((ret = setsockopt (sock, IPPROTO_IP, IP_RECVIF, &val, sizeof (val))) < 0)
358 : zlog_warn ("Can't set IP_RECVIF option for fd %d to %d: %s",
359 : sock,val,safe_strerror(errno));
360 : #else
361 : #warning "Neither IP_PKTINFO nor IP_RECVIF is available."
362 : #warning "Will not be able to receive link info."
363 : #warning "Things might be seriously broken.."
364 : /* XXX Does this ever happen? Should there be a zlog_warn message here? */
365 : ret = -1;
366 : #endif
367 0 : return ret;
368 : }
369 :
370 : int
371 0 : setsockopt_ipv4_tos(int sock, int tos)
372 : {
373 : int ret;
374 :
375 0 : ret = setsockopt (sock, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
376 0 : if (ret < 0)
377 0 : zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s",
378 0 : sock, tos, safe_strerror(errno));
379 0 : return ret;
380 : }
381 :
382 :
383 : int
384 0 : setsockopt_ifindex (int af, int sock, int val)
385 : {
386 0 : int ret = -1;
387 :
388 0 : switch (af)
389 : {
390 : case AF_INET:
391 0 : ret = setsockopt_ipv4_ifindex (sock, val);
392 0 : break;
393 : #ifdef HAVE_IPV6
394 : case AF_INET6:
395 0 : ret = setsockopt_ipv6_pktinfo (sock, val);
396 0 : break;
397 : #endif
398 : default:
399 0 : zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
400 : }
401 0 : return ret;
402 : }
403 :
404 : /*
405 : * Requires: msgh is not NULL and points to a valid struct msghdr, which
406 : * may or may not have control data about the incoming interface.
407 : *
408 : * Returns the interface index (small integer >= 1) if it can be
409 : * determined, or else 0.
410 : */
411 : static int
412 0 : getsockopt_ipv4_ifindex (struct msghdr *msgh)
413 : {
414 : /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */
415 0 : int ifindex = -1;
416 :
417 : #if defined(IP_PKTINFO)
418 : /* Linux pktinfo based ifindex retrieval */
419 : struct in_pktinfo *pktinfo;
420 :
421 0 : pktinfo =
422 : (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
423 : /* XXX Can pktinfo be NULL? Clean up post 0.98. */
424 0 : ifindex = pktinfo->ipi_ifindex;
425 :
426 : #elif defined(IP_RECVIF)
427 :
428 : /* retrieval based on IP_RECVIF */
429 :
430 : #ifndef SUNOS_5
431 : /* BSD systems use a sockaddr_dl as the control message payload. */
432 : struct sockaddr_dl *sdl;
433 : #else
434 : /* SUNOS_5 uses an integer with the index. */
435 : int *ifindex_p;
436 : #endif /* SUNOS_5 */
437 :
438 : #ifndef SUNOS_5
439 : /* BSD */
440 : sdl =
441 : (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF);
442 : if (sdl != NULL)
443 : ifindex = sdl->sdl_index;
444 : else
445 : ifindex = 0;
446 : #else
447 : /*
448 : * Solaris. On Solaris 8, IP_RECVIF is defined, but the call to
449 : * enable it fails with errno=99, and the struct msghdr has
450 : * controllen 0.
451 : */
452 : ifindex_p = (uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF);
453 : if (ifindex_p != NULL)
454 : ifindex = *ifindex_p;
455 : else
456 : ifindex = 0;
457 : #endif /* SUNOS_5 */
458 :
459 : #else
460 : /*
461 : * Neither IP_PKTINFO nor IP_RECVIF defined - warn at compile time.
462 : * XXX Decide if this is a core service, or if daemons have to cope.
463 : * Since Solaris 8 and OpenBSD seem not to provide it, it seems that
464 : * daemons have to cope.
465 : */
466 : #warning "getsockopt_ipv4_ifindex: Neither IP_PKTINFO nor IP_RECVIF defined."
467 : #warning "Some daemons may fail to operate correctly!"
468 : ifindex = 0;
469 :
470 : #endif /* IP_PKTINFO */
471 :
472 0 : return ifindex;
473 : }
474 :
475 : /* return ifindex, 0 if none found */
476 : int
477 0 : getsockopt_ifindex (int af, struct msghdr *msgh)
478 : {
479 0 : switch (af)
480 : {
481 : case AF_INET:
482 0 : return (getsockopt_ipv4_ifindex (msgh));
483 : break;
484 : #ifdef HAVE_IPV6
485 : case AF_INET6:
486 0 : return (getsockopt_ipv6_ifindex (msgh));
487 : break;
488 : #endif
489 : default:
490 0 : zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
491 0 : return 0;
492 : }
493 : }
494 :
495 : /* swab iph between order system uses for IP_HDRINCL and host order */
496 : void
497 0 : sockopt_iphdrincl_swab_htosys (struct ip *iph)
498 : {
499 : /* BSD and derived take iph in network order, except for
500 : * ip_len and ip_off
501 : */
502 : #ifndef HAVE_IP_HDRINCL_BSD_ORDER
503 0 : iph->ip_len = htons(iph->ip_len);
504 0 : iph->ip_off = htons(iph->ip_off);
505 : #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
506 :
507 0 : iph->ip_id = htons(iph->ip_id);
508 0 : }
509 :
510 : void
511 0 : sockopt_iphdrincl_swab_systoh (struct ip *iph)
512 : {
513 : #ifndef HAVE_IP_HDRINCL_BSD_ORDER
514 0 : iph->ip_len = ntohs(iph->ip_len);
515 0 : iph->ip_off = ntohs(iph->ip_off);
516 : #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
517 :
518 0 : iph->ip_id = ntohs(iph->ip_id);
519 0 : }
520 :
521 : int
522 0 : sockopt_tcp_signature (int sock, union sockunion *su, const char *password)
523 : {
524 : #if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
525 : /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
526 : * version of the Quagga patch (based on work by Rick Payne, and Bruce
527 : * Simpson)
528 : */
529 : #define TCP_MD5_AUTH 13
530 : #define TCP_MD5_AUTH_ADD 1
531 : #define TCP_MD5_AUTH_DEL 2
532 : struct tcp_rfc2385_cmd {
533 : u_int8_t command; /* Command - Add/Delete */
534 : u_int32_t address; /* IPV4 address associated */
535 : u_int8_t keylen; /* MD5 Key len (do NOT assume 0 terminated ascii) */
536 : void *key; /* MD5 Key */
537 : } cmd;
538 : struct in_addr *addr = &su->sin.sin_addr;
539 :
540 : cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
541 : cmd.address = addr->s_addr;
542 : cmd.keylen = (password != NULL ? strlen (password) : 0);
543 : cmd.key = password;
544 :
545 : return setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd);
546 :
547 : #elif HAVE_DECL_TCP_MD5SIG
548 : int ret;
549 : #ifndef GNU_LINUX
550 : /*
551 : * XXX Need to do PF_KEY operation here to add/remove an SA entry,
552 : * and add/remove an SP entry for this peer's packet flows also.
553 : */
554 : int md5sig = password && *password ? 1 : 0;
555 : #else
556 0 : int keylen = password ? strlen (password) : 0;
557 : struct tcp_md5sig md5sig;
558 : union sockunion *su2, *susock;
559 :
560 : /* Figure out whether the socket and the sockunion are the same family..
561 : * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
562 : */
563 0 : if (!(susock = sockunion_getsockname (sock)))
564 0 : return -1;
565 :
566 0 : if (susock->sa.sa_family == su->sa.sa_family)
567 0 : su2 = su;
568 : else
569 : {
570 : /* oops.. */
571 0 : su2 = susock;
572 :
573 0 : if (su2->sa.sa_family == AF_INET)
574 : {
575 0 : sockunion_free (susock);
576 0 : return 0;
577 : }
578 :
579 : #ifdef HAVE_IPV6
580 : /* If this does not work, then all users of this sockopt will need to
581 : * differentiate between IPv4 and IPv6, and keep seperate sockets for
582 : * each.
583 : *
584 : * Sadly, it doesn't seem to work at present. It's unknown whether
585 : * this is a bug or not.
586 : */
587 0 : if (su2->sa.sa_family == AF_INET6
588 0 : && su->sa.sa_family == AF_INET)
589 : {
590 0 : su2->sin6.sin6_family = AF_INET6;
591 : /* V4Map the address */
592 0 : memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
593 0 : su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
594 0 : memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4);
595 : }
596 : #endif
597 : }
598 :
599 0 : memset (&md5sig, 0, sizeof (md5sig));
600 0 : memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
601 0 : md5sig.tcpm_keylen = keylen;
602 0 : if (keylen)
603 0 : memcpy (md5sig.tcpm_key, password, keylen);
604 0 : sockunion_free (susock);
605 : #endif /* GNU_LINUX */
606 0 : if ((ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0)
607 : {
608 : /* ENOENT is harmless. It is returned when we clear a password for which
609 : one was not previously set. */
610 0 : if (ENOENT == errno)
611 0 : ret = 0;
612 : else
613 0 : zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s",
614 0 : sock, safe_strerror(errno));
615 : }
616 0 : return ret;
617 : #else /* HAVE_TCP_MD5SIG */
618 : return -2;
619 : #endif /* !HAVE_TCP_MD5SIG */
620 : }
|