mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-22 04:24:58 +02:00
ipset: update to 6.7-genl
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
/* 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 */
|
||||
#include <arpa/inet.h> /* ntoh* */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
#include <sys/socket.h> /* AF_ */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* memset */
|
||||
@@ -17,7 +18,7 @@
|
||||
#include <libipset/utils.h> /* inXcpy */
|
||||
#include <libipset/data.h> /* prototypes */
|
||||
|
||||
/* Internal data structure to hold
|
||||
/* Internal data structure to hold
|
||||
* a) input data entered by the user or
|
||||
* b) data received from kernel
|
||||
*
|
||||
@@ -72,6 +73,7 @@ struct ipset_data {
|
||||
char ether[ETH_ALEN];
|
||||
char name[IPSET_MAXNAMELEN];
|
||||
char nameref[IPSET_MAXNAMELEN];
|
||||
char iface[IFNAMSIZ];
|
||||
} adt;
|
||||
};
|
||||
};
|
||||
@@ -172,7 +174,7 @@ ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt)
|
||||
{
|
||||
bool ignored;
|
||||
assert(data);
|
||||
|
||||
|
||||
ignored = data->ignored & IPSET_FLAG(opt);
|
||||
data->ignored |= IPSET_FLAG(opt);
|
||||
|
||||
@@ -301,6 +303,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
case IPSET_OPT_PROTO:
|
||||
data->adt.proto = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_IFACE:
|
||||
ipset_strlcpy(data->adt.iface, value, IFNAMSIZ);
|
||||
break;
|
||||
/* Swap/rename */
|
||||
case IPSET_OPT_SETNAME2:
|
||||
ipset_strlcpy(data->setname2, value, IPSET_MAXNAMELEN);
|
||||
@@ -312,6 +317,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
case IPSET_OPT_BEFORE:
|
||||
cadt_flag_type_attr(data, opt, IPSET_FLAG_BEFORE);
|
||||
break;
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
cadt_flag_type_attr(data, opt, IPSET_FLAG_PHYSDEV);
|
||||
break;
|
||||
case IPSET_OPT_FLAGS:
|
||||
data->flags = *(const uint32_t *)value;
|
||||
break;
|
||||
@@ -321,7 +329,7 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
default:
|
||||
return -1;
|
||||
};
|
||||
|
||||
|
||||
ipset_data_flags_set(data, IPSET_FLAG(opt));
|
||||
return 0;
|
||||
}
|
||||
@@ -340,7 +348,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
{
|
||||
assert(data);
|
||||
assert(opt != IPSET_OPT_NONE);
|
||||
|
||||
|
||||
if (!(opt == IPSET_OPT_TYPENAME || ipset_data_test(data, opt)))
|
||||
return NULL;
|
||||
|
||||
@@ -413,6 +421,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
return &data->adt.cidr2;
|
||||
case IPSET_OPT_PROTO:
|
||||
return &data->adt.proto;
|
||||
case IPSET_OPT_IFACE:
|
||||
return &data->adt.iface;
|
||||
/* Swap/rename */
|
||||
case IPSET_OPT_SETNAME2:
|
||||
return data->setname2;
|
||||
@@ -422,6 +432,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
return &data->flags;
|
||||
case IPSET_OPT_CADT_FLAGS:
|
||||
case IPSET_OPT_BEFORE:
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
return &data->cadt_flags;
|
||||
default:
|
||||
return NULL;
|
||||
@@ -472,8 +483,9 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
|
||||
return sizeof(uint8_t);
|
||||
case IPSET_OPT_ETHER:
|
||||
return ETH_ALEN;
|
||||
/* Flags counted once */
|
||||
/* Flags doesn't counted once :-( */
|
||||
case IPSET_OPT_BEFORE:
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
return sizeof(uint32_t);
|
||||
default:
|
||||
return 0;
|
||||
@@ -521,8 +533,8 @@ uint8_t
|
||||
ipset_data_cidr(const struct ipset_data *data)
|
||||
{
|
||||
assert(data);
|
||||
return ipset_data_test(data, IPSET_OPT_CIDR) ? data->cidr :
|
||||
data->family == AF_INET ? 32 :
|
||||
return ipset_data_test(data, IPSET_OPT_CIDR) ? data->cidr :
|
||||
data->family == AF_INET ? 32 :
|
||||
data->family == AF_INET6 ? 128 : 0;
|
||||
}
|
||||
|
||||
|
@@ -1,12 +1,12 @@
|
||||
/* Copyright 2011 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 <arpa/inet.h> /* inet_ntop */
|
||||
#include <libmnl/libmnl.h> /* libmnl backend */
|
||||
#include <libmnl/libmnl.h> /* libmnl backend */
|
||||
|
||||
struct ipset_attrname {
|
||||
const char *name;
|
||||
@@ -63,6 +63,7 @@ static const struct ipset_attrname adtattr2name[] = {
|
||||
[IPSET_ATTR_IP2] = { .name = "IP2" },
|
||||
[IPSET_ATTR_CIDR2] = { .name = "CIDR2" },
|
||||
[IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" },
|
||||
[IPSET_ATTR_IFACE] = { .name = "IFACE" },
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -73,23 +74,24 @@ debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
|
||||
uint32_t v;
|
||||
int i;
|
||||
|
||||
fprintf(stderr,"\t\t%s attributes:\n", policy == create_attrs ? "CREATE" : "ADT");
|
||||
fprintf(stderr, "\t\t%s attributes:\n",
|
||||
policy == create_attrs ? "CREATE" : "ADT");
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= max; i++) {
|
||||
if (!nla[i])
|
||||
continue;
|
||||
switch (policy[i].type) {
|
||||
case MNL_TYPE_U8:
|
||||
v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
|
||||
v = *(uint8_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, v);
|
||||
break;
|
||||
case MNL_TYPE_U16:
|
||||
v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
|
||||
v = *(uint16_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, ntohs(v));
|
||||
break;
|
||||
case MNL_TYPE_U32:
|
||||
v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
|
||||
v = *(uint32_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, ntohl(v));
|
||||
break;
|
||||
@@ -103,18 +105,23 @@ debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
void *d;
|
||||
|
||||
if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb, ipattr) < 0) {
|
||||
fprintf(stderr, "\t\tIPADDR: cannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb,
|
||||
ipattr) < 0) {
|
||||
fprintf(stderr,
|
||||
"\t\tIPADDR: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
if (ipattr[IPSET_ATTR_IPADDR_IPV4]) {
|
||||
d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV4]);
|
||||
d = mnl_attr_get_payload(
|
||||
ipattr[IPSET_ATTR_IPADDR_IPV4]);
|
||||
|
||||
inet_ntop(AF_INET, d, addr, INET6_ADDRSTRLEN);
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
attr2name[i].name, addr);
|
||||
} else if (ipattr[IPSET_ATTR_IPADDR_IPV6]) {
|
||||
d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV6]);
|
||||
d = mnl_attr_get_payload(
|
||||
ipattr[IPSET_ATTR_IPADDR_IPV6]);
|
||||
|
||||
inet_ntop(AF_INET6, d, addr, INET6_ADDRSTRLEN);
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
@@ -137,23 +144,23 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
uint32_t v;
|
||||
int i;
|
||||
|
||||
fprintf(stderr,"\tCommand attributes:\n");
|
||||
fprintf(stderr, "\tCommand attributes:\n");
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) {
|
||||
if (!nla[i])
|
||||
continue;
|
||||
switch (cmd_attrs[i].type) {
|
||||
case MNL_TYPE_U8:
|
||||
v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
|
||||
v = *(uint8_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, v);
|
||||
break;
|
||||
case MNL_TYPE_U16:
|
||||
v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
|
||||
v = *(uint16_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, ntohs(v));
|
||||
break;
|
||||
case MNL_TYPE_U32:
|
||||
v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
|
||||
v = *(uint32_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, ntohl(v));
|
||||
break;
|
||||
@@ -168,8 +175,11 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
case IPSET_CMD_ADD:
|
||||
case IPSET_CMD_DEL:
|
||||
case IPSET_CMD_TEST:
|
||||
if (mnl_attr_parse_nested(nla[i], adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse_nested(nla[i],
|
||||
adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tADT: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
|
||||
@@ -178,8 +188,12 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
adt);
|
||||
break;
|
||||
default:
|
||||
if (mnl_attr_parse_nested(nla[i], create_attr_cb, cattr) < 0) {
|
||||
fprintf(stderr, "\tCREATE: cannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse_nested(nla[i],
|
||||
create_attr_cb,
|
||||
cattr) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tCREATE: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_CREATE_MAX,
|
||||
@@ -191,15 +205,18 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
struct nlattr *tb;
|
||||
mnl_attr_for_each_nested(tb, nla[i]) {
|
||||
memset(adt, 0, sizeof(adt));
|
||||
if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse_nested(tb,
|
||||
adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tADT: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
|
||||
adt_attrs,
|
||||
adtattr2name,
|
||||
adt);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -226,8 +243,9 @@ ipset_debug_msg(const char *dir, void *buffer, int len)
|
||||
"\tlen %d\n"
|
||||
"\tseq %u\n",
|
||||
dir,
|
||||
nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" :
|
||||
nlh->nlmsg_type == NLMSG_DONE ? "DONE" : "OVERRUN",
|
||||
nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" :
|
||||
nlh->nlmsg_type == NLMSG_DONE ? "DONE" :
|
||||
"OVERRUN",
|
||||
len, nlh->nlmsg_seq);
|
||||
goto next_msg;
|
||||
case NLMSG_ERROR: {
|
||||
@@ -256,8 +274,10 @@ ipset_debug_msg(const char *dir, void *buffer, int len)
|
||||
if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_CMD_MAX)
|
||||
goto next_msg;
|
||||
memset(nla, 0, sizeof(nla));
|
||||
if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP) {
|
||||
fprintf(stderr, "\tcannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse(nlh, nfmsglen,
|
||||
cmd_attr_cb, nla) < MNL_CB_STOP) {
|
||||
fprintf(stderr, "\tcannot validate "
|
||||
"and parse attributes\n");
|
||||
goto next_msg;
|
||||
}
|
||||
debug_cmd_attrs(cmd, nla);
|
||||
|
@@ -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 <libipset/utils.h> /* STRNEQ */
|
||||
@@ -49,19 +49,20 @@ static const struct icmp_names icmp_typecodes[] = {
|
||||
{ "address-mask-reply", 18, 0 },
|
||||
};
|
||||
|
||||
const char * id_to_icmp(uint8_t id)
|
||||
const char *id_to_icmp(uint8_t id)
|
||||
{
|
||||
return id < ARRAY_SIZE(icmp_typecodes) ? icmp_typecodes[id].name : NULL;
|
||||
}
|
||||
|
||||
const char * icmp_to_name(uint8_t type, uint8_t code)
|
||||
const char *icmp_to_name(uint8_t type, uint8_t code)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++)
|
||||
if (icmp_typecodes[i].type == type && icmp_typecodes[i].code == code)
|
||||
if (icmp_typecodes[i].type == type &&
|
||||
icmp_typecodes[i].code == code)
|
||||
return icmp_typecodes[i].name;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -71,9 +72,10 @@ int name_to_icmp(const char *str, uint16_t *typecode)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++)
|
||||
if (STRNCASEQ(icmp_typecodes[i].name, str, strlen(str))) {
|
||||
*typecode = (icmp_typecodes[i].type << 8) | icmp_typecodes[i].code;
|
||||
*typecode = (icmp_typecodes[i].type << 8) |
|
||||
icmp_typecodes[i].code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@@ -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 <libipset/utils.h> /* STRNEQ */
|
||||
@@ -36,19 +36,21 @@ static const struct icmpv6_names icmpv6_typecodes[] = {
|
||||
{ "redirect", 137, 0 },
|
||||
};
|
||||
|
||||
const char * id_to_icmpv6(uint8_t id)
|
||||
const char *id_to_icmpv6(uint8_t id)
|
||||
{
|
||||
return id < ARRAY_SIZE(icmpv6_typecodes) ? icmpv6_typecodes[id].name : NULL;
|
||||
return id < ARRAY_SIZE(icmpv6_typecodes) ?
|
||||
icmpv6_typecodes[id].name : NULL;
|
||||
}
|
||||
|
||||
const char * icmpv6_to_name(uint8_t type, uint8_t code)
|
||||
const char *icmpv6_to_name(uint8_t type, uint8_t code)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++)
|
||||
if (icmpv6_typecodes[i].type == type && icmpv6_typecodes[i].code == code)
|
||||
if (icmpv6_typecodes[i].type == type &&
|
||||
icmpv6_typecodes[i].code == code)
|
||||
return icmpv6_typecodes[i].name;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,10 @@ int name_to_icmpv6(const char *str, uint16_t *typecode)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++)
|
||||
if (STRNCASEQ(icmpv6_typecodes[i].name, str, strlen(str))) {
|
||||
*typecode = (icmpv6_typecodes[i].type << 8) | icmpv6_typecodes[i].code;
|
||||
*typecode = (icmpv6_typecodes[i].type << 8) |
|
||||
icmpv6_typecodes[i].code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@@ -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 */
|
||||
@@ -38,7 +38,8 @@ struct ipset_handle {
|
||||
|
||||
/* Netlink flags of the commands */
|
||||
static const uint16_t cmdflags[] = {
|
||||
[IPSET_CMD_CREATE-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL,
|
||||
[IPSET_CMD_CREATE-1] = NLM_F_REQUEST|NLM_F_ACK|
|
||||
NLM_F_CREATE|NLM_F_EXCL,
|
||||
[IPSET_CMD_DESTROY-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_RENAME-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
@@ -209,28 +210,28 @@ static int ipset_mnl_getid(struct ipset_handle *h, bool modprobe)
|
||||
|
||||
static struct ipset_handle *
|
||||
ipset_mnl_init(mnl_cb_t *cb_ctl, void *data)
|
||||
{
|
||||
{
|
||||
struct ipset_handle *handle;
|
||||
|
||||
|
||||
assert(cb_ctl);
|
||||
assert(data);
|
||||
|
||||
handle = calloc(1, sizeof(*handle));
|
||||
if (!handle)
|
||||
return NULL;
|
||||
|
||||
|
||||
handle->h = mnl_socket_open(NETLINK_GENERIC);
|
||||
if (!handle->h)
|
||||
goto free_handle;
|
||||
|
||||
|
||||
if (mnl_socket_bind(handle->h, 0, MNL_SOCKET_AUTOPID) < 0)
|
||||
goto close_nl;
|
||||
|
||||
|
||||
handle->portid = mnl_socket_get_portid(handle->h);
|
||||
handle->cb_ctl = cb_ctl;
|
||||
handle->data = data;
|
||||
handle->seq = time(NULL);
|
||||
|
||||
|
||||
if (ipset_mnl_getid(handle, false) < 0)
|
||||
goto close_nl;
|
||||
return handle;
|
||||
@@ -240,7 +241,7 @@ close_nl:
|
||||
free_handle:
|
||||
free(handle);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@@ -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, "
|
||||
|
@@ -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/socket.h> /* inet_ntop */
|
||||
#include <arpa/inet.h> /* inet_ntop */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/data.h> /* ipset_data_* */
|
||||
@@ -53,15 +54,15 @@ ipset_print_ether(char *buf, unsigned int len,
|
||||
{
|
||||
const unsigned char *ether;
|
||||
int i, size, offset = 0;
|
||||
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_ETHER);
|
||||
|
||||
|
||||
if (len < ETH_ALEN*3)
|
||||
return -1;
|
||||
|
||||
|
||||
ether = ipset_data_get(data, opt);
|
||||
assert(ether);
|
||||
|
||||
@@ -71,7 +72,7 @@ ipset_print_ether(char *buf, unsigned int len,
|
||||
size = snprintf(buf + offset, len, ":%02X", ether[i]);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -138,35 +139,60 @@ ipset_print_type(char *buf, unsigned int len,
|
||||
assert(type);
|
||||
if (len < strlen(type->name) + 1)
|
||||
return -1;
|
||||
|
||||
|
||||
return snprintf(buf, len, "%s", type->name);
|
||||
}
|
||||
|
||||
#define GETNAMEINFO(family, f, n) \
|
||||
static inline int \
|
||||
__getnameinfo##f(char *buf, unsigned int len, \
|
||||
int flags, const union nf_inet_addr *addr) \
|
||||
{ \
|
||||
struct sockaddr_in##n saddr; \
|
||||
int err; \
|
||||
\
|
||||
memset(&saddr, 0, sizeof(saddr)); \
|
||||
in##f##cpy(&saddr.sin##n##_addr, &addr->in##n); \
|
||||
saddr.sin##n##_family = family; \
|
||||
\
|
||||
err = getnameinfo((const struct sockaddr *)&saddr, \
|
||||
sizeof(saddr), \
|
||||
buf, len, NULL, 0, flags); \
|
||||
\
|
||||
if (!(flags & NI_NUMERICHOST) && \
|
||||
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL))) \
|
||||
err = getnameinfo((const struct sockaddr *)&saddr, \
|
||||
sizeof(saddr), \
|
||||
buf, len, NULL, 0, \
|
||||
flags | NI_NUMERICHOST); \
|
||||
D("getnameinfo err: %i, errno %i", err, errno); \
|
||||
return (err == 0 ? (int)strlen(buf) : \
|
||||
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);\
|
||||
static inline int
|
||||
__getnameinfo4(char *buf, unsigned int len,
|
||||
int flags, const union nf_inet_addr *addr)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
int err;
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
in4cpy(&saddr.sin_addr, &addr->in);
|
||||
saddr.sin_family = AF_INET;
|
||||
|
||||
err = getnameinfo((const struct sockaddr *)&saddr,
|
||||
sizeof(saddr),
|
||||
buf, len, NULL, 0, flags);
|
||||
|
||||
if (!(flags & NI_NUMERICHOST) &&
|
||||
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL)))
|
||||
err = getnameinfo((const struct sockaddr *)&saddr,
|
||||
sizeof(saddr),
|
||||
buf, len, NULL, 0,
|
||||
flags | NI_NUMERICHOST);
|
||||
D("getnameinfo err: %i, errno %i", err, errno);
|
||||
return (err == 0 ? (int)strlen(buf) :
|
||||
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__getnameinfo6(char *buf, unsigned int len,
|
||||
int flags, const union nf_inet_addr *addr)
|
||||
{
|
||||
struct sockaddr_in6 saddr;
|
||||
int err;
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
in6cpy(&saddr.sin6_addr, &addr->in6);
|
||||
saddr.sin6_family = AF_INET6;
|
||||
|
||||
err = getnameinfo((const struct sockaddr *)&saddr,
|
||||
sizeof(saddr),
|
||||
buf, len, NULL, 0, flags);
|
||||
|
||||
if (!(flags & NI_NUMERICHOST) &&
|
||||
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL)))
|
||||
err = getnameinfo((const struct sockaddr *)&saddr,
|
||||
sizeof(saddr),
|
||||
buf, len, NULL, 0,
|
||||
flags | NI_NUMERICHOST);
|
||||
D("getnameinfo err: %i, errno %i", err, errno);
|
||||
return (err == 0 ? (int)strlen(buf) :
|
||||
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);
|
||||
}
|
||||
|
||||
#define SNPRINTF_IP(mask, f) \
|
||||
@@ -189,10 +215,8 @@ snprintf_ipv##f(char *buf, unsigned int len, int flags, \
|
||||
return offset; \
|
||||
}
|
||||
|
||||
GETNAMEINFO(AF_INET, 4, )
|
||||
SNPRINTF_IP(32, 4)
|
||||
|
||||
GETNAMEINFO(AF_INET6, 6, 6)
|
||||
SNPRINTF_IP(128, 6)
|
||||
|
||||
/**
|
||||
@@ -231,7 +255,7 @@ ipset_print_ip(char *buf, unsigned int len,
|
||||
} else
|
||||
cidr = family == AF_INET6 ? 128 : 32;
|
||||
flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
||||
|
||||
|
||||
ip = ipset_data_get(data, opt);
|
||||
assert(ip);
|
||||
if (family == AF_INET)
|
||||
@@ -257,8 +281,8 @@ ipset_print_ip(char *buf, unsigned int len,
|
||||
size = snprintf_ipv6(buf + offset, len, flags, ip, cidr);
|
||||
else
|
||||
return -1;
|
||||
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -287,9 +311,9 @@ ipset_print_ipaddr(char *buf, unsigned int len,
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
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);
|
||||
|
||||
family = ipset_data_family(data);
|
||||
cidropt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2;
|
||||
@@ -332,7 +356,7 @@ ipset_print_number(char *buf, unsigned int len,
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
|
||||
|
||||
number = ipset_data_get(data, opt);
|
||||
maxsize = ipset_data_sizeof(opt, AF_INET);
|
||||
D("opt: %u, maxsize %zu", opt, maxsize);
|
||||
@@ -379,7 +403,7 @@ ipset_print_name(char *buf, unsigned int len,
|
||||
name = ipset_data_get(data, opt);
|
||||
assert(name);
|
||||
size = snprintf(buf, len, "%s", name);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
if (ipset_data_test(data, IPSET_OPT_NAMEREF)) {
|
||||
bool before = false;
|
||||
@@ -389,10 +413,10 @@ ipset_print_name(char *buf, unsigned int len,
|
||||
before = (*flags) & IPSET_FLAG_BEFORE;
|
||||
}
|
||||
size = snprintf(buf + offset, len,
|
||||
" %s %s", before ? "before" : "after",
|
||||
(const char *) ipset_data_get(data,
|
||||
IPSET_OPT_NAMEREF));
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
" %s %s", before ? "before" : "after",
|
||||
(const char *) ipset_data_get(data,
|
||||
IPSET_OPT_NAMEREF));
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
@@ -430,19 +454,58 @@ ipset_print_port(char *buf, unsigned int len,
|
||||
port = ipset_data_get(data, IPSET_OPT_PORT);
|
||||
assert(port);
|
||||
size = snprintf(buf, len, "%u", *port);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
if (ipset_data_test(data, IPSET_OPT_PORT_TO)) {
|
||||
port = ipset_data_get(data, IPSET_OPT_PORT_TO);
|
||||
size = snprintf(buf + offset, len,
|
||||
"%s%u",
|
||||
IPSET_RANGE_SEPARATOR, *port);
|
||||
"%s%u",
|
||||
IPSET_RANGE_SEPARATOR, *port);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_iface - print interface element string
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print interface element string to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_iface(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const char *name;
|
||||
int size, offset = 0;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_IFACE);
|
||||
|
||||
if (len < IFNAMSIZ + strlen("physdev:"))
|
||||
return -1;
|
||||
|
||||
if (ipset_data_test(data, IPSET_OPT_PHYSDEV)) {
|
||||
size = snprintf(buf, len, "physdev:");
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
name = ipset_data_get(data, opt);
|
||||
assert(name);
|
||||
size = snprintf(buf, len, "%s", name);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_proto - print protocol name
|
||||
* @buf: printing buffer
|
||||
@@ -471,12 +534,12 @@ ipset_print_proto(char *buf, unsigned int len,
|
||||
|
||||
proto = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
|
||||
assert(proto);
|
||||
|
||||
|
||||
protoent = getprotobynumber(proto);
|
||||
if (protoent)
|
||||
return snprintf(buf, len, "%s", protoent->p_name);
|
||||
|
||||
/* Should not happen */
|
||||
/* Should not happen */
|
||||
return snprintf(buf, len, "%u", proto);
|
||||
}
|
||||
|
||||
@@ -511,7 +574,8 @@ ipset_print_icmp(char *buf, unsigned int len,
|
||||
if (name != NULL)
|
||||
return snprintf(buf, len, "%s", name);
|
||||
else
|
||||
return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF);
|
||||
return snprintf(buf, len, "%u/%u",
|
||||
typecode >> 8, typecode & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,7 +609,8 @@ ipset_print_icmpv6(char *buf, unsigned int len,
|
||||
if (name != NULL)
|
||||
return snprintf(buf, len, "%s", name);
|
||||
else
|
||||
return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF);
|
||||
return snprintf(buf, len, "%u/%u",
|
||||
typecode >> 8, typecode & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -574,8 +639,8 @@ ipset_print_proto_port(char *buf, unsigned int len,
|
||||
assert(opt == IPSET_OPT_PORT);
|
||||
|
||||
if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_PROTO))) {
|
||||
uint8_t proto = *(const uint8_t *) ipset_data_get(data,
|
||||
IPSET_OPT_PROTO);
|
||||
uint8_t proto = *(const uint8_t *) ipset_data_get(data,
|
||||
IPSET_OPT_PROTO);
|
||||
size = ipset_print_proto(buf, len, data, IPSET_OPT_PROTO, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
if (len < 2)
|
||||
@@ -601,16 +666,16 @@ ipset_print_proto_port(char *buf, unsigned int len,
|
||||
}
|
||||
size = ipset_print_port(buf + offset, len, data, IPSET_OPT_PORT, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
#define print_second(data) \
|
||||
ipset_data_flags_test(data, \
|
||||
IPSET_FLAG(IPSET_OPT_PORT)|IPSET_FLAG(IPSET_OPT_ETHER))
|
||||
IPSET_FLAG(IPSET_OPT_PORT)|IPSET_FLAG(IPSET_OPT_ETHER))
|
||||
|
||||
#define print_third(data) \
|
||||
ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_IP2))
|
||||
ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_IP2))
|
||||
|
||||
/**
|
||||
* ipset_print_elem - print ADT elem according to settype
|
||||
@@ -639,25 +704,25 @@ ipset_print_elem(char *buf, unsigned int len,
|
||||
type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
if (!type)
|
||||
return -1;
|
||||
|
||||
|
||||
size = type->elem[IPSET_DIM_ONE].print(buf, len, data,
|
||||
type->elem[IPSET_DIM_ONE].opt, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt),
|
||||
"print second elem");
|
||||
if (type->dimension == IPSET_DIM_ONE
|
||||
|| (type->last_elem_optional
|
||||
&& !ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
|
||||
if (type->dimension == IPSET_DIM_ONE ||
|
||||
(type->last_elem_optional &&
|
||||
!ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
|
||||
return offset;
|
||||
|
||||
|
||||
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
size = type->elem[IPSET_DIM_TWO].print(buf + offset, len, data,
|
||||
type->elem[IPSET_DIM_TWO].opt, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
if (type->dimension == IPSET_DIM_TWO
|
||||
|| (type->last_elem_optional
|
||||
&& !ipset_data_test(data, type->elem[IPSET_DIM_THREE].opt)))
|
||||
if (type->dimension == IPSET_DIM_TWO ||
|
||||
(type->last_elem_optional &&
|
||||
!ipset_data_test(data, type->elem[IPSET_DIM_THREE].opt)))
|
||||
return offset;
|
||||
|
||||
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
||||
@@ -685,7 +750,7 @@ int
|
||||
ipset_print_flag(char *buf UNUSED, unsigned int len UNUSED,
|
||||
const struct ipset_data *data UNUSED,
|
||||
enum ipset_opt opt UNUSED, uint8_t env UNUSED)
|
||||
{
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -731,6 +796,9 @@ ipset_print_data(char *buf, unsigned int len,
|
||||
case IPSET_OPT_PORT:
|
||||
size = ipset_print_port(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_IFACE:
|
||||
size = ipset_print_iface(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_GC:
|
||||
case IPSET_OPT_HASHSIZE:
|
||||
case IPSET_OPT_MAXELEM:
|
||||
@@ -747,6 +815,6 @@ ipset_print_data(char *buf, unsigned int len,
|
||||
return -1;
|
||||
}
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
@@ -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 */
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <string.h> /* str* */
|
||||
#include <unistd.h> /* getpagesize */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
@@ -199,14 +200,14 @@ ipset_session_output(struct ipset_session *session,
|
||||
*
|
||||
* Returns -1.
|
||||
*/
|
||||
int __attribute__((format(printf,3,4)))
|
||||
int __attribute__((format(printf, 3, 4)))
|
||||
ipset_session_report(struct ipset_session *session,
|
||||
enum ipset_err_type type,
|
||||
enum ipset_err_type type,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int len, offset = 0;
|
||||
va_list args;
|
||||
|
||||
|
||||
assert(session);
|
||||
assert(fmt);
|
||||
|
||||
@@ -215,13 +216,13 @@ ipset_session_report(struct ipset_session *session,
|
||||
session->lineno);
|
||||
}
|
||||
offset = strlen(session->report);
|
||||
|
||||
|
||||
va_start(args, fmt);
|
||||
len = vsnprintf(session->report + offset,
|
||||
IPSET_ERRORBUFLEN - 1 - offset,
|
||||
fmt, args);
|
||||
IPSET_ERRORBUFLEN - 1 - offset,
|
||||
fmt, args);
|
||||
va_end(args);
|
||||
|
||||
|
||||
if (len >= IPSET_ERRORBUFLEN - 1 - offset)
|
||||
session->report[IPSET_ERRORBUFLEN - 1] = '\0';
|
||||
if (strlen(session->report) < IPSET_ERRORBUFLEN - 1)
|
||||
@@ -475,6 +476,11 @@ static const struct ipset_attr_policy adt_attrs[] = {
|
||||
.type = MNL_TYPE_NESTED,
|
||||
.opt = IPSET_OPT_IP2_TO,
|
||||
},
|
||||
[IPSET_ATTR_IFACE] = {
|
||||
.type = MNL_TYPE_NUL_STRING,
|
||||
.opt = IPSET_OPT_IFACE,
|
||||
.len = IFNAMSIZ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ipset_attr_policy ipaddr_attrs[] = {
|
||||
@@ -497,7 +503,7 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
|
||||
{
|
||||
const struct nlattr **tb = data;
|
||||
int type = mnl_attr_get_type(attr);
|
||||
|
||||
|
||||
IF_D(debug, "attr type: %u, len %u", type, attr->nla_len);
|
||||
if (mnl_attr_type_valid(attr, attr_max) < 0) {
|
||||
IF_D(debug, "attr type: %u INVALID", type);
|
||||
@@ -508,9 +514,9 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
|
||||
mnl_attr_get_payload_len(attr));
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
if (policy[type].type == MNL_TYPE_NUL_STRING
|
||||
&& mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN)
|
||||
return MNL_CB_ERROR;
|
||||
if (policy[type].type == MNL_TYPE_NUL_STRING &&
|
||||
mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN)
|
||||
return MNL_CB_ERROR;
|
||||
tb[type] = attr;
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
@@ -594,7 +600,7 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
|
||||
switch (attr->type) {
|
||||
case MNL_TYPE_U32: {
|
||||
uint32_t value;
|
||||
|
||||
|
||||
value = ntohl(*(const uint32_t *)d);
|
||||
|
||||
d = &value;
|
||||
@@ -602,7 +608,7 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
|
||||
}
|
||||
case MNL_TYPE_U16: {
|
||||
uint16_t value;
|
||||
|
||||
|
||||
value = ntohs(*(const uint16_t *)d);
|
||||
|
||||
d = &value;
|
||||
@@ -613,15 +619,15 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
|
||||
}
|
||||
}
|
||||
#ifdef IPSET_DEBUG
|
||||
if (type == IPSET_ATTR_TYPENAME)
|
||||
if (type == IPSET_ATTR_TYPENAME)
|
||||
D("nla typename %s", (const char *) d);
|
||||
#endif
|
||||
ret = ipset_data_set(data, attr->opt, d);
|
||||
#ifdef IPSET_DEBUG
|
||||
if (type == IPSET_ATTR_TYPENAME)
|
||||
if (type == IPSET_ATTR_TYPENAME)
|
||||
D("nla typename %s",
|
||||
(const char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
|
||||
#endif
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -650,16 +656,16 @@ static inline int
|
||||
call_outfn(struct ipset_session *session)
|
||||
{
|
||||
int ret = session->outfn("%s", session->outbuf);
|
||||
|
||||
|
||||
session->outbuf[0] = '\0';
|
||||
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/* Handle printing failures */
|
||||
static jmp_buf printf_failure;
|
||||
|
||||
static int __attribute__((format(printf,2,3)))
|
||||
static int __attribute__((format(printf, 2, 3)))
|
||||
safe_snprintf(struct ipset_session *session, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -672,7 +678,7 @@ retry:
|
||||
ret = vsnprintf(session->outbuf + len, IPSET_OUTBUFLEN - len,
|
||||
fmt, args);
|
||||
va_end(args);
|
||||
|
||||
|
||||
if (ret < 0) {
|
||||
ipset_err(session,
|
||||
"Internal error at printing to output buffer");
|
||||
@@ -706,7 +712,7 @@ retry:
|
||||
D("len: %u, retry %u", len, loop);
|
||||
ret = fn(session->outbuf + len, IPSET_OUTBUFLEN - len,
|
||||
session->data, opt, session->envopts);
|
||||
|
||||
|
||||
if (ret < 0) {
|
||||
ipset_err(session,
|
||||
"Internal error at printing to output buffer");
|
||||
@@ -728,7 +734,7 @@ retry:
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
list_adt(struct ipset_session *session, struct nlattr *nla[])
|
||||
{
|
||||
@@ -738,7 +744,7 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
|
||||
uint8_t family;
|
||||
int i, found = 0;
|
||||
|
||||
D("enter");
|
||||
D("enter");
|
||||
/* Check and load type, family */
|
||||
if (!ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
type = ipset_type_get(session, IPSET_CMD_ADD);
|
||||
@@ -769,7 +775,7 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
safe_dprintf(session, ipset_print_elem, IPSET_OPT_ELEM);
|
||||
|
||||
for (arg = type->args[IPSET_ADD]; arg != NULL && arg->print; arg++) {
|
||||
@@ -800,7 +806,7 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (session->mode == IPSET_LIST_XML)
|
||||
safe_snprintf(session, "</member>\n");
|
||||
else
|
||||
@@ -859,10 +865,10 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
|
||||
}
|
||||
|
||||
for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->opt; arg++) {
|
||||
if (!arg->print
|
||||
|| !ipset_data_test(data, arg->opt)
|
||||
|| (arg->opt == IPSET_OPT_FAMILY
|
||||
&& family == type->family))
|
||||
if (!arg->print ||
|
||||
!ipset_data_test(data, arg->opt) ||
|
||||
(arg->opt == IPSET_OPT_FAMILY &&
|
||||
family == type->family))
|
||||
continue;
|
||||
switch (session->mode) {
|
||||
case IPSET_LIST_SAVE:
|
||||
@@ -975,15 +981,15 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
|
||||
if (STREQ(ipset_data_setname(data), session->saved_setname)) {
|
||||
/* Header part already seen */
|
||||
if (ipset_data_test(data, IPSET_OPT_TYPE)
|
||||
&& nla[IPSET_ATTR_DATA] != NULL)
|
||||
if (ipset_data_test(data, IPSET_OPT_TYPE) &&
|
||||
nla[IPSET_ATTR_DATA] != NULL)
|
||||
FAILURE("Broken %s kernel message: "
|
||||
"extra DATA received!", cmd2name[cmd]);
|
||||
} else {
|
||||
if (nla[IPSET_ATTR_DATA] == NULL)
|
||||
FAILURE("Broken %s kernel message: "
|
||||
"missing DATA part!", cmd2name[cmd]);
|
||||
|
||||
|
||||
/* Close previous set printing */
|
||||
if (session->saved_setname[0] != '\0')
|
||||
print_set_done(session);
|
||||
@@ -992,13 +998,14 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
if (nla[IPSET_ATTR_DATA] != NULL) {
|
||||
struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_FAMILY]
|
||||
&& nla[IPSET_ATTR_REVISION]))
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_FAMILY] &&
|
||||
nla[IPSET_ATTR_REVISION]))
|
||||
FAILURE("Broken %s kernel message: missing %s!",
|
||||
cmd2name[cmd],
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
!nla[IPSET_ATTR_FAMILY] ? "family" : "revision");
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
!nla[IPSET_ATTR_FAMILY] ? "family" :
|
||||
"revision");
|
||||
|
||||
/* Reset CREATE specific flags */
|
||||
ipset_data_flags_unset(data, IPSET_CREATE_FLAGS);
|
||||
@@ -1021,7 +1028,7 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
return MNL_CB_ERROR;
|
||||
strcpy(session->saved_setname, ipset_data_setname(data));
|
||||
}
|
||||
|
||||
|
||||
if (nla[IPSET_ATTR_ADT] != NULL) {
|
||||
struct nlattr *tb, *adt[IPSET_ATTR_ADT_MAX+1];
|
||||
|
||||
@@ -1053,7 +1060,7 @@ static int
|
||||
callback_version(struct ipset_session *session, struct nlattr *nla[])
|
||||
{
|
||||
uint8_t min, max;
|
||||
|
||||
|
||||
min = max = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
|
||||
|
||||
if (nla[IPSET_ATTR_PROTOCOL_MIN]) {
|
||||
@@ -1067,8 +1074,8 @@ callback_version(struct ipset_session *session, struct nlattr *nla[])
|
||||
"while userspace supports protocol versions %u-%u",
|
||||
min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
|
||||
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)
|
||||
&& max != IPSET_PROTOCOL_MAX)
|
||||
if (!(session->envopts & IPSET_ENV_QUIET) &&
|
||||
max != IPSET_PROTOCOL_MAX)
|
||||
ipset_warn(session,
|
||||
"Kernel support protocol versions %u-%u "
|
||||
"while userspace supports protocol versions %u-%u",
|
||||
@@ -1084,7 +1091,7 @@ callback_header(struct ipset_session *session, struct nlattr *nla[])
|
||||
{
|
||||
const char *setname;
|
||||
const struct ipset_data *data = session->data;
|
||||
|
||||
|
||||
if (!nla[IPSET_ATTR_SETNAME])
|
||||
FAILURE("Broken HEADER kernel message: missing setname!");
|
||||
|
||||
@@ -1093,10 +1100,10 @@ callback_header(struct ipset_session *session, struct nlattr *nla[])
|
||||
FAILURE("Broken HEADER kernel message: sent setname `%s' "
|
||||
"does not match with received one `%s'!",
|
||||
ipset_data_setname(data), setname);
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_REVISION]
|
||||
&& nla[IPSET_ATTR_FAMILY]))
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_REVISION] &&
|
||||
nla[IPSET_ATTR_FAMILY]))
|
||||
FAILURE("Broken HEADER kernel message: "
|
||||
"missing attribute '%s'!",
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
@@ -1116,10 +1123,10 @@ callback_type(struct ipset_session *session, struct nlattr *nla[])
|
||||
{
|
||||
const struct ipset_data *data = session->data;
|
||||
const char *typename, *orig;
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_REVISION]
|
||||
&& nla[IPSET_ATTR_FAMILY]))
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_REVISION] &&
|
||||
nla[IPSET_ATTR_FAMILY]))
|
||||
FAILURE("Broken TYPE kernel message: "
|
||||
"missing attribute '%s'!",
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
@@ -1132,7 +1139,7 @@ callback_type(struct ipset_session *session, struct nlattr *nla[])
|
||||
FAILURE("Broken TYPE kernel message: sent typename `%s' "
|
||||
"does not match with received one `%s'!",
|
||||
orig, typename);
|
||||
|
||||
|
||||
ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
|
||||
ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
|
||||
ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
|
||||
@@ -1156,7 +1163,7 @@ mnl_attr_parse_dbg(const struct nlmsghdr *nlh, int offset,
|
||||
int ret = MNL_CB_OK;
|
||||
struct nlattr *attr = mnl_nlmsg_get_payload_offset(nlh, offset);
|
||||
int len = nlh->nlmsg_len - MNL_NLMSG_HDRLEN - MNL_ALIGN(offset);
|
||||
|
||||
|
||||
while (mnl_attr_ok(attr, len)) {
|
||||
D("attr: type %u, attrlen %u, len %u",
|
||||
mnl_attr_get_type(attr), attr->nla_len, len);
|
||||
@@ -1175,7 +1182,7 @@ callback_data(const struct nlmsghdr *nlh, void *data)
|
||||
struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
|
||||
uint8_t proto, cmd;
|
||||
int ret = MNL_CB_OK, nfmsglen = MNL_ALIGN(sizeof(struct genlmsghdr));
|
||||
|
||||
|
||||
D("called, nlmsg_len %u", nlh->nlmsg_len);
|
||||
cmd = ipset_get_nlmsg_type(nlh);
|
||||
if (cmd == IPSET_CMD_LIST && session->cmd == IPSET_CMD_SAVE)
|
||||
@@ -1195,8 +1202,8 @@ callback_data(const struct nlmsghdr *nlh, void *data)
|
||||
|
||||
if (!nla[IPSET_ATTR_PROTOCOL])
|
||||
FAILURE("Sad, sad day: kernel message %s "
|
||||
"does not carry the protocol version.",
|
||||
cmd2name[cmd]);
|
||||
"does not carry the protocol version.",
|
||||
cmd2name[cmd]);
|
||||
|
||||
proto = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
|
||||
|
||||
@@ -1241,8 +1248,8 @@ callback_done(const struct nlmsghdr *nlh UNUSED, void *data)
|
||||
|
||||
D(" called");
|
||||
if (session->cmd == IPSET_CMD_LIST || session->cmd == IPSET_CMD_SAVE)
|
||||
return print_set_done(session);
|
||||
|
||||
return print_set_done(session);
|
||||
|
||||
FAILURE("Invalid message received in non LIST or SAVE state.");
|
||||
}
|
||||
|
||||
@@ -1254,7 +1261,7 @@ decode_errmsg(struct ipset_session *session, const struct nlmsghdr *nlh)
|
||||
struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
|
||||
enum ipset_cmd cmd;
|
||||
int nfmsglen = MNL_ALIGN(sizeof(struct genlmsghdr));
|
||||
|
||||
|
||||
if (nlh->nlmsg_len < (uint32_t) MNL_ALIGN(sizeof(struct nlmsgerr))
|
||||
|| nlh->nlmsg_len < MNL_ALIGN(sizeof(struct nlmsgerr))
|
||||
+ msg->nlmsg_len)
|
||||
@@ -1277,15 +1284,15 @@ decode_errmsg(struct ipset_session *session, const struct nlmsghdr *nlh)
|
||||
FAILURE("Broken %s error report message: "
|
||||
"missing protocol attribute",
|
||||
cmd2name[cmd]);
|
||||
|
||||
|
||||
if (nla[IPSET_ATTR_LINENO]) {
|
||||
session->lineno = mnl_attr_get_u32(nla[IPSET_ATTR_LINENO]);
|
||||
if (nla[IPSET_ATTR_LINENO]->nla_type & NLA_F_NET_BYTEORDER)
|
||||
session->lineno = ntohl(session->lineno);
|
||||
}
|
||||
|
||||
|
||||
return ipset_errcode(session, cmd, -err->error);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
@@ -1318,16 +1325,20 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
break;
|
||||
case IPSET_CMD_RENAME:
|
||||
ipset_cache_rename(ipset_data_setname(data),
|
||||
ipset_data_get(data, IPSET_OPT_SETNAME2));
|
||||
ipset_data_get(data,
|
||||
IPSET_OPT_SETNAME2));
|
||||
break;
|
||||
case IPSET_CMD_SWAP:
|
||||
ipset_cache_swap(ipset_data_setname(data),
|
||||
ipset_data_get(data, IPSET_OPT_SETNAME2));
|
||||
ipset_data_get(data,
|
||||
IPSET_OPT_SETNAME2));
|
||||
break;
|
||||
case IPSET_CMD_TEST:
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)) {
|
||||
ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
|
||||
session->data, IPSET_OPT_NONE, 0);
|
||||
ipset_print_elem(session->report,
|
||||
IPSET_ERRORBUFLEN,
|
||||
session->data,
|
||||
IPSET_OPT_NONE, 0);
|
||||
ipset_warn(session, " is in set %s.",
|
||||
ipset_data_setname(data));
|
||||
}
|
||||
@@ -1341,7 +1352,8 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
print_set_done(session);
|
||||
break;
|
||||
default:
|
||||
FAILURE("ACK message received to command %s[%u], which is not expected",
|
||||
FAILURE("ACK message received to command %s[%u], "
|
||||
"which is not expected",
|
||||
session->cmd < IPSET_MSG_MAX
|
||||
? cmd2name[session->cmd] : "unknown",
|
||||
session->cmd);
|
||||
@@ -1351,10 +1363,10 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
D("nlmsgerr error: %u", -err->error);
|
||||
|
||||
/* Error messages */
|
||||
|
||||
|
||||
/* Special case for IPSET_CMD_TEST */
|
||||
if (session->cmd == IPSET_CMD_TEST
|
||||
&& err->error == -IPSET_ERR_EXIST) {
|
||||
if (session->cmd == IPSET_CMD_TEST &&
|
||||
err->error == -IPSET_ERR_EXIST) {
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)) {
|
||||
ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
|
||||
session->data, IPSET_OPT_NONE, 0);
|
||||
@@ -1365,7 +1377,7 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
}
|
||||
|
||||
decode_errmsg(session, nlh);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1419,7 +1431,8 @@ attr_len(const struct ipset_attr_policy *attr, uint8_t family, uint16_t *flags)
|
||||
}
|
||||
|
||||
#define BUFFER_FULL(bufsize, nlmsg_len, nestlen, attrlen) \
|
||||
(nlmsg_len + nestlen + MNL_ATTR_HDRLEN + MNL_ALIGN(alen) + MNL_ALIGN(sizeof(struct nlmsgerr)) > bufsize)
|
||||
(nlmsg_len + nestlen + MNL_ATTR_HDRLEN + MNL_ALIGN(alen) + \
|
||||
MNL_ALIGN(sizeof(struct nlmsgerr)) > bufsize)
|
||||
|
||||
static int
|
||||
rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
@@ -1439,14 +1452,15 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
: IPSET_ATTR_IPADDR_IPV6;
|
||||
|
||||
alen = attr_len(attr, family, &flags);
|
||||
if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len, MNL_ATTR_HDRLEN, alen))
|
||||
if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len,
|
||||
MNL_ATTR_HDRLEN, alen))
|
||||
return 1;
|
||||
nested = mnl_attr_nest_start(nlh, type);
|
||||
D("family: %s", family == AF_INET ? "INET" :
|
||||
family == AF_INET6 ? "INET6" : "UNSPEC");
|
||||
mnl_attr_put(nlh, atype | flags, alen, d);
|
||||
mnl_attr_nest_end(nlh, nested);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1460,20 +1474,20 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
break;
|
||||
case MNL_TYPE_U32: {
|
||||
uint32_t value = htonl(*(const uint32_t *)d);
|
||||
|
||||
|
||||
d = &value;
|
||||
break;
|
||||
}
|
||||
case MNL_TYPE_U16: {
|
||||
uint16_t value = htons(*(const uint16_t *)d);
|
||||
|
||||
|
||||
d = &value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
mnl_attr_put(nlh, type | flags, alen, d);
|
||||
|
||||
return 0;
|
||||
@@ -1500,7 +1514,7 @@ data2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
data2attr(session, nlh, data, IPSET_ATTR_SETNAME, AF_INET, cmd_attrs)
|
||||
|
||||
#define ADDATTR_IF(session, nlh, data, type, family, attrs) \
|
||||
ipset_data_test(data, attrs[type].opt) ? \
|
||||
ipset_data_test(data, attrs[type].opt) ? \
|
||||
data2attr(session, nlh, data, type, family, attrs) : 0
|
||||
|
||||
#define ADDATTR_RAW(session, nlh, data, type, attrs) \
|
||||
@@ -1521,7 +1535,7 @@ addattr_adt(struct ipset_session *session,
|
||||
struct nlmsghdr *nlh, struct ipset_data *data, uint8_t family)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
|
||||
if (ADDATTR_IF(session, nlh, data, i, family, adt_attrs))
|
||||
return 1;
|
||||
@@ -1541,7 +1555,7 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
|
||||
/* Initialize header */
|
||||
session->transport->fill_hdr(session->handle, cmd, buffer, len, 0);
|
||||
|
||||
|
||||
ADDATTR_PROTOCOL(nlh);
|
||||
|
||||
switch (cmd) {
|
||||
@@ -1559,9 +1573,11 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
return ipset_err(session,
|
||||
"Invalid internal TYPE command: "
|
||||
"missing settype");
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME, AF_INET, cmd_attrs);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
|
||||
AF_INET, cmd_attrs);
|
||||
if (ipset_data_test(data, IPSET_OPT_FAMILY))
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
|
||||
AF_INET, cmd_attrs);
|
||||
else
|
||||
/* bitmap:port and list:set types */
|
||||
mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, AF_UNSPEC);
|
||||
@@ -1582,10 +1598,10 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
static inline bool
|
||||
may_aggregate_ad(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
{
|
||||
return session->lineno != 0
|
||||
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)
|
||||
&& cmd == session->cmd
|
||||
&& STREQ(ipset_data_setname(session->data), session->saved_setname);
|
||||
return session->lineno != 0 &&
|
||||
(cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL) &&
|
||||
cmd == session->cmd &&
|
||||
STREQ(ipset_data_setname(session->data), session->saved_setname);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1618,12 +1634,13 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
if (!ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
return ipset_err(session,
|
||||
"Invalid create command: missing settype");
|
||||
|
||||
|
||||
type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
/* Core attributes:
|
||||
* setname, typename, revision, family, flags (optional) */
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME, AF_INET, cmd_attrs);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
|
||||
AF_INET, cmd_attrs);
|
||||
ADDATTR_RAW(session, nlh, &type->revision,
|
||||
IPSET_ATTR_REVISION, cmd_attrs);
|
||||
D("family: %u, type family %u",
|
||||
@@ -1651,7 +1668,7 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
break;
|
||||
case IPSET_CMD_LIST: {
|
||||
uint32_t flags = 0;
|
||||
|
||||
|
||||
if (session->envopts & IPSET_ENV_LIST_SETNAME)
|
||||
flags |= IPSET_FLAG_LIST_SETNAME;
|
||||
if (session->envopts & IPSET_ENV_LIST_HEADER)
|
||||
@@ -1670,13 +1687,16 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
if (!ipset_data_test(data, IPSET_SETNAME))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing from-setname",
|
||||
session->cmd == IPSET_CMD_SWAP ? "swap" : "rename");
|
||||
session->cmd == IPSET_CMD_SWAP ? "swap" :
|
||||
"rename");
|
||||
if (!ipset_data_test(data, IPSET_OPT_SETNAME2))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing to-setname",
|
||||
session->cmd == IPSET_CMD_SWAP ? "swap" : "rename");
|
||||
session->cmd == IPSET_CMD_SWAP ? "swap" :
|
||||
"rename");
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
ADDATTR_RAW(session, nlh, ipset_data_get(data, IPSET_OPT_SETNAME2),
|
||||
ADDATTR_RAW(session, nlh,
|
||||
ipset_data_get(data, IPSET_OPT_SETNAME2),
|
||||
IPSET_ATTR_SETNAME2, cmd_attrs);
|
||||
break;
|
||||
case IPSET_CMD_ADD:
|
||||
@@ -1688,12 +1708,14 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
if (!ipset_data_test(data, IPSET_SETNAME))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing setname",
|
||||
session->cmd == IPSET_CMD_ADD ? "add" : "del");
|
||||
session->cmd == IPSET_CMD_ADD ? "add" :
|
||||
"del");
|
||||
|
||||
if (!ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing settype",
|
||||
session->cmd == IPSET_CMD_ADD ? "add" : "del");
|
||||
session->cmd == IPSET_CMD_ADD ? "add" :
|
||||
"del");
|
||||
|
||||
/* Core options: setname */
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
@@ -1711,11 +1733,12 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
D("open_nested failed");
|
||||
return 1;
|
||||
}
|
||||
if (addattr_adt(session, nlh, data, ipset_data_family(data))
|
||||
|| ADDATTR_RAW(session, nlh, &session->lineno,
|
||||
IPSET_ATTR_LINENO, cmd_attrs)) {
|
||||
if (addattr_adt(session, nlh, data, ipset_data_family(data)) ||
|
||||
ADDATTR_RAW(session, nlh, &session->lineno,
|
||||
IPSET_ATTR_LINENO, cmd_attrs)) {
|
||||
/* Cancel last, unfinished nested attribute */
|
||||
mnl_attr_nest_cancel(nlh, session->nested[session->nestid-1]);
|
||||
mnl_attr_nest_cancel(nlh,
|
||||
session->nested[session->nestid-1]);
|
||||
session->nested[--session->nestid] = NULL;
|
||||
return 1;
|
||||
}
|
||||
@@ -1727,7 +1750,7 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
/* Return codes are not aggregated, so tests cannot be either */
|
||||
|
||||
/* Setname, type not checked/added yet */
|
||||
|
||||
|
||||
if (!ipset_data_test(data, IPSET_SETNAME))
|
||||
return ipset_err(session,
|
||||
"Invalid test command: missing setname");
|
||||
@@ -1735,7 +1758,7 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
if (!ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
return ipset_err(session,
|
||||
"Invalid test command: missing settype");
|
||||
|
||||
|
||||
type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
D("family: %u, type family %u",
|
||||
ipset_data_family(data), type->family);
|
||||
@@ -1769,7 +1792,8 @@ ipset_commit(struct ipset_session *session)
|
||||
assert(session);
|
||||
|
||||
nlh = session->buffer;
|
||||
D("send buffer: len %u, cmd %s", nlh->nlmsg_len, cmd2name[session->cmd]);
|
||||
D("send buffer: len %u, cmd %s",
|
||||
nlh->nlmsg_len, cmd2name[session->cmd]);
|
||||
if (nlh->nlmsg_len == 0)
|
||||
/* Nothing to do */
|
||||
return 0;
|
||||
@@ -1798,7 +1822,7 @@ ipset_commit(struct ipset_session *session)
|
||||
return -1;
|
||||
else
|
||||
return ipset_err(session,
|
||||
"Internal protocol error");
|
||||
"Internal protocol error");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1810,7 +1834,7 @@ static mnl_cb_t cb_ctl[] = {
|
||||
[NLMSG_OVERRUN] = callback_noop,
|
||||
[NLMSG_MIN_TYPE] = callback_data,
|
||||
};
|
||||
|
||||
|
||||
static inline struct ipset_handle *
|
||||
init_transport(struct ipset_session *session)
|
||||
{
|
||||
@@ -1839,7 +1863,7 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
struct ipset_data *data;
|
||||
bool aggregate = false;
|
||||
int ret = -1;
|
||||
|
||||
|
||||
assert(session);
|
||||
|
||||
if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_MSG_MAX)
|
||||
@@ -1859,9 +1883,9 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
}
|
||||
|
||||
/* Private commands */
|
||||
if (cmd == IPSET_CMD_TYPE || cmd == IPSET_CMD_HEADER)
|
||||
if (cmd == IPSET_CMD_TYPE || cmd == IPSET_CMD_HEADER)
|
||||
return build_send_private_msg(session, cmd);
|
||||
|
||||
|
||||
/* Check aggregatable commands */
|
||||
aggregate = may_aggregate_ad(session, cmd);
|
||||
if (!aggregate) {
|
||||
@@ -1874,7 +1898,7 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
/* Real command: update lineno too */
|
||||
session->cmd = cmd;
|
||||
session->lineno = lineno;
|
||||
|
||||
|
||||
/* Set default output mode */
|
||||
if (cmd == IPSET_CMD_LIST) {
|
||||
if (session->mode == IPSET_LIST_NONE)
|
||||
@@ -1902,8 +1926,8 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
|
||||
/* We have to save the type for error handling */
|
||||
session->saved_type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
if (session->lineno != 0
|
||||
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
|
||||
if (session->lineno != 0 &&
|
||||
(cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
|
||||
/* Save setname for the next possible aggregated restore line */
|
||||
strcpy(session->saved_setname, ipset_data_setname(data));
|
||||
ipset_data_reset(data);
|
||||
@@ -1912,7 +1936,7 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
D("call commit");
|
||||
D("call commit");
|
||||
ret = ipset_commit(session);
|
||||
|
||||
cleanup:
|
||||
@@ -1944,10 +1968,10 @@ ipset_session_init(ipset_outfn outfn)
|
||||
|
||||
/* The single transport method yet */
|
||||
session->transport = &ipset_mnl_transport;
|
||||
|
||||
|
||||
/* Output function */
|
||||
session->outfn = outfn;
|
||||
|
||||
|
||||
/* Initialize data structures */
|
||||
session->data = ipset_data_init();
|
||||
if (session->data == NULL)
|
||||
@@ -1957,8 +1981,8 @@ ipset_session_init(ipset_outfn outfn)
|
||||
return session;
|
||||
|
||||
free_session:
|
||||
free(session);
|
||||
return NULL;
|
||||
free(session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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 */
|
||||
@@ -28,8 +28,8 @@ struct ipset {
|
||||
struct ipset *next;
|
||||
};
|
||||
|
||||
static struct ipset_type *typelist = NULL; /* registered set types */
|
||||
static struct ipset *setlist = NULL; /* cached sets */
|
||||
static struct ipset_type *typelist; /* registered set types */
|
||||
static struct ipset *setlist; /* cached sets */
|
||||
|
||||
/**
|
||||
* ipset_cache_add - add a set to the cache
|
||||
@@ -57,7 +57,7 @@ ipset_cache_add(const char *name, const struct ipset_type *type,
|
||||
ipset_strlcpy(n->name, name, IPSET_MAXNAMELEN);
|
||||
n->type = type;
|
||||
n->family = family;
|
||||
n->next = NULL;
|
||||
n->next = NULL;
|
||||
|
||||
if (setlist == NULL) {
|
||||
setlist = n;
|
||||
@@ -109,7 +109,7 @@ ipset_cache_del(const char *name)
|
||||
}
|
||||
if (match == NULL)
|
||||
return -EEXIST;
|
||||
|
||||
|
||||
free(match);
|
||||
return 0;
|
||||
}
|
||||
@@ -168,7 +168,7 @@ ipset_cache_swap(const char *from, const char *to)
|
||||
ipset_strlcpy(b->name, from, IPSET_MAXNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ ipset_cache_swap(const char *from, const char *to)
|
||||
bool
|
||||
ipset_match_typename(const char *name, const struct ipset_type *type)
|
||||
{
|
||||
const char * const * alias = type->alias;
|
||||
const char * const *alias = type->alias;
|
||||
|
||||
if (STREQ(name, type->name))
|
||||
return true;
|
||||
@@ -189,7 +189,7 @@ ipset_match_typename(const char *name, const struct ipset_type *type)
|
||||
alias++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline const struct ipset_type *
|
||||
create_type_get(struct ipset_session *session)
|
||||
@@ -215,17 +215,17 @@ create_type_get(struct ipset_session *session)
|
||||
if (ipset_match_typename(typename, t)
|
||||
&& MATCH_FAMILY(t, family)) {
|
||||
if (match == NULL) {
|
||||
match = t;
|
||||
tmin = tmax = t->revision;
|
||||
match = t;
|
||||
tmin = tmax = t->revision;
|
||||
} else if (t->family == match->family)
|
||||
tmin = t->revision;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
return ipset_errptr(session,
|
||||
"Syntax error: unknown settype %s",
|
||||
typename);
|
||||
|
||||
|
||||
/* Family is unspecified yet: set from matching set type */
|
||||
if (family == AF_UNSPEC && match->family != AF_UNSPEC) {
|
||||
family = match->family == AF_INET46 ? AF_INET : match->family;
|
||||
@@ -240,9 +240,11 @@ create_type_get(struct ipset_session *session)
|
||||
if (ret != 0)
|
||||
return NULL;
|
||||
|
||||
kmin = kmax = *(const uint8_t *)ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
kmin = kmax = *(const uint8_t *)ipset_data_get(data,
|
||||
IPSET_OPT_REVISION);
|
||||
if (ipset_data_test(data, IPSET_OPT_REVISION_MIN))
|
||||
kmin = *(const uint8_t *)ipset_data_get(data, IPSET_OPT_REVISION_MIN);
|
||||
kmin = *(const uint8_t *)ipset_data_get(data,
|
||||
IPSET_OPT_REVISION_MIN);
|
||||
|
||||
if (MAX(tmin, kmin) > MIN(tmax, kmax)) {
|
||||
if (kmin > tmax)
|
||||
@@ -266,7 +268,7 @@ create_type_get(struct ipset_session *session)
|
||||
family == AF_INET6 ? "INET6" : "UNSPEC",
|
||||
kmax, tmin);
|
||||
}
|
||||
|
||||
|
||||
/* Disable unsupported revisions */
|
||||
for (match = NULL, t = typelist; t != NULL; t = t->next) {
|
||||
/* Skip revisions which are unsupported by the kernel */
|
||||
@@ -274,16 +276,16 @@ create_type_get(struct ipset_session *session)
|
||||
continue;
|
||||
if (ipset_match_typename(typename, t)
|
||||
&& MATCH_FAMILY(t, family)) {
|
||||
if (t->revision < kmin || t->revision > kmax)
|
||||
t->kernel_check = IPSET_KERNEL_MISMATCH;
|
||||
if (t->revision < kmin || t->revision > kmax)
|
||||
t->kernel_check = IPSET_KERNEL_MISMATCH;
|
||||
else if (match == NULL)
|
||||
match = t;
|
||||
}
|
||||
match = t;
|
||||
}
|
||||
}
|
||||
match->kernel_check = IPSET_KERNEL_OK;
|
||||
found:
|
||||
ipset_data_set(data, IPSET_OPT_TYPE, match);
|
||||
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
@@ -327,7 +329,7 @@ adt_type_get(struct ipset_session *session)
|
||||
return NULL;
|
||||
|
||||
typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
|
||||
revision = ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
revision = ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
family = ipset_data_family(data);
|
||||
|
||||
/* Check registered types */
|
||||
@@ -542,7 +544,7 @@ void
|
||||
ipset_cache_fini(void)
|
||||
{
|
||||
struct ipset *set;
|
||||
|
||||
|
||||
while (setlist) {
|
||||
set = setlist;
|
||||
setlist = setlist->next;
|
||||
|
Reference in New Issue
Block a user