From c52cf6000923b6a5c6416360d9425061dd19424d Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 5 Nov 2012 17:11:10 +0100 Subject: Use gethostbyname2 instead of getaddrinfo In newer glibc, getaddrinfo issues an extra system call to kernel, which slows down ipset. Replace getaddrinfo with gethostbyname2, where possible. --- lib/parse.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) (limited to 'lib/parse.c') diff --git a/lib/parse.c b/lib/parse.c index af2168e..550048c 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -24,6 +24,7 @@ #include /* ipset_type_get */ #include /* string utilities */ #include /* prototypes */ +#include "../config.h" #ifndef ULLONG_MAX #define ULLONG_MAX 18446744073709551615ULL @@ -679,6 +680,103 @@ ipset_parse_family(struct ipset_session *session, * We resolve hostnames but just the first IP address is used. */ +static void +print_warn(struct ipset_session *session) +{ + if (!ipset_envopt_test(session, IPSET_ENV_QUIET)) + fprintf(stderr, "Warning: %s", + ipset_session_warning(session)); + ipset_session_report_reset(session); +} + +#ifdef HAVE_GETHOSTBYNAME2 +static int +get_hostbyname2(struct ipset_session *session, + enum ipset_opt opt, + const char *str, + int af) +{ + struct hostent *h = gethostbyname2(str, af); + + if (h == NULL) { + syntax_err("cannot parse %s: resolving to %s address failed", + str, af == AF_INET ? "IPv4" : "IPv6"); + return -1; + } + if (h->h_addr_list[1] != NULL) { + ipset_warn(session, + "%s resolves to multiple addresses: " + "using only the first one returned " + "by the resolver.", + str); + print_warn(session); + } + + return ipset_session_data_set(session, opt, h->h_addr_list[0]); +} + +static int +parse_ipaddr(struct ipset_session *session, + enum ipset_opt opt, const char *str, + uint8_t family) +{ + uint8_t m = family == NFPROTO_IPV4 ? 32 : 128; + int af = family == NFPROTO_IPV4 ? AF_INET : AF_INET6; + int err = 0, range = 0; + char *saved = ipset_strdup(session, str); + char *a, *tmp = saved; + enum ipset_opt copt, opt2; + + if (opt == IPSET_OPT_IP) { + copt = IPSET_OPT_CIDR; + opt2 = IPSET_OPT_IP_TO; + } else { + copt = IPSET_OPT_CIDR2; + opt2 = IPSET_OPT_IP2_TO; + } + + if (tmp == NULL) + return -1; + if ((a = cidr_separator(tmp)) != NULL) { + /* IP/mask */ + *a++ = '\0'; + + if ((err = string_to_cidr(session, a, 0, m, &m)) != 0 || + (err = ipset_session_data_set(session, copt, &m)) != 0) + goto out; + } else { + a = find_range_separator(session, tmp); + if (a == tmp) { + err = -1; + goto out; + } + if (a != NULL) { + /* IP-IP */ + *a++ = '\0'; + D("range %s", a); + range++; + } + } + tmp = strip_escape(session, tmp); + if (tmp == NULL) { + err = -1; + goto out; + } + if ((err = get_hostbyname2(session, opt, tmp, af)) != 0 || + !range) + goto out; + a = strip_escape(session, a); + if (a == NULL) { + err = -1; + goto out; + } + err = get_hostbyname2(session, opt2, a, af); + +out: + free(saved); + return err; +} +#else static struct addrinfo * call_getaddrinfo(struct ipset_session *session, const char *str, uint8_t family) @@ -746,8 +844,9 @@ get_addrinfo(struct ipset_session *session, ipset_warn(session, "%s resolves to multiple addresses: " "using only the first one returned " - "by the resolver", + "by the resolver.", str); + print_warn(session); } found++; } @@ -826,6 +925,7 @@ out: free(saved); return err; } +#endif enum ipaddr_type { IPADDR_ANY, -- cgit v1.2.3