END_TEST START_TEST (netaddr_set_sockaddr_any_test) { pr_netaddr_t *addr; int res; const char *name; #ifdef PR_USE_IPV6 int family; #endif /* PR_USE_IPV6 */ res = pr_netaddr_set_sockaddr_any(NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); name = "127.0.0.1"; addr = pr_netaddr_get_addr(p, name, NULL); fail_unless(addr != NULL, "Failed to resolve '%s': %s", name, strerror(errno)); res = pr_netaddr_set_sockaddr_any(addr); fail_unless(res == 0, "Failed to set sockaddr any: %s", strerror(errno)); #ifdef PR_USE_IPV6 name = "::1"; addr = pr_netaddr_get_addr(p, name, NULL); fail_unless(addr != NULL, "Failed to resolve '%s': %s", name, strerror(errno)); res = pr_netaddr_set_sockaddr_any(addr); fail_unless(res == 0, "Failed to set sockaddr any: %s", strerror(errno)); pr_netaddr_disable_ipv6(); res = pr_netaddr_set_sockaddr_any(addr); fail_unless(res < 0, "Set sockaddr any unexpectedly"); fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM, strerror(errno), errno); pr_netaddr_enable_ipv6(); family = addr->na_family; addr->na_family = 777; res = pr_netaddr_set_sockaddr_any(addr); addr->na_family = family; fail_unless(res < 0, "Set sockaddr any unexpectedly"); fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM, strerror(errno), errno); #endif /* PR_USE_IPV6 */ }
pr_namebind_t *pr_namebind_find(const char *name, pr_netaddr_t *addr, unsigned int port, unsigned char skip_inactive) { pr_ipbind_t *ipbind = NULL; pr_namebind_t *namebind = NULL; if (name == NULL || addr == NULL) { errno = EINVAL; return NULL; } /* First, find an active ipbind for the given addr/port */ ipbind = pr_ipbind_find(addr, port, skip_inactive); if (ipbind == NULL) { pr_netaddr_t wildcard_addr; int addr_family; /* If not found, look for the wildcard address. */ addr_family = pr_netaddr_get_family(addr); pr_netaddr_clear(&wildcard_addr); pr_netaddr_set_family(&wildcard_addr, addr_family); pr_netaddr_set_sockaddr_any(&wildcard_addr); ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); #ifdef PR_USE_IPV6 if (ipbind == FALSE && addr_family == AF_INET6 && pr_netaddr_use_ipv6()) { /* No IPv6 wildcard address found; try the IPv4 wildcard address. */ pr_netaddr_clear(&wildcard_addr); pr_netaddr_set_family(&wildcard_addr, AF_INET); pr_netaddr_set_sockaddr_any(&wildcard_addr); ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); } #endif /* PR_USE_IPV6 */ } if (ipbind == NULL) { errno = ENOENT; return NULL; } if (!ipbind->ib_namebinds) { return NULL; } else { register unsigned int i = 0; pr_namebind_t **namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; for (i = 0; i < ipbind->ib_namebinds->nelts; i++) { namebind = namebinds[i]; /* Skip inactive namebinds */ if (skip_inactive == TRUE && namebind != NULL && namebind->nb_isactive == FALSE) { continue; } /* At present, this looks for an exactly matching name. In the future, * we may want to have something like Apache's matching scheme, which * looks for the most specific domain to the most general. Note that * that scheme, however, is specific to DNS; should any other naming * scheme be desired, that sort of matching will be unnecessary. */ if (namebind != NULL && namebind->nb_name != NULL) { if (namebind->nb_iswildcard == FALSE) { if (strcasecmp(namebind->nb_name, name) == 0) return namebind; } } else { int match_flags = PR_FNM_NOESCAPE|PR_FNM_CASEFOLD; if (pr_fnmatch(namebind->nb_name, name, match_flags) == 0) { pr_trace_msg(trace_channel, 9, "matched name '%s' against pattern '%s'", name, namebind->nb_name); return namebind; } pr_trace_msg(trace_channel, 9, "failed to match name '%s' against pattern '%s'", name, namebind->nb_name); } } } return NULL; }
int pr_namebind_create(server_rec *server, const char *name, pr_netaddr_t *addr, unsigned int port) { pr_ipbind_t *ipbind = NULL; pr_namebind_t *namebind = NULL, **namebinds = NULL; if (server == NULL || name == NULL) { errno = EINVAL; return -1; } /* First, find the ipbind to hold this namebind. */ ipbind = pr_ipbind_find(addr, port, FALSE); if (ipbind == NULL) { pr_netaddr_t wildcard_addr; int addr_family; /* If not found, look for the wildcard address. */ addr_family = pr_netaddr_get_family(addr); pr_netaddr_clear(&wildcard_addr); pr_netaddr_set_family(&wildcard_addr, addr_family); pr_netaddr_set_sockaddr_any(&wildcard_addr); ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); #ifdef PR_USE_IPV6 if (ipbind == FALSE && addr_family == AF_INET6 && pr_netaddr_use_ipv6()) { /* No IPv6 wildcard address found; try the IPv4 wildcard address. */ pr_netaddr_clear(&wildcard_addr); pr_netaddr_set_family(&wildcard_addr, AF_INET); pr_netaddr_set_sockaddr_any(&wildcard_addr); ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); } #endif /* PR_USE_IPV6 */ } if (ipbind == NULL) { errno = ENOENT; return -1; } /* Make sure we can add this namebind. */ if (!ipbind->ib_namebinds) { ipbind->ib_namebinds = make_array(binding_pool, 0, sizeof(pr_namebind_t *)); } else { register unsigned int i = 0; namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; /* See if there is already a namebind for the given name. */ for (i = 0; i < ipbind->ib_namebinds->nelts; i++) { namebind = namebinds[i]; if (namebind != NULL && namebind->nb_name != NULL) { /* DNS names are case-insensitive, hence the case-insensitive check * here. * * XXX Ideally, we should check whether any existing namebinds which * are globs will match the newly added namebind as well. */ if (strcasecmp(namebind->nb_name, name) == 0) { errno = EEXIST; return -1; } } } } namebind = (pr_namebind_t *) pcalloc(server->pool, sizeof(pr_namebind_t)); namebind->nb_name = name; namebind->nb_server = server; namebind->nb_isactive = FALSE; if (pr_str_is_fnmatch(name) == TRUE) { namebind->nb_iswildcard = TRUE; } pr_trace_msg(trace_channel, 8, "created named binding '%s' for %s#%u, server %p", name, pr_netaddr_get_ipstr(server->addr), server->ServerPort, server->ServerName); /* The given server should already have the following populated: * * server->ServerName * server->ServerAddress * server->ServerFQDN */ /* These TCP socket tweaks will not apply to the control connection (it will * already have been established by the time this named vhost is used), * but WILL apply to any data connections established to this named vhost. */ #if 0 namebind->nb_server->tcp_mss_len = (server->tcp_mss_len ? server->tcp_mss_len : main_server->tcp_mss_len); namebind->nb_server->tcp_rcvbuf_len = (server->tcp_rcvbuf_len ? server->tcp_rcvbuf_len : main_server->tcp_rcvbuf_len); namebind->nb_server->tcp_rcvbuf_override = (server->tcp_rcvbuf_override ? TRUE : main_server->tcp_rcvbuf_override); namebind->nb_server->tcp_sndbuf_len = (server->tcp_sndbuf_len ? server->tcp_sndbuf_len : main_server->tcp_sndbuf_len); namebind->nb_server->tcp_sndbuf_override = (server->tcp_sndbuf_override ? TRUE : main_server->tcp_sndbuf_override); /* XXX Shouldn't need these; the ipbind container handles all of the * connection (listener, port, addr) stuff. */ namebind->nb_server->addr = (server->addr ? server->addr : main_server->addr); namebind->nb_server->ServerPort = (server->ServerPort ? server->ServerPort : main_server->ServerPort); namebind->nb_listener = (server->listen ? server->listen : main_server->listen); #endif *((pr_namebind_t **) push_array(ipbind->ib_namebinds)) = namebind; return 0; }
server_rec *pr_ipbind_get_server(pr_netaddr_t *addr, unsigned int port) { pr_ipbind_t *ipbind = NULL; pr_netaddr_t wildcard_addr; int addr_family; /* If we've got a binding configured for this exact address, return it * straightaway. */ ipbind = pr_ipbind_find(addr, port, TRUE); if (ipbind != NULL) return ipbind->ib_server; /* Look for a vhost bound to the wildcard address (i.e. INADDR_ANY). * * This allows for "<VirtualHost 0.0.0.0>" configurations, where the * IP address to which the client might connect is not known at * configuration time. (Usually happens when the same config file * is deployed to multiple machines.) */ addr_family = pr_netaddr_get_family(addr); pr_netaddr_clear(&wildcard_addr); pr_netaddr_set_family(&wildcard_addr, addr_family); pr_netaddr_set_sockaddr_any(&wildcard_addr); ipbind = pr_ipbind_find(&wildcard_addr, port, TRUE); if (ipbind != NULL) { pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using " "'%s' listening on wildcard address", pr_netaddr_get_ipstr(addr), port, ipbind->ib_server->ServerName); return ipbind->ib_server; } else { #ifdef PR_USE_IPV6 if (addr_family == AF_INET6 && pr_netaddr_use_ipv6()) { /* The pr_ipbind_find() probably returned NULL because there aren't * any <VirtualHost> sections configured explicitly for the wildcard * IPv6 address of "::", just the IPv4 wildcard "0.0.0.0" address. * * So try the pr_ipbind_find() again, this time using the IPv4 wildcard. */ pr_netaddr_clear(&wildcard_addr); pr_netaddr_set_family(&wildcard_addr, AF_INET); pr_netaddr_set_sockaddr_any(&wildcard_addr); ipbind = pr_ipbind_find(&wildcard_addr, port, TRUE); if (ipbind != NULL) { pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using " "'%s' listening on wildcard address", pr_netaddr_get_ipstr(addr), port, ipbind->ib_server->ServerName); return ipbind->ib_server; } } #endif /* PR_USE_IPV6 */ } /* Use the default server, if set. */ if (ipbind_default_server && ipbind_default_server->ib_isactive) { pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using " "DefaultServer '%s'", pr_netaddr_get_ipstr(addr), port, ipbind_default_server->ib_server->ServerName); return ipbind_default_server->ib_server; } /* Not found in binding list, and no DefaultServer, so see if it's the * loopback address */ if (ipbind_localhost_server && pr_netaddr_is_loopback(addr)) { return ipbind_localhost_server->ib_server; } return NULL; }