ipset: update to 6.7-genl

This commit is contained in:
Jan Engelhardt
2011-05-31 22:53:12 +02:00
parent cfb72bf468
commit b2fc85c589
54 changed files with 1823 additions and 655 deletions

View File

@@ -1,7 +1,7 @@
/* Copyright 2007-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <assert.h> /* assert */
@@ -12,6 +12,7 @@
#include <sys/types.h> /* getaddrinfo */
#include <sys/socket.h> /* getaddrinfo, AF_ */
#include <net/ethernet.h> /* ETH_ALEN */
#include <net/if.h> /* IFNAMSIZ */
#include <netinet/in.h> /* IPPROTO_ */
#include <libipset/debug.h> /* D() */
@@ -43,21 +44,23 @@ static char *
ipset_strchr(const char *str, const char *sep)
{
char *match;
assert(str);
assert(sep);
for (; *sep != '\0'; sep++)
if ((match = strchr(str, sep[0])) != NULL
&& str[0] != sep[0]
&& str[strlen(str)-1] != sep[0])
for (; *sep != '\0'; sep++) {
match = strchr(str, sep[0]);
if (match != NULL &&
str[0] != sep[0] &&
str[strlen(str)-1] != sep[0])
return match;
}
return NULL;
}
/*
* Parser functions, shamelessly taken from iptables.c, ip6tables.c
/*
* Parser functions, shamelessly taken from iptables.c, ip6tables.c
* and parser.c from libnetfilter_conntrack.
*/
@@ -66,7 +69,7 @@ ipset_strchr(const char *str, const char *sep)
*/
static int
string_to_number_ll(struct ipset_session *session,
const char *str,
const char *str,
unsigned long long min,
unsigned long long max,
unsigned long long *ret)
@@ -113,7 +116,7 @@ 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);
if (!err && (*ret < min || *ret > max))
return syntax_err("'%s' is out of range %u-%u",
str, min, max);
@@ -164,7 +167,7 @@ ipset_parse_ether(struct ipset_session *session,
{
unsigned int i = 0;
unsigned char ether[ETH_ALEN];
assert(session);
assert(opt == IPSET_OPT_ETHER);
assert(str);
@@ -178,9 +181,9 @@ ipset_parse_ether(struct ipset_session *session,
number = strtol(str + i * 3, &end, 16);
if (end == str + i * 3 + 2
&& (*end == ':' || *end == '\0')
&& number >= 0 && number <= 255)
if (end == str + i * 3 + 2 &&
(*end == ':' || *end == '\0') &&
number >= 0 && number <= 255)
ether[i] = number;
else
goto error;
@@ -198,13 +201,13 @@ static int
parse_portname(struct ipset_session *session, const char *str,
uint16_t *port, const char *proto)
{
struct servent *service;
struct servent *service = getservbyname(str, proto);
if ((service = getservbyname(str, proto)) != NULL) {
if (service != NULL) {
*port = ntohs((uint16_t) service->s_port);
return 0;
}
return syntax_err("cannot parse '%s' as a %s port", str, proto);
}
@@ -232,8 +235,8 @@ ipset_parse_port(struct ipset_session *session,
assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
assert(str);
if ((err = string_to_u16(session, str, &port)) == 0
|| (err = parse_portname(session, str, &port, proto)) == 0)
if ((err = string_to_u16(session, str, &port)) == 0 ||
(err = parse_portname(session, str, &port, proto)) == 0)
err = ipset_session_data_set(session, opt, &port);
if (!err)
@@ -351,7 +354,7 @@ ipset_parse_proto(struct ipset_session *session,
assert(session);
assert(opt == IPSET_OPT_PROTO);
assert(str);
protoent = getprotobyname(strcasecmp(str, "icmpv6") == 0
? "ipv6-icmp" : str);
if (protoent == NULL)
@@ -360,7 +363,7 @@ ipset_parse_proto(struct ipset_session *session,
proto = protoent->p_proto;
if (!proto)
return syntax_err("Unsupported protocol '%s'", str);
return ipset_session_data_set(session, opt, &proto);
}
@@ -374,7 +377,7 @@ parse_icmp_typecode(struct ipset_session *session,
uint8_t type, code;
char *a, *saved, *tmp;
int err;
saved = tmp = strdup(str);
if (tmp == NULL)
return ipset_err(session,
@@ -384,13 +387,14 @@ parse_icmp_typecode(struct ipset_session *session,
if (a == NULL) {
free(saved);
return ipset_err(session,
"Cannot parse %s as an %s type/code.", str, family);
"Cannot parse %s as an %s type/code.",
str, family);
}
*a++ = '\0';
if ((err = string_to_u8(session, a, &type)) != 0
|| (err = string_to_u8(session, tmp, &code)) != 0)
goto error;
if ((err = string_to_u8(session, a, &type)) != 0 ||
(err = string_to_u8(session, tmp, &code)) != 0)
goto error;
typecode = (type << 8) | code;
err = ipset_session_data_set(session, opt, &typecode);
@@ -496,7 +500,7 @@ ipset_parse_proto_port(struct ipset_session *session,
err = ipset_parse_proto(session, IPSET_OPT_PROTO, tmp);
if (err)
goto error;
p = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
switch (p) {
case IPPROTO_TCP:
@@ -508,28 +512,31 @@ ipset_parse_proto_port(struct ipset_session *session,
goto parse_port;
case IPPROTO_ICMP:
if (family != AF_INET) {
syntax_err("Protocol ICMP can be used with family INET only");
syntax_err("Protocol ICMP can be used "
"with family INET only");
goto error;
}
err = ipset_parse_icmp(session, opt, a);
break;
case IPPROTO_ICMPV6:
if (family != AF_INET6) {
syntax_err("Protocol ICMPv6 can be used with family INET6 only");
syntax_err("Protocol ICMPv6 can be used "
"with family INET6 only");
goto error;
}
err = ipset_parse_icmpv6(session, opt, a);
break;
default:
if (!STREQ(a, "0")) {
syntax_err("Protocol %s can be used with pseudo port value 0 only.");
syntax_err("Protocol %s can be used "
"with pseudo port value 0 only.");
goto error;
}
ipset_data_flags_set(data, IPSET_FLAG(opt));
}
goto error;
} else {
proto = "TCP";
proto = "TCP";
err = ipset_data_set(data, IPSET_OPT_PROTO, &p);
if (err)
goto error;
@@ -559,7 +566,7 @@ ipset_parse_family(struct ipset_session *session,
{
struct ipset_data *data;
uint8_t family;
assert(session);
assert(opt == IPSET_OPT_FAMILY);
assert(str);
@@ -577,7 +584,7 @@ ipset_parse_family(struct ipset_session *session,
family = AF_UNSPEC;
else
return syntax_err("unknown INET family %s", str);
return ipset_data_set(data, opt, &family);
}
@@ -585,27 +592,27 @@ ipset_parse_family(struct ipset_session *session,
* Parse IPv4/IPv6 addresses, networks and ranges.
* We resolve hostnames but just the first IP address is used.
*/
static struct addrinfo *
call_getaddrinfo(struct ipset_session *session, const char *str,
uint8_t family)
{
struct addrinfo hints;
struct addrinfo *res;
struct addrinfo *res;
int err;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = family;
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = 0;
hints.ai_next = NULL;
hints.ai_family = family;
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = 0;
hints.ai_next = NULL;
if ((err = getaddrinfo(str, NULL, &hints, &res)) != 0) {
syntax_err("cannot resolve '%s' to an %s address: %s",
str, family == AF_INET6 ? "IPv6" : "IPv4",
gai_strerror(err));
return NULL;
if ((err = getaddrinfo(str, NULL, &hints, &res)) != 0) {
syntax_err("cannot resolve '%s' to an %s address: %s",
str, family == AF_INET6 ? "IPv6" : "IPv4",
gai_strerror(err));
return NULL;
} else
return res;
}
@@ -617,10 +624,10 @@ get_addrinfo(struct ipset_session *session,
struct addrinfo **info,
uint8_t family)
{
struct addrinfo *i;
struct addrinfo *i;
size_t addrlen = family == AF_INET ? sizeof(struct sockaddr_in)
: sizeof(struct sockaddr_in6);
int found, err = 0;
int found, err = 0;
if ((*info = call_getaddrinfo(session, str, family)) == NULL) {
syntax_err("cannot parse %s: resolving to %s address failed",
@@ -633,13 +640,21 @@ get_addrinfo(struct ipset_session *session,
continue;
if (found == 0) {
if (family == AF_INET) {
/* Workaround: direct cast increases required alignment on Sparc */
const struct sockaddr_in *saddr = (void *)i->ai_addr;
err = ipset_session_data_set(session, opt, &saddr->sin_addr);
/* Workaround: direct cast increases
* required alignment on Sparc
*/
const struct sockaddr_in *saddr =
(void *)i->ai_addr;
err = ipset_session_data_set(session,
opt, &saddr->sin_addr);
} else {
/* Workaround: direct cast increases required alignment on Sparc */
const struct sockaddr_in6 *saddr = (void *)i->ai_addr;
err = ipset_session_data_set(session, opt, &saddr->sin6_addr);
/* Workaround: direct cast increases
* required alignment on Sparc
*/
const struct sockaddr_in6 *saddr =
(void *)i->ai_addr;
err = ipset_session_data_set(session,
opt, &saddr->sin6_addr);
}
} else if (found == 1) {
ipset_warn(session,
@@ -662,12 +677,12 @@ parse_ipaddr(struct ipset_session *session,
enum ipset_opt opt, const char *str,
uint8_t family)
{
uint8_t m = family == AF_INET ? 32 : 128;
int aerr = EINVAL, err = 0, range = 0;
char *saved = strdup(str);
char *a, *tmp = saved;
struct addrinfo *info;
enum ipset_opt copt, opt2;
uint8_t m = family == AF_INET ? 32 : 128;
int aerr = EINVAL, err = 0, range = 0;
char *saved = strdup(str);
char *a, *tmp = saved;
struct addrinfo *info;
enum ipset_opt copt, opt2;
if (opt == IPSET_OPT_IP) {
copt = IPSET_OPT_CIDR;
@@ -685,8 +700,8 @@ parse_ipaddr(struct ipset_session *session,
/* IP/mask */
*a++ = '\0';
if ((err = string_to_cidr(session, a, 0, m, &m)) != 0
|| (err = ipset_session_data_set(session, copt, &m)) != 0)
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 */
@@ -694,8 +709,8 @@ parse_ipaddr(struct ipset_session *session,
D("range %s", a);
range++;
}
if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0
|| !range)
if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0 ||
!range)
goto out;
freeaddrinfo(info);
aerr = get_addrinfo(session, opt2, a, &info, family);
@@ -708,7 +723,7 @@ out:
err = -1;
free(saved);
return err;
}
}
enum ipaddr_type {
IPADDR_ANY,
@@ -721,7 +736,7 @@ static inline bool
cidr_hostaddr(const char *str, uint8_t family)
{
char *a = cidr_separator(str);
return family == AF_INET ? STREQ(a, "/32") : STREQ(a, "/128");
}
@@ -739,10 +754,10 @@ parse_ip(struct ipset_session *session,
switch (addrtype) {
case IPADDR_PLAIN:
if (range_separator(str)
|| (cidr_separator(str) && !cidr_hostaddr(str, family)))
return syntax_err("plain IP address must be supplied: %s",
str);
if (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))
@@ -795,7 +810,7 @@ ipset_parse_ip(struct ipset_session *session,
* @opt: option kind of the data
* @str: string to parse
*
* Parse string as an IPv4|IPv6 address or hostname. If family
* Parse string as an IPv4|IPv6 address or hostname. If family
* is not set yet in the data blob, INET is assumed.
* The value is stored in the data blob of the session.
*
@@ -806,9 +821,9 @@ ipset_parse_single_ip(struct ipset_session *session,
enum ipset_opt opt, const char *str)
{
assert(session);
assert(opt == IPSET_OPT_IP
|| opt == IPSET_OPT_IP_TO
|| opt == IPSET_OPT_IP2);
assert(opt == IPSET_OPT_IP ||
opt == IPSET_OPT_IP_TO ||
opt == IPSET_OPT_IP2);
assert(str);
return parse_ip(session, opt, str, IPADDR_PLAIN);
@@ -820,7 +835,7 @@ ipset_parse_single_ip(struct ipset_session *session,
* @opt: option kind of the data
* @str: string to parse
*
* Parse string as an IPv4|IPv6 address/cidr pattern. If family
* Parse string as an IPv4|IPv6 address/cidr pattern. If family
* is not set yet in the data blob, INET is assumed.
* The value is stored in the data blob of the session.
*
@@ -882,8 +897,8 @@ ipset_parse_netrange(struct ipset_session *session,
assert(str);
if (!(range_separator(str) || cidr_separator(str)))
return syntax_err("IP/cidr or IP-IP range must be specified: %s",
str);
return syntax_err("IP/cidr or IP-IP range must be specified: "
"%s", str);
return parse_ip(session, opt, str, IPADDR_ANY);
}
@@ -909,8 +924,8 @@ ipset_parse_iprange(struct ipset_session *session,
assert(str);
if (cidr_separator(str))
return syntax_err("IP address or IP-IP range must be specified: %s",
str);
return syntax_err("IP address or IP-IP range must be "
"specified: %s", str);
return parse_ip(session, opt, str, IPADDR_ANY);
}
@@ -966,15 +981,15 @@ ipset_parse_ip4_single6(struct ipset_session *session,
assert(session);
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
assert(str);
data = ipset_session_data(session);
family = ipset_data_family(data);
if (family == AF_UNSPEC) {
family = AF_INET;
ipset_data_set(data, IPSET_OPT_FAMILY, &family);
}
return family == AF_INET ? ipset_parse_ip(session, opt, str)
: ipset_parse_single_ip(session, opt, str);
@@ -1006,15 +1021,15 @@ ipset_parse_ip4_net6(struct ipset_session *session,
assert(session);
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
assert(str);
data = ipset_session_data(session);
family = ipset_data_family(data);
if (family == AF_UNSPEC) {
family = AF_INET;
ipset_data_set(data, IPSET_OPT_FAMILY, &family);
}
return family == AF_INET ? parse_ip(session, opt, str, IPADDR_ANY)
: ipset_parse_ipnet(session, opt, str);
@@ -1049,8 +1064,8 @@ ipset_parse_iptimeout(struct ipset_session *session,
if (ipset_data_flags_test(ipset_session_data(session),
IPSET_FLAG(IPSET_OPT_TIMEOUT)))
return syntax_err("mixed syntax, timeout already specified");
tmp = saved = strdup(str);
tmp = saved = strdup(str);
if (saved == NULL)
return ipset_err(session,
"Cannot allocate memory to duplicate %s.",
@@ -1072,12 +1087,12 @@ ipset_parse_iptimeout(struct ipset_session *session,
#define check_setname(str, saved) \
do { \
if (strlen(str) > IPSET_MAXNAMELEN - 1) { \
if (saved != NULL) \
free(saved); \
return syntax_err("setname '%s' is longer than %u characters", \
str, IPSET_MAXNAMELEN - 1); \
} \
if (strlen(str) > IPSET_MAXNAMELEN - 1) { \
if (saved != NULL) \
free(saved); \
return syntax_err("setname '%s' is longer than %u characters",\
str, IPSET_MAXNAMELEN - 1); \
} \
} while (0)
@@ -1112,7 +1127,7 @@ 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 = strdup(str);
if (saved == NULL)
return ipset_err(session,
"Cannot allocate memory to duplicate %s.",
@@ -1122,8 +1137,8 @@ ipset_parse_name_compat(struct ipset_session *session,
*a++ = '\0';
if ((b = elem_separator(a)) != NULL)
*b++ = '\0';
if (b == NULL
|| !(STREQ(a, "before") || STREQ(a, "after"))) {
if (b == NULL ||
!(STREQ(a, "before") || STREQ(a, "after"))) {
err = ipset_err(session, "you must specify elements "
"as setname%s[before|after]%ssetname",
sep, sep);
@@ -1164,9 +1179,9 @@ ipset_parse_setname(struct ipset_session *session,
enum ipset_opt opt, const char *str)
{
assert(session);
assert(opt == IPSET_SETNAME
|| opt == IPSET_OPT_NAME
|| opt == IPSET_OPT_SETNAME2);
assert(opt == IPSET_SETNAME ||
opt == IPSET_OPT_NAME ||
opt == IPSET_OPT_SETNAME2);
assert(str);
check_setname(str, NULL);
@@ -1252,13 +1267,13 @@ ipset_parse_uint32(struct ipset_session *session,
{
uint32_t value;
int err;
assert(session);
assert(str);
if ((err = string_to_u32(session, str, &value)) == 0)
return ipset_session_data_set(session, opt, &value);
return err;
}
@@ -1279,7 +1294,7 @@ ipset_parse_uint8(struct ipset_session *session,
{
uint8_t value;
int err;
assert(session);
assert(str);
@@ -1308,7 +1323,7 @@ ipset_parse_netmask(struct ipset_session *session,
uint8_t family, cidr;
struct ipset_data *data;
int err = 0;
assert(session);
assert(opt == IPSET_OPT_NETMASK);
assert(str);
@@ -1321,7 +1336,7 @@ ipset_parse_netmask(struct ipset_session *session,
}
err = string_to_cidr(session, str,
family == AF_INET ? 1 : 4,
family == AF_INET ? 1 : 4,
family == AF_INET ? 31 : 124,
&cidr);
@@ -1350,7 +1365,7 @@ ipset_parse_flag(struct ipset_session *session,
enum ipset_opt opt, const char *str UNUSED)
{
assert(session);
return ipset_session_data_set(session, opt, NULL);
}
@@ -1390,10 +1405,45 @@ ipset_parse_typename(struct ipset_session *session,
if (type == NULL)
return -1;
return ipset_session_data_set(session, IPSET_OPT_TYPE, type);
}
/**
* ipset_parse_iface - parse string as an interface name
* @session: session structure
* @opt: option kind of the data
* @str: string to parse
*
* Parse string as an interface name, optionally with 'physdev:' prefix.
* The value is stored in the data blob of the session.
*
* Returns 0 on success or a negative error code.
*/
int
ipset_parse_iface(struct ipset_session *session,
enum ipset_opt opt, const char *str)
{
struct ipset_data *data;
int offset = 0, err = 0;
assert(session);
assert(opt == IPSET_OPT_IFACE);
assert(str);
data = ipset_session_data(session);
if (STREQ(str, "physdev:")) {
offset = 8;
err = ipset_data_set(data, IPSET_OPT_PHYSDEV, str);
}
if (strlen(str + offset) > IFNAMSIZ - 1)
return syntax_err("interface name '%s' is longer "
"than %u characters",
str + offset, IFNAMSIZ - 1);
return ipset_data_set(data, opt, str + offset);
}
/**
* ipset_parse_output - parse output format name
* @session: session structure
@@ -1442,7 +1492,8 @@ ipset_parse_ignored(struct ipset_session *session,
if (!ipset_data_ignored(ipset_session_data(session), opt))
ipset_warn(session,
"Option %s is ignored. Please upgrade your syntax.", str);
"Option %s is ignored. "
"Please upgrade your syntax.", str);
return 0;
}
@@ -1473,7 +1524,7 @@ ipset_call_parser(struct ipset_session *session,
}
#define parse_elem(s, t, d, str) \
do { \
do { \
if (!(t)->elem[d].parse) \
goto internal; \
ret = (t)->elem[d].parse(s, (t)->elem[d].opt, str); \
@@ -1531,8 +1582,8 @@ ipset_parse_elem(struct ipset_session *session,
} else if (a != NULL) {
if (type->compat_parse_elem) {
ret = type->compat_parse_elem(session,
type->elem[IPSET_DIM_ONE].opt,
saved);
type->elem[IPSET_DIM_ONE].opt,
saved);
goto out;
}
elem_syntax_err("Elem separator in %s, "