summaryrefslogtreecommitdiffstats
path: root/lib/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/parse.c')
-rw-r--r--lib/parse.c121
1 files changed, 93 insertions, 28 deletions
diff --git a/lib/parse.c b/lib/parse.c
index 31a619d..4d2d8b3 100644
--- a/lib/parse.c
+++ b/lib/parse.c
@@ -41,6 +41,9 @@
#define syntax_err(fmt, args...) \
ipset_err(session, "Syntax error: " fmt , ## args)
+#define syntax_err_ll(errtype, fmt, args...) \
+ ipset_session_report(session, errtype, "Syntax error: " fmt , ## args)
+
static char *
ipset_strchr(const char *str, const char *sep)
{
@@ -87,7 +90,8 @@ string_to_number_ll(struct ipset_session *session,
const char *str,
unsigned long long min,
unsigned long long max,
- unsigned long long *ret)
+ unsigned long long *ret,
+ enum ipset_err_type errtype)
{
unsigned long long number = 0;
char *end;
@@ -104,23 +108,24 @@ string_to_number_ll(struct ipset_session *session,
errno = ERANGE;
}
if (errno == ERANGE && max)
- return syntax_err("'%s' is out of range %llu-%llu",
- str, min, max);
+ return syntax_err_ll(errtype, "'%s' is out of range %llu-%llu",
+ str, min, max);
else if (errno == ERANGE)
- return syntax_err("'%s' is out of range %llu-%llu",
- str, min, ULLONG_MAX);
+ return syntax_err_ll(errtype, "'%s' is out of range %llu-%llu",
+ str, min, ULLONG_MAX);
else
- return syntax_err("'%s' is invalid as number", str);
+ return syntax_err_ll(errtype, "'%s' is invalid as number", str);
}
static int
string_to_u8(struct ipset_session *session,
- const char *str, uint8_t *ret)
+ const char *str, uint8_t *ret,
+ enum ipset_err_type errtype)
{
int err;
unsigned long long num = 0;
- err = string_to_number_ll(session, str, 0, 255, &num);
+ err = string_to_number_ll(session, str, 0, 255, &num, errtype);
*ret = num;
return err;
@@ -130,7 +135,7 @@ static int
string_to_cidr(struct ipset_session *session,
const char *str, uint8_t min, uint8_t max, uint8_t *ret)
{
- int err = string_to_u8(session, str, ret);
+ int err = string_to_u8(session, str, ret, IPSET_ERROR);
if (!err && (*ret < min || *ret > max))
return syntax_err("'%s' is out of range %u-%u",
@@ -141,12 +146,13 @@ string_to_cidr(struct ipset_session *session,
static int
string_to_u16(struct ipset_session *session,
- const char *str, uint16_t *ret)
+ const char *str, uint16_t *ret,
+ enum ipset_err_type errtype)
{
int err;
unsigned long long num = 0;
- err = string_to_number_ll(session, str, 0, USHRT_MAX, &num);
+ err = string_to_number_ll(session, str, 0, USHRT_MAX, &num, errtype);
*ret = num;
return err;
@@ -159,7 +165,8 @@ string_to_u32(struct ipset_session *session,
int err;
unsigned long long num = 0;
- err = string_to_number_ll(session, str, 0, UINT_MAX, &num);
+ err = string_to_number_ll(session, str, 0, UINT_MAX, &num,
+ IPSET_ERROR);
*ret = num;
return err;
@@ -274,7 +281,10 @@ parse_portname(struct ipset_session *session, const char *str,
uint16_t *port, const char *proto)
{
char *saved, *tmp;
+ const char *protoname;
+ const struct protoent *protoent;
struct servent *service;
+ uint8_t protonum = 0;
saved = tmp = ipset_strdup(session, str);
if (tmp == NULL)
@@ -283,7 +293,15 @@ parse_portname(struct ipset_session *session, const char *str,
if (tmp == NULL)
goto error;
- service = getservbyname(tmp, proto);
+ protoname = proto;
+ if (string_to_u8(session, proto, &protonum, IPSET_WARNING) == 0) {
+ protoent = getprotobynumber(protonum);
+ if (protoent == NULL)
+ goto error;
+ protoname = protoent->p_name;
+ }
+
+ service = getservbyname(tmp, protoname);
if (service != NULL) {
*port = ntohs((uint16_t) service->s_port);
free(saved);
@@ -319,11 +337,11 @@ ipset_parse_port(struct ipset_session *session,
assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
assert(str);
- if (parse_portname(session, str, &port, proto) == 0) {
+ if (string_to_u16(session, str, &port, IPSET_WARNING) == 0) {
return ipset_session_data_set(session, opt, &port);
}
/* Error is stored as warning in session report */
- if (string_to_u16(session, str, &port) == 0) {
+ if (parse_portname(session, str, &port, proto) == 0) {
/* No error, so reset false error messages */
ipset_session_report_reset(session);
return ipset_session_data_set(session, opt, &port);
@@ -469,21 +487,23 @@ ipset_parse_proto(struct ipset_session *session,
{
const struct protoent *protoent;
uint8_t proto = 0;
+ uint8_t protonum = 0;
assert(session);
assert(opt == IPSET_OPT_PROTO);
assert(str);
+ if (string_to_u8(session, str, &protonum, IPSET_WARNING) == 0)
+ return ipset_session_data_set(session, opt, &protonum);
+
+ /* No error, so reset false error messages */
+ ipset_session_report_reset(session);
protoent = getprotobyname(strcasecmp(str, "icmpv6") == 0
? "ipv6-icmp" : str);
- if (protoent == NULL) {
- uint8_t protonum = 0;
- if (string_to_u8(session, str, &protonum) ||
- (protoent = getprotobynumber(protonum)) == NULL)
- return syntax_err("cannot parse '%s' "
- "as a protocol", str);
- }
+ if (protoent == NULL)
+ return syntax_err("cannot parse '%s' "
+ "as a protocol", str);
proto = protoent->p_proto;
if (!proto)
return syntax_err("Unsupported protocol '%s'", str);
@@ -513,8 +533,8 @@ parse_icmp_typecode(struct ipset_session *session,
str, family);
}
*a++ = '\0';
- if ((err = string_to_u8(session, tmp, &type)) != 0 ||
- (err = string_to_u8(session, a, &code)) != 0)
+ if ((err = string_to_u8(session, tmp, &type, IPSET_ERROR)) != 0 ||
+ (err = string_to_u8(session, a, &code, IPSET_ERROR)) != 0)
goto error;
typecode = (type << 8) | code;
@@ -1335,7 +1355,8 @@ ipset_parse_timeout(struct ipset_session *session,
assert(opt == IPSET_OPT_TIMEOUT);
assert(str);
- err = string_to_number_ll(session, str, 0, (UINT_MAX>>1)/1000, &llnum);
+ err = string_to_number_ll(session, str, 0, (UINT_MAX>>1)/1000, &llnum,
+ IPSET_ERROR);
if (err == 0) {
/* Timeout is expected to be 32bits wide, so we have
to convert it here */
@@ -1579,7 +1600,8 @@ ipset_parse_uint64(struct ipset_session *session,
assert(session);
assert(str);
- err = string_to_number_ll(session, str, 0, ULLONG_MAX - 1, &value);
+ err = string_to_number_ll(session, str, 0, ULLONG_MAX - 1, &value,
+ IPSET_ERROR);
if (err)
return err;
@@ -1623,7 +1645,7 @@ ipset_parse_uint16(struct ipset_session *session,
assert(session);
assert(str);
- err = string_to_u16(session, str, &value);
+ err = string_to_u16(session, str, &value, IPSET_ERROR);
if (err == 0)
return ipset_session_data_set(session, opt, &value);
@@ -1651,7 +1673,7 @@ ipset_parse_uint8(struct ipset_session *session,
assert(session);
assert(str);
- if ((err = string_to_u8(session, str, &value)) == 0)
+ if ((err = string_to_u8(session, str, &value, IPSET_ERROR)) == 0)
return ipset_session_data_set(session, opt, &value);
return err;
@@ -1682,6 +1704,9 @@ ipset_parse_netmask(struct ipset_session *session,
assert(str);
data = ipset_session_data(session);
+ if (ipset_data_test(data, IPSET_OPT_BITMASK))
+ return syntax_err("bitmask and netmask are mutually exclusive, provide only one");
+
family = ipset_data_family(data);
if (family == NFPROTO_UNSPEC) {
family = NFPROTO_IPV4;
@@ -1701,6 +1726,46 @@ ipset_parse_netmask(struct ipset_session *session,
}
/**
+ * ipset_parse_bitmask - parse string as a bitmask
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as a bitmask value, depending on family type.
+ * If family is not set yet, INET is assumed.
+ * The value is stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_bitmask(struct ipset_session *session,
+ enum ipset_opt opt, const char *str)
+{
+ uint8_t family;
+ struct ipset_data *data;
+
+ assert(session);
+ assert(opt == IPSET_OPT_BITMASK);
+ assert(str);
+
+ data = ipset_session_data(session);
+ if (ipset_data_test(data, IPSET_OPT_NETMASK))
+ return syntax_err("bitmask and netmask are mutually exclusive, provide only one");
+
+ family = ipset_data_family(data);
+ if (family == NFPROTO_UNSPEC) {
+ family = NFPROTO_IPV4;
+ ipset_data_set(data, IPSET_OPT_FAMILY, &family);
+ }
+
+ if (parse_ipaddr(session, opt, str, family))
+ return syntax_err("bitmask is not valid for family = %s",
+ family == NFPROTO_IPV4 ? "inet" : "inet6");
+
+ return 0;
+}
+
+/**
* ipset_parse_flag - "parse" option flags
* @session: session structure
* @opt: option kind of the data