summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/parse.c170
-rw-r--r--lib/print.c28
2 files changed, 153 insertions, 45 deletions
diff --git a/lib/parse.c b/lib/parse.c
index 0ee34c3..30efdb6 100644
--- a/lib/parse.c
+++ b/lib/parse.c
@@ -59,6 +59,20 @@ ipset_strchr(const char *str, const char *sep)
return NULL;
}
+static char *
+escape_range_separator(const char *str)
+{
+ const char *tmp = NULL;
+
+ if (STRNEQ(str, IPSET_ESCAPE_START, 1)) {
+ tmp = strstr(str, IPSET_ESCAPE_END);
+ if (tmp == NULL)
+ return NULL;
+ }
+
+ return range_separator(tmp == NULL ? str : tmp);
+}
+
/*
* Parser functions, shamelessly taken from iptables.c, ip6tables.c
* and parser.c from libnetfilter_conntrack.
@@ -194,6 +208,60 @@ error:
return syntax_err("cannot parse '%s' as ethernet address", str);
}
+static char *
+ipset_strdup(struct ipset_session *session, const char *str)
+{
+ char *tmp = strdup(str);
+
+ if (tmp == NULL)
+ ipset_err(session,
+ "Cannot allocate memory to duplicate %s.",
+ str);
+ return tmp;
+}
+
+static char *
+find_range_separator(struct ipset_session *session, char *str)
+{
+ char *esc;
+
+ if (STRNEQ(str, IPSET_ESCAPE_START, 1)) {
+ esc = strstr(str, IPSET_ESCAPE_END);
+ if (esc == NULL) {
+ syntax_err("cannot find closing escape character "
+ "'%s' in %s", IPSET_ESCAPE_END, str);
+ return str;
+ }
+ if (esc[1] == '\0')
+ /* No range separator, just a single escaped elem */
+ return NULL;
+ esc++;
+ if (!STRNEQ(esc, IPSET_RANGE_SEPARATOR, 1)) {
+ *esc = '\0';
+ syntax_err("range separator expected after "
+ "'%s'", str);
+ return str;
+ }
+ return esc;
+ }
+ return range_separator(str);
+}
+
+static char *
+strip_escape(struct ipset_session *session, char * str)
+{
+ if (STRNEQ(str, IPSET_ESCAPE_START, 1)) {
+ if (!STREQ(str + strlen(str) - 1, IPSET_ESCAPE_END)) {
+ syntax_err("cannot find closing escape character "
+ "'%s' in %s", IPSET_ESCAPE_END, str);
+ return NULL;
+ }
+ str++;
+ str[strlen(str) - 1] = '\0';
+ }
+ return str;
+}
+
/*
* Parse TCP service names or port numbers
*/
@@ -201,13 +269,25 @@ static int
parse_portname(struct ipset_session *session, const char *str,
uint16_t *port, const char *proto)
{
- struct servent *service = getservbyname(str, proto);
+ char *saved, *tmp;
+ struct servent *service;
+ saved = tmp = ipset_strdup(session, str);
+ if (tmp == NULL)
+ return -1;
+ tmp = strip_escape(session, tmp);
+ if (tmp == NULL)
+ goto error;
+
+ service = getservbyname(tmp, proto);
if (service != NULL) {
*port = ntohs((uint16_t) service->s_port);
+ free(saved);
return 0;
}
+error:
+ free(saved);
return syntax_err("cannot parse '%s' as a %s port", str, proto);
}
@@ -270,13 +350,16 @@ ipset_parse_tcpudp_port(struct ipset_session *session,
assert(opt == IPSET_OPT_PORT);
assert(str);
- saved = tmp = strdup(str);
+ saved = tmp = ipset_strdup(session, str);
if (tmp == NULL)
- return ipset_err(session,
- "Cannot allocate memory to duplicate %s.",
- str);
+ return -1;
+
+ a = find_range_separator(session, tmp);
+ if (a == tmp) {
+ err = -1;
+ goto error;
+ }
- a = range_separator(tmp);
if (a != NULL) {
/* port-port */
*a++ = '\0';
@@ -378,11 +461,9 @@ parse_icmp_typecode(struct ipset_session *session,
char *a, *saved, *tmp;
int err;
- saved = tmp = strdup(str);
+ saved = tmp = ipset_strdup(session, str);
if (tmp == NULL)
- return ipset_err(session,
- "Cannot allocate memory to duplicate %s.",
- str);
+ return -1;
a = cidr_separator(tmp);
if (a == NULL) {
free(saved);
@@ -485,11 +566,9 @@ ipset_parse_proto_port(struct ipset_session *session,
assert(str);
data = ipset_session_data(session);
- saved = tmp = strdup(str);
+ saved = tmp = ipset_strdup(session, str);
if (tmp == NULL)
- return ipset_err(session,
- "Cannot allocate memory to duplicate %s.",
- str);
+ return -1;
a = proto_separator(tmp);
if (a != NULL) {
@@ -536,7 +615,7 @@ ipset_parse_proto_port(struct ipset_session *session,
}
goto error;
} else {
- proto = "TCP";
+ proto = "tcp";
err = ipset_data_set(data, IPSET_OPT_PROTO, &p);
if (err)
goto error;
@@ -679,7 +758,7 @@ parse_ipaddr(struct ipset_session *session,
{
uint8_t m = family == NFPROTO_IPV4 ? 32 : 128;
int aerr = EINVAL, err = 0, range = 0;
- char *saved = strdup(str);
+ char *saved = ipset_strdup(session, str);
char *a, *tmp = saved;
struct addrinfo *info;
enum ipset_opt copt, opt2;
@@ -693,9 +772,7 @@ parse_ipaddr(struct ipset_session *session,
}
if (tmp == NULL)
- return ipset_err(session,
- "Cannot allocate memory to duplicate %s.",
- str);
+ return -1;
if ((a = cidr_separator(tmp)) != NULL) {
/* IP/mask */
*a++ = '\0';
@@ -703,16 +780,33 @@ parse_ipaddr(struct ipset_session *session,
if ((err = string_to_cidr(session, a, 0, m, &m)) != 0 ||
(err = ipset_session_data_set(session, copt, &m)) != 0)
goto out;
- } else if ((a = range_separator(tmp)) != NULL) {
- /* IP-IP */
- *a++ = '\0';
- D("range %s", a);
- range++;
+ } 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 ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0 ||
!range)
goto out;
freeaddrinfo(info);
+ a = strip_escape(session, a);
+ if (a == NULL) {
+ err = -1;
+ goto out;
+ }
aerr = get_addrinfo(session, opt2, a, &info, family);
out:
@@ -754,18 +848,18 @@ parse_ip(struct ipset_session *session,
switch (addrtype) {
case IPADDR_PLAIN:
- if (range_separator(str) ||
+ if (escape_range_separator(str) ||
(cidr_separator(str) && !cidr_hostaddr(str, family)))
return syntax_err("plain IP address must be supplied: "
"%s", str);
break;
case IPADDR_NET:
- if (!cidr_separator(str) || range_separator(str))
+ if (!cidr_separator(str) || escape_range_separator(str))
return syntax_err("IP/netblock must be supplied: %s",
str);
break;
case IPADDR_RANGE:
- if (!range_separator(str) || cidr_separator(str))
+ if (!escape_range_separator(str) || cidr_separator(str))
return syntax_err("IP-IP range must supplied: %s",
str);
break;
@@ -896,7 +990,7 @@ ipset_parse_netrange(struct ipset_session *session,
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
assert(str);
- if (!(range_separator(str) || cidr_separator(str)))
+ if (!(escape_range_separator(str) || cidr_separator(str)))
return syntax_err("IP/cidr or IP-IP range must be specified: "
"%s", str);
return parse_ip(session, opt, str, IPADDR_ANY);
@@ -949,7 +1043,7 @@ ipset_parse_ipnet(struct ipset_session *session,
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
assert(str);
- if (range_separator(str))
+ if (escape_range_separator(str))
return syntax_err("IP address or IP/cidr must be specified: %s",
str);
return parse_ip(session, opt, str, IPADDR_ANY);
@@ -1065,11 +1159,9 @@ ipset_parse_iptimeout(struct ipset_session *session,
IPSET_FLAG(IPSET_OPT_TIMEOUT)))
return syntax_err("mixed syntax, timeout already specified");
- tmp = saved = strdup(str);
+ tmp = saved = ipset_strdup(session, str);
if (saved == NULL)
- return ipset_err(session,
- "Cannot allocate memory to duplicate %s.",
- str);
+ return 1;
a = elem_separator(tmp);
if (a == NULL) {
@@ -1127,11 +1219,9 @@ ipset_parse_name_compat(struct ipset_session *session,
if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF)))
syntax_err("mixed syntax, before|after option already used");
- tmp = saved = strdup(str);
+ tmp = saved = ipset_strdup(session, str);
if (saved == NULL)
- return ipset_err(session,
- "Cannot allocate memory to duplicate %s.",
- str);
+ return -1;
if ((a = elem_separator(tmp)) != NULL) {
/* setname,[before|after,setname */
*a++ = '\0';
@@ -1565,11 +1655,9 @@ ipset_parse_elem(struct ipset_session *session,
return ipset_err(session,
"Internal error: set type is unknown!");
- saved = tmp = strdup(str);
+ saved = tmp = ipset_strdup(session, str);
if (tmp == NULL)
- return ipset_err(session,
- "Cannot allocate memory to duplicate %s.",
- str);
+ return -1;
a = elem_separator(tmp);
if (type->dimension > IPSET_DIM_ONE) {
diff --git a/lib/print.c b/lib/print.c
index 662baae..f2f848b 100644
--- a/lib/print.c
+++ b/lib/print.c
@@ -158,13 +158,23 @@ __getnameinfo4(char *buf, unsigned int len,
sizeof(saddr),
buf, len, NULL, 0, flags);
- if (!(flags & NI_NUMERICHOST) &&
- (err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL)))
+ if (!(flags & NI_NUMERICHOST) && (err == EAI_AGAIN))
err = getnameinfo((const struct sockaddr *)&saddr,
sizeof(saddr),
buf, len, NULL, 0,
flags | NI_NUMERICHOST);
D("getnameinfo err: %i, errno %i", err, errno);
+ if (err == 0 && strstr(buf, IPSET_RANGE_SEPARATOR) != NULL) {
+ const char escape[] = IPSET_ESCAPE_START;
+ /* Escape hostname */
+ if (strlen(buf) + 2 > len) {
+ err = EAI_OVERFLOW;
+ return -1;
+ }
+ memmove(buf + 1, buf, strlen(buf) + 1);
+ buf[0] = escape[0];
+ strcat(buf, IPSET_ESCAPE_END);
+ }
return (err == 0 ? (int)strlen(buf) :
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);
}
@@ -184,13 +194,23 @@ __getnameinfo6(char *buf, unsigned int len,
sizeof(saddr),
buf, len, NULL, 0, flags);
- if (!(flags & NI_NUMERICHOST) &&
- (err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL)))
+ if (!(flags & NI_NUMERICHOST) && (err == EAI_AGAIN))
err = getnameinfo((const struct sockaddr *)&saddr,
sizeof(saddr),
buf, len, NULL, 0,
flags | NI_NUMERICHOST);
D("getnameinfo err: %i, errno %i", err, errno);
+ if (err == 0 && strstr(buf, IPSET_RANGE_SEPARATOR) != NULL) {
+ const char escape[] = IPSET_ESCAPE_START;
+ /* Escape hostname */
+ if (strlen(buf) + 2 > len) {
+ err = EAI_OVERFLOW;
+ return -1;
+ }
+ memmove(buf + 1, buf, strlen(buf) + 1);
+ buf[0] = escape[0];
+ strcat(buf, IPSET_ESCAPE_END);
+ }
return (err == 0 ? (int)strlen(buf) :
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);
}