PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/bind9/lib/isc/unix/net.c

https://bitbucket.org/freebsd/freebsd-head/
C | 524 lines | 418 code | 70 blank | 36 comment | 63 complexity | be39dbb13a407cb2cc7f85e05423c5d9 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  1. /*
  2. * Copyright (C) 2004, 2005, 2007, 2008, 2012 Internet Systems Consortium, Inc. ("ISC")
  3. * Copyright (C) 1999-2003 Internet Software Consortium.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11. * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15. * PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* $Id$ */
  18. #include <config.h>
  19. #include <sys/types.h>
  20. #if defined(HAVE_SYS_SYSCTL_H)
  21. #if defined(HAVE_SYS_PARAM_H)
  22. #include <sys/param.h>
  23. #endif
  24. #include <sys/sysctl.h>
  25. #endif
  26. #include <errno.h>
  27. #include <unistd.h>
  28. #include <isc/log.h>
  29. #include <isc/msgs.h>
  30. #include <isc/net.h>
  31. #include <isc/once.h>
  32. #include <isc/strerror.h>
  33. #include <isc/string.h>
  34. #include <isc/util.h>
  35. /*%
  36. * Definitions about UDP port range specification. This is a total mess of
  37. * portability variants: some use sysctl (but the sysctl names vary), some use
  38. * system-specific interfaces, some have the same interface for IPv4 and IPv6,
  39. * some separate them, etc...
  40. */
  41. /*%
  42. * The last resort defaults: use all non well known port space
  43. */
  44. #ifndef ISC_NET_PORTRANGELOW
  45. #define ISC_NET_PORTRANGELOW 1024
  46. #endif /* ISC_NET_PORTRANGELOW */
  47. #ifndef ISC_NET_PORTRANGEHIGH
  48. #define ISC_NET_PORTRANGEHIGH 65535
  49. #endif /* ISC_NET_PORTRANGEHIGH */
  50. #ifdef HAVE_SYSCTLBYNAME
  51. /*%
  52. * sysctl variants
  53. */
  54. #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
  55. #define USE_SYSCTL_PORTRANGE
  56. #define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
  57. #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
  58. #define SYSCTL_V6PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
  59. #define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
  60. #endif
  61. #ifdef __NetBSD__
  62. #define USE_SYSCTL_PORTRANGE
  63. #define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.anonportmin"
  64. #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
  65. #define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.anonportmin"
  66. #define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax"
  67. #endif
  68. #else /* !HAVE_SYSCTLBYNAME */
  69. #ifdef __OpenBSD__
  70. #define USE_SYSCTL_PORTRANGE
  71. #define SYSCTL_V4PORTRANGE_LOW { CTL_NET, PF_INET, IPPROTO_IP, \
  72. IPCTL_IPPORT_HIFIRSTAUTO }
  73. #define SYSCTL_V4PORTRANGE_HIGH { CTL_NET, PF_INET, IPPROTO_IP, \
  74. IPCTL_IPPORT_HILASTAUTO }
  75. /* Same for IPv6 */
  76. #define SYSCTL_V6PORTRANGE_LOW SYSCTL_V4PORTRANGE_LOW
  77. #define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
  78. #endif
  79. #endif /* HAVE_SYSCTLBYNAME */
  80. #if defined(ISC_PLATFORM_HAVEIPV6)
  81. # if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
  82. const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
  83. # endif
  84. # if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
  85. const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
  86. # endif
  87. # if defined(WANT_IPV6)
  88. static isc_once_t once_ipv6only = ISC_ONCE_INIT;
  89. # endif
  90. # if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
  91. static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
  92. # endif
  93. #endif /* ISC_PLATFORM_HAVEIPV6 */
  94. static isc_once_t once = ISC_ONCE_INIT;
  95. static isc_result_t ipv4_result = ISC_R_NOTFOUND;
  96. static isc_result_t ipv6_result = ISC_R_NOTFOUND;
  97. static isc_result_t unix_result = ISC_R_NOTFOUND;
  98. static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
  99. static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
  100. static isc_result_t
  101. try_proto(int domain) {
  102. int s;
  103. isc_result_t result = ISC_R_SUCCESS;
  104. char strbuf[ISC_STRERRORSIZE];
  105. s = socket(domain, SOCK_STREAM, 0);
  106. if (s == -1) {
  107. switch (errno) {
  108. #ifdef EAFNOSUPPORT
  109. case EAFNOSUPPORT:
  110. #endif
  111. #ifdef EPROTONOSUPPORT
  112. case EPROTONOSUPPORT:
  113. #endif
  114. #ifdef EINVAL
  115. case EINVAL:
  116. #endif
  117. return (ISC_R_NOTFOUND);
  118. default:
  119. isc__strerror(errno, strbuf, sizeof(strbuf));
  120. UNEXPECTED_ERROR(__FILE__, __LINE__,
  121. "socket() %s: %s",
  122. isc_msgcat_get(isc_msgcat,
  123. ISC_MSGSET_GENERAL,
  124. ISC_MSG_FAILED,
  125. "failed"),
  126. strbuf);
  127. return (ISC_R_UNEXPECTED);
  128. }
  129. }
  130. #ifdef ISC_PLATFORM_HAVEIPV6
  131. #ifdef WANT_IPV6
  132. #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
  133. if (domain == PF_INET6) {
  134. struct sockaddr_in6 sin6;
  135. unsigned int len;
  136. /*
  137. * Check to see if IPv6 is broken, as is common on Linux.
  138. */
  139. len = sizeof(sin6);
  140. if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
  141. {
  142. isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
  143. ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
  144. "retrieving the address of an IPv6 "
  145. "socket from the kernel failed.");
  146. isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
  147. ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
  148. "IPv6 is not supported.");
  149. result = ISC_R_NOTFOUND;
  150. } else {
  151. if (len == sizeof(struct sockaddr_in6))
  152. result = ISC_R_SUCCESS;
  153. else {
  154. isc_log_write(isc_lctx,
  155. ISC_LOGCATEGORY_GENERAL,
  156. ISC_LOGMODULE_SOCKET,
  157. ISC_LOG_ERROR,
  158. "IPv6 structures in kernel and "
  159. "user space do not match.");
  160. isc_log_write(isc_lctx,
  161. ISC_LOGCATEGORY_GENERAL,
  162. ISC_LOGMODULE_SOCKET,
  163. ISC_LOG_ERROR,
  164. "IPv6 is not supported.");
  165. result = ISC_R_NOTFOUND;
  166. }
  167. }
  168. }
  169. #endif
  170. #endif
  171. #endif
  172. (void)close(s);
  173. return (result);
  174. }
  175. static void
  176. initialize_action(void) {
  177. ipv4_result = try_proto(PF_INET);
  178. #ifdef ISC_PLATFORM_HAVEIPV6
  179. #ifdef WANT_IPV6
  180. #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
  181. ipv6_result = try_proto(PF_INET6);
  182. #endif
  183. #endif
  184. #endif
  185. #ifdef ISC_PLATFORM_HAVESYSUNH
  186. unix_result = try_proto(PF_UNIX);
  187. #endif
  188. }
  189. static void
  190. initialize(void) {
  191. RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
  192. }
  193. isc_result_t
  194. isc_net_probeipv4(void) {
  195. initialize();
  196. return (ipv4_result);
  197. }
  198. isc_result_t
  199. isc_net_probeipv6(void) {
  200. initialize();
  201. return (ipv6_result);
  202. }
  203. isc_result_t
  204. isc_net_probeunix(void) {
  205. initialize();
  206. return (unix_result);
  207. }
  208. #ifdef ISC_PLATFORM_HAVEIPV6
  209. #ifdef WANT_IPV6
  210. static void
  211. try_ipv6only(void) {
  212. #ifdef IPV6_V6ONLY
  213. int s, on;
  214. char strbuf[ISC_STRERRORSIZE];
  215. #endif
  216. isc_result_t result;
  217. result = isc_net_probeipv6();
  218. if (result != ISC_R_SUCCESS) {
  219. ipv6only_result = result;
  220. return;
  221. }
  222. #ifndef IPV6_V6ONLY
  223. ipv6only_result = ISC_R_NOTFOUND;
  224. return;
  225. #else
  226. /* check for TCP sockets */
  227. s = socket(PF_INET6, SOCK_STREAM, 0);
  228. if (s == -1) {
  229. isc__strerror(errno, strbuf, sizeof(strbuf));
  230. UNEXPECTED_ERROR(__FILE__, __LINE__,
  231. "socket() %s: %s",
  232. isc_msgcat_get(isc_msgcat,
  233. ISC_MSGSET_GENERAL,
  234. ISC_MSG_FAILED,
  235. "failed"),
  236. strbuf);
  237. ipv6only_result = ISC_R_UNEXPECTED;
  238. return;
  239. }
  240. on = 1;
  241. if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
  242. ipv6only_result = ISC_R_NOTFOUND;
  243. goto close;
  244. }
  245. close(s);
  246. /* check for UDP sockets */
  247. s = socket(PF_INET6, SOCK_DGRAM, 0);
  248. if (s == -1) {
  249. isc__strerror(errno, strbuf, sizeof(strbuf));
  250. UNEXPECTED_ERROR(__FILE__, __LINE__,
  251. "socket() %s: %s",
  252. isc_msgcat_get(isc_msgcat,
  253. ISC_MSGSET_GENERAL,
  254. ISC_MSG_FAILED,
  255. "failed"),
  256. strbuf);
  257. ipv6only_result = ISC_R_UNEXPECTED;
  258. return;
  259. }
  260. on = 1;
  261. if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
  262. ipv6only_result = ISC_R_NOTFOUND;
  263. goto close;
  264. }
  265. close(s);
  266. ipv6only_result = ISC_R_SUCCESS;
  267. close:
  268. close(s);
  269. return;
  270. #endif /* IPV6_V6ONLY */
  271. }
  272. static void
  273. initialize_ipv6only(void) {
  274. RUNTIME_CHECK(isc_once_do(&once_ipv6only,
  275. try_ipv6only) == ISC_R_SUCCESS);
  276. }
  277. #endif /* WANT_IPV6 */
  278. #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
  279. static void
  280. try_ipv6pktinfo(void) {
  281. int s, on;
  282. char strbuf[ISC_STRERRORSIZE];
  283. isc_result_t result;
  284. int optname;
  285. result = isc_net_probeipv6();
  286. if (result != ISC_R_SUCCESS) {
  287. ipv6pktinfo_result = result;
  288. return;
  289. }
  290. /* we only use this for UDP sockets */
  291. s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  292. if (s == -1) {
  293. isc__strerror(errno, strbuf, sizeof(strbuf));
  294. UNEXPECTED_ERROR(__FILE__, __LINE__,
  295. "socket() %s: %s",
  296. isc_msgcat_get(isc_msgcat,
  297. ISC_MSGSET_GENERAL,
  298. ISC_MSG_FAILED,
  299. "failed"),
  300. strbuf);
  301. ipv6pktinfo_result = ISC_R_UNEXPECTED;
  302. return;
  303. }
  304. #ifdef IPV6_RECVPKTINFO
  305. optname = IPV6_RECVPKTINFO;
  306. #else
  307. optname = IPV6_PKTINFO;
  308. #endif
  309. on = 1;
  310. if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
  311. ipv6pktinfo_result = ISC_R_NOTFOUND;
  312. goto close;
  313. }
  314. close(s);
  315. ipv6pktinfo_result = ISC_R_SUCCESS;
  316. close:
  317. close(s);
  318. return;
  319. }
  320. static void
  321. initialize_ipv6pktinfo(void) {
  322. RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
  323. try_ipv6pktinfo) == ISC_R_SUCCESS);
  324. }
  325. #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
  326. #endif /* ISC_PLATFORM_HAVEIPV6 */
  327. isc_result_t
  328. isc_net_probe_ipv6only(void) {
  329. #ifdef ISC_PLATFORM_HAVEIPV6
  330. #ifdef WANT_IPV6
  331. initialize_ipv6only();
  332. #else
  333. ipv6only_result = ISC_R_NOTFOUND;
  334. #endif
  335. #endif
  336. return (ipv6only_result);
  337. }
  338. isc_result_t
  339. isc_net_probe_ipv6pktinfo(void) {
  340. #ifdef ISC_PLATFORM_HAVEIPV6
  341. #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
  342. #ifdef WANT_IPV6
  343. initialize_ipv6pktinfo();
  344. #else
  345. ipv6pktinfo_result = ISC_R_NOTFOUND;
  346. #endif
  347. #endif
  348. #endif
  349. return (ipv6pktinfo_result);
  350. }
  351. #if defined(USE_SYSCTL_PORTRANGE)
  352. #if defined(HAVE_SYSCTLBYNAME)
  353. static isc_result_t
  354. getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
  355. int port_low, port_high;
  356. size_t portlen;
  357. const char *sysctlname_lowport, *sysctlname_hiport;
  358. if (af == AF_INET) {
  359. sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
  360. sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
  361. } else {
  362. sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
  363. sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
  364. }
  365. portlen = sizeof(portlen);
  366. if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
  367. NULL, 0) < 0) {
  368. return (ISC_R_FAILURE);
  369. }
  370. portlen = sizeof(portlen);
  371. if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
  372. NULL, 0) < 0) {
  373. return (ISC_R_FAILURE);
  374. }
  375. if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
  376. return (ISC_R_RANGE);
  377. *low = (in_port_t)port_low;
  378. *high = (in_port_t)port_high;
  379. return (ISC_R_SUCCESS);
  380. }
  381. #else /* !HAVE_SYSCTLBYNAME */
  382. static isc_result_t
  383. getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
  384. int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
  385. int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
  386. int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
  387. int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
  388. int *mib_lo, *mib_hi, miblen;
  389. int port_low, port_high;
  390. size_t portlen;
  391. if (af == AF_INET) {
  392. mib_lo = mib_lo4;
  393. mib_hi = mib_hi4;
  394. miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
  395. } else {
  396. mib_lo = mib_lo6;
  397. mib_hi = mib_hi6;
  398. miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
  399. }
  400. portlen = sizeof(portlen);
  401. if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
  402. return (ISC_R_FAILURE);
  403. }
  404. portlen = sizeof(portlen);
  405. if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
  406. return (ISC_R_FAILURE);
  407. }
  408. if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
  409. return (ISC_R_RANGE);
  410. *low = (in_port_t) port_low;
  411. *high = (in_port_t) port_high;
  412. return (ISC_R_SUCCESS);
  413. }
  414. #endif /* HAVE_SYSCTLBYNAME */
  415. #endif /* USE_SYSCTL_PORTRANGE */
  416. isc_result_t
  417. isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
  418. int result = ISC_R_FAILURE;
  419. REQUIRE(low != NULL && high != NULL);
  420. #if defined(USE_SYSCTL_PORTRANGE)
  421. result = getudpportrange_sysctl(af, low, high);
  422. #else
  423. UNUSED(af);
  424. #endif
  425. if (result != ISC_R_SUCCESS) {
  426. *low = ISC_NET_PORTRANGELOW;
  427. *high = ISC_NET_PORTRANGEHIGH;
  428. }
  429. return (ISC_R_SUCCESS); /* we currently never fail in this function */
  430. }
  431. void
  432. isc_net_disableipv4(void) {
  433. initialize();
  434. if (ipv4_result == ISC_R_SUCCESS)
  435. ipv4_result = ISC_R_DISABLED;
  436. }
  437. void
  438. isc_net_disableipv6(void) {
  439. initialize();
  440. if (ipv6_result == ISC_R_SUCCESS)
  441. ipv6_result = ISC_R_DISABLED;
  442. }
  443. void
  444. isc_net_enableipv4(void) {
  445. initialize();
  446. if (ipv4_result == ISC_R_DISABLED)
  447. ipv4_result = ISC_R_SUCCESS;
  448. }
  449. void
  450. isc_net_enableipv6(void) {
  451. initialize();
  452. if (ipv6_result == ISC_R_DISABLED)
  453. ipv6_result = ISC_R_SUCCESS;
  454. }