📄 sockaddr.c
字号:
/* AIX, HP/UX, D/UX et alia */ gethostbyname_r(hostname, &hs, &hd); hp = &hs;#else#if defined(GETHOSTBYNAME_R_GLIBC2) /* Linux glibc2+ */ gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hp, &hosterror);#else /* Solaris, Irix et alia */ hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hosterror);#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ if (!hp) { return (hosterror + APR_OS_START_SYSERR); }#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */#else hp = gethostbyname(hostname);#endif if (!hp) {#ifdef WIN32 return apr_get_netos_error();#else return (h_errno + APR_OS_START_SYSERR);#endif } } prev_sa = NULL; curaddr = 0; while (hp->h_addr_list[curaddr]) { apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); new_sa->pool = p; new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr]; apr_sockaddr_vars_set(new_sa, AF_INET, port); if (!prev_sa) { /* first element in new list */ if (orig_hostname) { new_sa->hostname = apr_pstrdup(p, orig_hostname); } *sa = new_sa; } else { new_sa->hostname = prev_sa->hostname; prev_sa->next = new_sa; } prev_sa = new_sa; ++curaddr; } return APR_SUCCESS;}#endif /* end of !HAVE_GETADDRINFO code */APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, const char *hostname, apr_int32_t family, apr_port_t port, apr_int32_t flags, apr_pool_t *p){ apr_int32_t masked; *sa = NULL; if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) { if (!hostname || family != AF_UNSPEC || masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) { return APR_EINVAL; }#if !APR_HAVE_IPV6 if (flags & APR_IPV6_ADDR_OK) { return APR_ENOTIMPL; }#endif }#if !APR_HAVE_IPV6 /* What may happen is that APR is not IPv6-enabled, but we're still * going to call getaddrinfo(), so we have to tell the OS we only * want IPv4 addresses back since we won't know what to do with * IPv6 addresses. */ if (family == APR_UNSPEC) { family = APR_INET; }#endif return find_addresses(sa, hostname, family, port, flags, p);}APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, apr_sockaddr_t *sockaddr, apr_int32_t flags){#if defined(HAVE_GETNAMEINFO) int rc;#if defined(NI_MAXHOST) char tmphostname[NI_MAXHOST];#else char tmphostname[256];#endif /* don't know if it is portable for getnameinfo() to set h_errno; * clear it then see if it was set */ SET_H_ERRNO(0); /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return * a numeric address string if it fails to resolve the host name; * that is *not* what we want here * * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc). */#if APR_HAVE_IPV6 if (sockaddr->family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) { struct sockaddr_in tmpsa; tmpsa.sin_family = AF_INET; tmpsa.sin_port = 0; tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];#ifdef SIN6_LEN tmpsa.sin_len = sizeof(tmpsa);#endif rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa), tmphostname, sizeof(tmphostname), NULL, 0, flags != 0 ? flags : NI_NAMEREQD); } else#endif rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen, tmphostname, sizeof(tmphostname), NULL, 0, flags != 0 ? flags : NI_NAMEREQD); if (rc != 0) { *hostname = NULL;#ifndef WIN32 /* something went wrong. Look at the EAI_ error code */ if (rc == EAI_SYSTEM) { /* EAI_SYSTEM System error returned in errno. */ /* IMHO, Implementations that set h_errno a simply broken. */ if (h_errno) { /* for broken implementations which set h_errno */ return h_errno + APR_OS_START_SYSERR; } else { /* "normal" case */ return errno + APR_OS_START_SYSERR; } } else #endif {#if defined(NEGATIVE_EAI) if (rc < 0) rc = -rc;#endif return rc + APR_OS_START_EAIERR; /* return the EAI_ error */ } } *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, tmphostname); return APR_SUCCESS;#else#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \ defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS)#ifdef GETHOSTBYNAME_R_HOSTENT_DATA struct hostent_data hd;#else char tmp[GETHOSTBYNAME_BUFLEN];#endif int hosterror; struct hostent hs, *hptr;#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) /* AIX, HP/UX, D/UX et alia */ gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, sizeof(struct in_addr), AF_INET, &hs, &hd); hptr = &hs;#else#if defined(GETHOSTBYNAME_R_GLIBC2) /* Linux glibc2+ */ gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, sizeof(struct in_addr), AF_INET, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror);#else /* Solaris, Irix et alia */ hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, sizeof(struct in_addr), AF_INET, &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror);#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ if (!hptr) { *hostname = NULL; return hosterror + APR_OS_START_SYSERR; }#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */#else struct hostent *hptr; hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, sizeof(struct in_addr), AF_INET);#endif if (hptr) { *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name); return APR_SUCCESS; } *hostname = NULL;#if defined(WIN32) return apr_get_netos_error();#elif defined(OS2) return h_errno;#else return h_errno + APR_OS_START_SYSERR;#endif#endif}APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, const char *servname){ struct servent *se; if (servname == NULL) return APR_EINVAL; if ((se = getservbyname(servname, NULL)) != NULL){ sockaddr->port = htons(se->s_port); sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); sockaddr->sa.sin.sin_port = se->s_port; return APR_SUCCESS; } return errno;}#define V4MAPPED_EQUAL(a,b) \((a)->sa.sin.sin_family == AF_INET && \ (b)->sa.sin.sin_family == AF_INET6 && \ IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) && \ !memcmp((a)->ipaddr_ptr, \ &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12], \ (a)->ipaddr_len))APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, const apr_sockaddr_t *addr2){ if (addr1->ipaddr_len == addr2->ipaddr_len && !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len)) { return 1; }#if APR_HAVE_IPV6 if (V4MAPPED_EQUAL(addr1, addr2)) { return 1; } if (V4MAPPED_EQUAL(addr2, addr1)) { return 1; }#endif return 0; /* not equal */}static apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network){ /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */ int shift; char *s, *t; int octet; char buf[sizeof "255.255.255.255"]; if (strlen(network) < sizeof buf) { strcpy(buf, network); } else { return APR_EBADIP; } /* parse components */ s = buf; ipsub->sub[0] = 0; ipsub->mask[0] = 0; shift = 24; while (*s) { t = s; if (!apr_isdigit(*t)) { return APR_EBADIP; } while (apr_isdigit(*t)) { ++t; } if (*t == '.') { *t++ = 0; } else if (*t) { return APR_EBADIP; } if (shift < 0) { return APR_EBADIP; } octet = atoi(s); if (octet < 0 || octet > 255) { return APR_EBADIP; } ipsub->sub[0] |= octet << shift; ipsub->mask[0] |= 0xFFUL << shift; s = t; shift -= 8; } ipsub->sub[0] = ntohl(ipsub->sub[0]); ipsub->mask[0] = ntohl(ipsub->mask[0]); ipsub->family = AF_INET; return APR_SUCCESS;}/* return values: * APR_EINVAL not an IP address; caller should see if it is something else * APR_BADIP IP address portion is is not valid * APR_BADMASK mask portion is not valid */static apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed){ /* supported flavors of IP: * * . IPv6 numeric address string (e.g., "fe80::1") * * IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address. * * . IPv4 numeric address string (e.g., "127.0.0.1") * * . IPv4 network string (e.g., "9.67") * * IMPORTANT: This network form is only allowed if network_allowed is on. */ int rc;#if APR_HAVE_IPV6 rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub); if (rc == 1) { if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) { /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6 * addresses; this of course forces the user to specify IPv4 addresses * in a.b.c.d style instead of ::ffff:a.b.c.d style. */ return APR_EBADIP; } ipsub->family = AF_INET6; } else#endif { rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub); if (rc == 1) { ipsub->family = AF_INET; } } if (rc != 1) { if (network_allowed) { return parse_network(ipsub, ipstr); } else { return APR_EBADIP; } } return APR_SUCCESS;}static int looks_like_ip(const char *ipstr){ if (strchr(ipstr, ':')) { /* definitely not a hostname; assume it is intended to be an IPv6 address */ return 1; } /* simple IPv4 address string check */ while ((*ipstr == '.') || apr_isdigit(*ipstr)) ipstr++; return (*ipstr == '\0');}static void fix_subnet(apr_ipsubnet_t *ipsub){ /* in case caller specified more bits in network address than are * valid according to the mask, turn off the extra bits */ int i; for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) { ipsub->sub[i] &= ipsub->mask[i]; }}/* be sure not to store any IPv4 address as a v4-mapped IPv6 address */APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr, const char *mask_or_numbits, apr_pool_t *p){ apr_status_t rv; char *endptr; long bits, maxbits = 32; /* filter out stuff which doesn't look remotely like an IP address; this helps * callers like mod_access which have a syntax allowing hostname or IP address; * APR_EINVAL tells the caller that it was probably not intended to be an IP * address */ if (!looks_like_ip(ipstr)) { return APR_EINVAL; } *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t)); /* assume ipstr is an individual IP address, not a subnet */ memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask); rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL); if (rv != APR_SUCCESS) { return rv; } if (mask_or_numbits) {#if APR_HAVE_IPV6 if ((*ipsub)->family == AF_INET6) { maxbits = 128; }#endif bits = strtol(mask_or_numbits, &endptr, 10); if (*endptr == '\0' && bits > 0 && bits <= maxbits) { /* valid num-bits string; fill in mask appropriately */ int cur_entry = 0; apr_int32_t cur_bit_value; memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask); while (bits > 32) { (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */ bits -= 32; ++cur_entry; } cur_bit_value = 0x80000000; while (bits) { (*ipsub)->mask[cur_entry] |= cur_bit_value; --bits; cur_bit_value /= 2; } (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]); } else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 && (*ipsub)->family == AF_INET) { /* valid IPv4 netmask */ } else { return APR_EBADMASK; } } fix_subnet(*ipsub); return APR_SUCCESS;}APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa){#if APR_HAVE_IPV6 /* XXX This line will segv on Win32 build with APR_HAVE_IPV6, * but without the IPV6 drivers installed. */ if (sa->sa.sin.sin_family == AF_INET) { if (ipsub->family == AF_INET && ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) { return 1; } } else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) { if (ipsub->family == AF_INET && (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) { return 1; } } else { apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr; if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] && (addr[1] & ipsub->mask[1]) == ipsub->sub[1] && (addr[2] & ipsub->mask[2]) == ipsub->sub[2] && (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) { return 1; } }#else if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) { return 1; }#endif /* APR_HAVE_IPV6 */ return 0; /* no match */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -