sockopt.c 16 KB

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