mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-20 19:44:56 +02:00
ipset: fast forward to v4.0
This commit is contained in:
@@ -30,11 +30,15 @@
|
||||
#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
|
||||
#endif
|
||||
|
||||
#define IPSET_VERSION "3.2"
|
||||
#define IPSET_VERSION "4.0"
|
||||
|
||||
char program_name[] = "ipset";
|
||||
char program_version[] = IPSET_VERSION;
|
||||
const char *ipset_libdir = IPSET_LIB_DIR;
|
||||
static int protocol_version = 0;
|
||||
|
||||
#define STREQ(a,b) (strncmp(a,b,IP_SET_MAXNAMELEN) == 0)
|
||||
#define DONT_ALIGN (protocol_version == IP_SET_PROTOCOL_UNALIGNED)
|
||||
#define ALIGNED(len) IPSET_VALIGN(len, DONT_ALIGN)
|
||||
|
||||
/* The list of loaded set types */
|
||||
static struct settype *all_settypes = NULL;
|
||||
@@ -68,7 +72,7 @@ static unsigned int global_option_offset = 0;
|
||||
|
||||
static const char cmdflags[] = { ' ', /* CMD_NONE */
|
||||
'N', 'X', 'F', 'E', 'W', 'L', 'S', 'R',
|
||||
'A', 'D', 'T', 'B', 'U', 'H', 'V',
|
||||
'A', 'D', 'T', 'H', 'V',
|
||||
};
|
||||
|
||||
/* Options */
|
||||
@@ -77,11 +81,10 @@ static const char cmdflags[] = { ' ', /* CMD_NONE */
|
||||
#define OPT_SORTED 0x0002U /* -s */
|
||||
#define OPT_QUIET 0x0004U /* -q */
|
||||
#define OPT_DEBUG 0x0008U /* -z */
|
||||
#define OPT_BINDING 0x0010U /* -b */
|
||||
#define OPT_RESOLVE 0x0020U /* -r */
|
||||
#define NUMBER_OF_OPT 6
|
||||
#define NUMBER_OF_OPT 5
|
||||
static const char optflags[] =
|
||||
{ 'n', 's', 'q', 'z', 'b', 'r' };
|
||||
{ 'n', 's', 'q', 'z', 'r' };
|
||||
|
||||
static struct option opts_long[] = {
|
||||
/* set operations */
|
||||
@@ -100,15 +103,10 @@ static struct option opts_long[] = {
|
||||
{"del", 1, 0, 'D'},
|
||||
{"test", 1, 0, 'T'},
|
||||
|
||||
/* binding operations */
|
||||
{"bind", 1, 0, 'B'},
|
||||
{"unbind", 1, 0, 'U'},
|
||||
|
||||
/* free options */
|
||||
{"numeric", 0, 0, 'n'},
|
||||
{"sorted", 0, 0, 's'},
|
||||
{"quiet", 0, 0, 'q'},
|
||||
{"binding", 1, 0, 'b'},
|
||||
{"resolve", 0, 0, 'r'},
|
||||
|
||||
#ifdef IPSET_DEBUG
|
||||
@@ -125,7 +123,7 @@ static struct option opts_long[] = {
|
||||
};
|
||||
|
||||
static char opts_short[] =
|
||||
"-N:X::F::E:W:L::S::RA:D:T:B:U:nrsqzb:Vh::H::";
|
||||
"-N:X::F::E:W:L::S::RA:D:T:nrsqzvVh::H::";
|
||||
|
||||
/* Table of legal combinations of commands and options. If any of the
|
||||
* given commands make an option legal, that option is legal.
|
||||
@@ -136,22 +134,20 @@ static char opts_short[] =
|
||||
*/
|
||||
|
||||
static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = {
|
||||
/* -n -s -q -z -b */
|
||||
/*CREATE*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*DESTROY*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*FLUSH*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*RENAME*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*SWAP*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*LIST*/ {' ', ' ', 'x', ' ', 'x', ' '},
|
||||
/*SAVE*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*RESTORE*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*ADD*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*DEL*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*TEST*/ {'x', 'x', ' ', ' ', ' ', 'x'},
|
||||
/*BIND*/ {'x', 'x', ' ', ' ', '+', 'x'},
|
||||
/*UNBIND*/ {'x', 'x', ' ', ' ', 'x', 'x'},
|
||||
/*HELP*/ {'x', 'x', 'x', ' ', 'x', 'x'},
|
||||
/*VERSION*/ {'x', 'x', 'x', ' ', 'x', 'x'},
|
||||
/* -n -s -q -z -r */
|
||||
/*CREATE*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*DESTROY*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*FLUSH*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*RENAME*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*SWAP*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*LIST*/ {' ', ' ', 'x', ' ', ' '},
|
||||
/*SAVE*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*RESTORE*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*ADD*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*DEL*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*TEST*/ {'x', 'x', ' ', ' ', 'x'},
|
||||
/*HELP*/ {'x', 'x', 'x', ' ', 'x'},
|
||||
/*VERSION*/ {'x', 'x', 'x', ' ', 'x'},
|
||||
};
|
||||
|
||||
/* Main parser function */
|
||||
@@ -454,25 +450,26 @@ static void check_protocolversion(void)
|
||||
{
|
||||
struct ip_set_req_version req_version;
|
||||
socklen_t size = sizeof(struct ip_set_req_version);
|
||||
int sockfd = kernel_getsocket();
|
||||
int res;
|
||||
|
||||
req_version.op = IP_SET_OP_VERSION;
|
||||
res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size);
|
||||
|
||||
if (res != 0) {
|
||||
ipset_printf("I'm of protocol version %u.\n"
|
||||
"Kernel module is not loaded in, "
|
||||
"cannot verify kernel version.",
|
||||
IP_SET_PROTOCOL_VERSION);
|
||||
if (protocol_version)
|
||||
return;
|
||||
}
|
||||
if (req_version.version != IP_SET_PROTOCOL_VERSION)
|
||||
|
||||
req_version.op = IP_SET_OP_VERSION;
|
||||
res = wrapped_getsockopt(&req_version, &size);
|
||||
|
||||
if (res != 0)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Kernel ipset code is of protocol version %u."
|
||||
"Couldn't verify kernel module version!");
|
||||
|
||||
if (!(req_version.version == IP_SET_PROTOCOL_VERSION
|
||||
|| req_version.version == IP_SET_PROTOCOL_UNALIGNED))
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Kernel ip_set module is of protocol version %u."
|
||||
"I'm of protocol version %u.\n"
|
||||
"Please upgrade your kernel and/or ipset(8) utillity.",
|
||||
req_version.version, IP_SET_PROTOCOL_VERSION);
|
||||
protocol_version = req_version.version;
|
||||
}
|
||||
|
||||
static void set_command(int *cmd, int newcmd)
|
||||
@@ -594,11 +591,6 @@ char *ip_tostring(ip_set_ip_t ip, unsigned options)
|
||||
return inet_ntoa(addr);
|
||||
}
|
||||
|
||||
char *binding_ip_tostring(struct set *set UNUSED,
|
||||
ip_set_ip_t ip, unsigned options)
|
||||
{
|
||||
return ip_tostring(ip, options);
|
||||
}
|
||||
char *ip_tostring_numeric(ip_set_ip_t ip)
|
||||
{
|
||||
return ip_tostring(ip, OPT_NUMERIC);
|
||||
@@ -763,8 +755,7 @@ static struct settype *settype_find(const char *typename)
|
||||
DP("%s", typename);
|
||||
|
||||
while (runner != NULL) {
|
||||
if (strncmp(runner->typename, typename,
|
||||
IP_SET_MAXNAMELEN) == 0)
|
||||
if (STREQ(runner->typename, typename))
|
||||
return runner;
|
||||
|
||||
runner = runner->next;
|
||||
@@ -886,9 +877,7 @@ struct set *set_find_byname(const char *name)
|
||||
ip_set_id_t i;
|
||||
|
||||
for (i = 0; i < max_sets; i++)
|
||||
if (set_list[i]
|
||||
&& strncmp(set_list[i]->name, name,
|
||||
IP_SET_MAXNAMELEN) == 0) {
|
||||
if (set_list[i] != NULL && STREQ(set_list[i]->name, name)) {
|
||||
set = set_list[i];
|
||||
break;
|
||||
}
|
||||
@@ -906,9 +895,7 @@ static ip_set_id_t set_find_free_index(const char *name)
|
||||
if (idx == IP_SET_INVALID_ID
|
||||
&& set_list[i] == NULL)
|
||||
idx = i;
|
||||
if (set_list[i] != NULL
|
||||
&& strncmp(set_list[i]->name, name,
|
||||
IP_SET_MAXNAMELEN) == 0)
|
||||
if (set_list[i] != NULL && STREQ(set_list[i]->name, name))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Set %s is already defined, cannot be restored",
|
||||
name);
|
||||
@@ -935,7 +922,7 @@ static void set_create(const char *name, struct settype *settype)
|
||||
DP("%s %s", name, settype->typename);
|
||||
|
||||
req_create.op = IP_SET_OP_CREATE;
|
||||
req_create.version = IP_SET_PROTOCOL_VERSION;
|
||||
req_create.version = protocol_version;
|
||||
strcpy(req_create.name, name);
|
||||
strcpy(req_create.typename, settype->typename);
|
||||
|
||||
@@ -959,14 +946,14 @@ static void set_restore_create(const char *name, struct settype *settype)
|
||||
{
|
||||
struct set *set;
|
||||
|
||||
DP("%s %s %u %u %u %u", name, settype->typename,
|
||||
DP("%s %s %zu %zu %u %u", name, settype->typename,
|
||||
restore_offset, sizeof(struct ip_set_restore),
|
||||
settype->create_size, restore_size);
|
||||
|
||||
/* Sanity checking */
|
||||
if (restore_offset
|
||||
+ sizeof(struct ip_set_restore)
|
||||
+ settype->create_size > restore_size)
|
||||
+ ALIGNED(sizeof(struct ip_set_restore))
|
||||
+ ALIGNED(settype->create_size) > restore_size)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Giving up, restore file is screwed up!");
|
||||
|
||||
@@ -985,11 +972,11 @@ static void set_restore_create(const char *name, struct settype *settype)
|
||||
DP("name %s, restore index %u", restore_set->name, restore_set->index);
|
||||
/* Add settype data */
|
||||
|
||||
memcpy(restore_data + restore_offset + sizeof(struct ip_set_restore),
|
||||
settype->data, settype->create_size);
|
||||
restore_offset += ALIGNED(sizeof(struct ip_set_restore));
|
||||
memcpy(restore_data + restore_offset, settype->data, settype->create_size);
|
||||
|
||||
restore_offset += sizeof(struct ip_set_restore)
|
||||
+ settype->create_size;
|
||||
restore_offset += ALIGNED(settype->create_size);
|
||||
DP("restore_offset: %zu", restore_offset);
|
||||
|
||||
/* Add set to set_list */
|
||||
set = ipset_malloc(sizeof(struct set));
|
||||
@@ -1009,7 +996,7 @@ static void set_destroy(const char *name, unsigned op, unsigned cmd)
|
||||
DP("%s %s", cmd == CMD_DESTROY ? "destroy" : "flush", name);
|
||||
|
||||
req.op = op;
|
||||
req.version = IP_SET_PROTOCOL_VERSION;
|
||||
req.version = protocol_version;
|
||||
strcpy(req.name, name);
|
||||
|
||||
kernel_sendto(cmd, &req, sizeof(struct ip_set_req_std));
|
||||
@@ -1027,7 +1014,7 @@ static void set_rename(const char *name, const char *newname,
|
||||
name, newname);
|
||||
|
||||
req.op = op;
|
||||
req.version = IP_SET_PROTOCOL_VERSION;
|
||||
req.version = protocol_version;
|
||||
strcpy(req.name, name);
|
||||
strcpy(req.typename, newname);
|
||||
|
||||
@@ -1065,7 +1052,7 @@ tryagain:
|
||||
}
|
||||
/* Get max_sets */
|
||||
req_max_sets.op = IP_SET_OP_MAX_SETS;
|
||||
req_max_sets.version = IP_SET_PROTOCOL_VERSION;
|
||||
req_max_sets.version = protocol_version;
|
||||
strcpy(req_max_sets.set.name, name);
|
||||
size = sizeof(req_max_sets);
|
||||
kernel_getfrom(CMD_MAX_SETS, &req_max_sets, &size);
|
||||
@@ -1083,8 +1070,8 @@ tryagain:
|
||||
return 0;
|
||||
|
||||
/* Get setnames */
|
||||
size = req_size = sizeof(struct ip_set_req_setnames)
|
||||
+ req_max_sets.sets * sizeof(struct ip_set_name_list);
|
||||
size = req_size = ALIGNED(sizeof(struct ip_set_req_setnames))
|
||||
+ req_max_sets.sets * ALIGNED(sizeof(struct ip_set_name_list));
|
||||
data = ipset_malloc(size);
|
||||
((struct ip_set_req_setnames *) data)->op = op;
|
||||
((struct ip_set_req_setnames *) data)->index = *idx;
|
||||
@@ -1102,8 +1089,8 @@ tryagain:
|
||||
}
|
||||
|
||||
/* Load in setnames */
|
||||
size = sizeof(struct ip_set_req_setnames);
|
||||
while (size + sizeof(struct ip_set_name_list) <= req_size) {
|
||||
size = ALIGNED(sizeof(struct ip_set_req_setnames));
|
||||
while (size + ALIGNED(sizeof(struct ip_set_name_list)) <= req_size) {
|
||||
name_list = (struct ip_set_name_list *)
|
||||
(data + size);
|
||||
set = ipset_malloc(sizeof(struct set));
|
||||
@@ -1114,9 +1101,9 @@ tryagain:
|
||||
set_list[name_list->index] = set;
|
||||
DP("loaded %s, type %s, index %u",
|
||||
set->name, set->settype->typename, set->index);
|
||||
size += sizeof(struct ip_set_name_list);
|
||||
size += ALIGNED(sizeof(struct ip_set_name_list));
|
||||
}
|
||||
/* Size to get set members, bindings */
|
||||
/* Size to get set members */
|
||||
size = ((struct ip_set_req_setnames *)data)->size;
|
||||
free(data);
|
||||
|
||||
@@ -1126,36 +1113,7 @@ tryagain:
|
||||
/*
|
||||
* Save operation
|
||||
*/
|
||||
static size_t save_bindings(void *data, size_t offset, size_t len)
|
||||
{
|
||||
struct ip_set_hash_save *hash =
|
||||
(struct ip_set_hash_save *) (data + offset);
|
||||
struct set *set;
|
||||
|
||||
DP("offset %u, len %u", offset, len);
|
||||
if (offset + sizeof(struct ip_set_hash_save) > len)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Save operation failed, try again later.");
|
||||
|
||||
set = set_find_byid(hash->id);
|
||||
if (!(set && set_list[hash->binding]))
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Save binding failed, try again later.");
|
||||
if (!set->settype->bindip_tostring)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Internal error, binding is not supported with set %s"
|
||||
" of settype %s\n",
|
||||
set->name, set->settype->typename);
|
||||
printf("-B %s %s -b %s\n",
|
||||
set->name,
|
||||
set->settype->bindip_tostring(set, hash->ip, OPT_NUMERIC),
|
||||
set_list[hash->binding]->name);
|
||||
|
||||
return sizeof(struct ip_set_hash_save);
|
||||
}
|
||||
|
||||
static size_t save_set(void *data, int *bindings,
|
||||
size_t offset, size_t len)
|
||||
static size_t save_set(void *data, size_t offset, size_t len)
|
||||
{
|
||||
struct ip_set_save *set_save =
|
||||
(struct ip_set_save *) (data + offset);
|
||||
@@ -1163,12 +1121,12 @@ static size_t save_set(void *data, int *bindings,
|
||||
struct settype *settype;
|
||||
size_t used;
|
||||
|
||||
DP("offset %u (%u/%u/%u), len %u", offset,
|
||||
DP("offset %zu (%zu/%u/%u), len %zu", offset,
|
||||
sizeof(struct ip_set_save),
|
||||
set_save->header_size, set_save->members_size,
|
||||
len);
|
||||
if (offset + sizeof(struct ip_set_save) > len
|
||||
|| offset + sizeof(struct ip_set_save)
|
||||
if (offset + ALIGNED(sizeof(struct ip_set_save)) > len
|
||||
|| offset + ALIGNED(sizeof(struct ip_set_save))
|
||||
+ set_save->header_size + set_save->members_size > len)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Save operation failed, try again later.");
|
||||
@@ -1176,8 +1134,7 @@ static size_t save_set(void *data, int *bindings,
|
||||
DP("index: %u", set_save->index);
|
||||
if (set_save->index == IP_SET_INVALID_ID) {
|
||||
/* Marker */
|
||||
*bindings = 1;
|
||||
return sizeof(struct ip_set_save);
|
||||
return ALIGNED(sizeof(struct ip_set_save));
|
||||
}
|
||||
set = set_list[set_save->index];
|
||||
if (!set)
|
||||
@@ -1186,7 +1143,7 @@ static size_t save_set(void *data, int *bindings,
|
||||
settype = set->settype;
|
||||
|
||||
/* Init set header */
|
||||
used = sizeof(struct ip_set_save);
|
||||
used = ALIGNED(sizeof(struct ip_set_save));
|
||||
settype->initheader(set, data + offset + used);
|
||||
|
||||
/* Print create set */
|
||||
@@ -1195,44 +1152,18 @@ static size_t save_set(void *data, int *bindings,
|
||||
/* Print add IPs */
|
||||
used += set_save->header_size;
|
||||
settype->saveips(set, data + offset + used,
|
||||
set_save->members_size, OPT_NUMERIC);
|
||||
set_save->members_size, OPT_NUMERIC,
|
||||
DONT_ALIGN);
|
||||
|
||||
return (used + set_save->members_size);
|
||||
}
|
||||
|
||||
static size_t save_default_bindings(void *data, int *bindings)
|
||||
{
|
||||
struct ip_set_save *set_save = (struct ip_set_save *) data;
|
||||
struct set *set;
|
||||
|
||||
if (set_save->index == IP_SET_INVALID_ID) {
|
||||
/* Marker */
|
||||
*bindings = 1;
|
||||
return sizeof(struct ip_set_save);
|
||||
}
|
||||
|
||||
set = set_list[set_save->index];
|
||||
DP("%s, binding %u", set->name, set_save->binding);
|
||||
if (set_save->binding != IP_SET_INVALID_ID) {
|
||||
if (!set_list[set_save->binding])
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Save set failed, try again later.");
|
||||
|
||||
printf("-B %s %s -b %s\n",
|
||||
set->name, IPSET_TOKEN_DEFAULT,
|
||||
set_list[set_save->binding]->name);
|
||||
}
|
||||
return (sizeof(struct ip_set_save)
|
||||
+ set_save->header_size
|
||||
+ set_save->members_size);
|
||||
}
|
||||
|
||||
static int try_save_sets(const char name[IP_SET_MAXNAMELEN])
|
||||
{
|
||||
void *data = NULL;
|
||||
socklen_t size, req_size = 0;
|
||||
ip_set_id_t idx;
|
||||
int res = 0, bindings = 0;
|
||||
int res = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
/* Load set_list from kernel */
|
||||
@@ -1240,15 +1171,17 @@ static int try_save_sets(const char name[IP_SET_MAXNAMELEN])
|
||||
IP_SET_OP_SAVE_SIZE, CMD_SAVE);
|
||||
|
||||
if (size) {
|
||||
/* Get sets, bindings and print them */
|
||||
/* Get sets and print them */
|
||||
/* Take into account marker */
|
||||
req_size = (size += sizeof(struct ip_set_save));
|
||||
req_size = (size += ALIGNED(sizeof(struct ip_set_save)));
|
||||
data = ipset_malloc(size);
|
||||
((struct ip_set_req_list *) data)->op = IP_SET_OP_SAVE;
|
||||
((struct ip_set_req_list *) data)->index = idx;
|
||||
res = kernel_getfrom_handleerrno(CMD_SAVE, data, &size);
|
||||
|
||||
if (res != 0 || size != req_size) {
|
||||
DP("Try again: res: %i, size %u, req_size: %u",
|
||||
res, size, req_size);
|
||||
free(data);
|
||||
return -EAGAIN;
|
||||
}
|
||||
@@ -1258,17 +1191,8 @@ static int try_save_sets(const char name[IP_SET_MAXNAMELEN])
|
||||
size = 0;
|
||||
while (size < req_size) {
|
||||
DP("size: %u, req_size: %u", size, req_size);
|
||||
if (bindings)
|
||||
size += save_bindings(data, size, req_size);
|
||||
else
|
||||
size += save_set(data, &bindings, size, req_size);
|
||||
size += save_set(data, size, req_size);
|
||||
}
|
||||
/* Re-read data to save default bindings */
|
||||
bindings = 0;
|
||||
size = 0;
|
||||
while (size < req_size && bindings == 0)
|
||||
size += save_default_bindings(data + size, &bindings);
|
||||
|
||||
printf("COMMIT\n");
|
||||
now = time(NULL);
|
||||
printf("# Completed on %s", ctime(&now));
|
||||
@@ -1366,7 +1290,7 @@ static void set_restore(char *argv0)
|
||||
char buffer[1024];
|
||||
char *ptr, *name = NULL;
|
||||
char cmd = ' ';
|
||||
int first_pass, i, bindings = 0;
|
||||
int first_pass, i;
|
||||
struct settype *settype = NULL;
|
||||
struct ip_set_req_setnames *header;
|
||||
ip_set_id_t idx;
|
||||
@@ -1381,8 +1305,7 @@ static void set_restore(char *argv0)
|
||||
IP_SET_OP_LIST_SIZE, CMD_RESTORE);
|
||||
|
||||
restore_line = 0;
|
||||
restore_size = sizeof(struct ip_set_req_setnames)/* header */
|
||||
+ sizeof(struct ip_set_restore); /* marker */
|
||||
restore_size = ALIGNED(sizeof(struct ip_set_req_setnames)); /* header */
|
||||
DP("restore_size: %u", restore_size);
|
||||
/* First pass: calculate required amount of data */
|
||||
while (fgets(buffer, sizeof(buffer), in)) {
|
||||
@@ -1429,13 +1352,9 @@ static void set_restore(char *argv0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Missing settype in line %u\n",
|
||||
restore_line);
|
||||
if (bindings)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Invalid line %u: create must precede bindings\n",
|
||||
restore_line);
|
||||
settype = check_set_typename(ptr);
|
||||
restore_size += sizeof(struct ip_set_restore)
|
||||
+ settype->create_size;
|
||||
restore_size += ALIGNED(sizeof(struct ip_set_restore))
|
||||
+ ALIGNED(settype->create_size);
|
||||
DP("restore_size (N): %u", restore_size);
|
||||
break;
|
||||
}
|
||||
@@ -1446,20 +1365,10 @@ static void set_restore(char *argv0)
|
||||
"Add IP to set %s in line %u without "
|
||||
"preceding corresponding create set line\n",
|
||||
ptr, restore_line);
|
||||
if (bindings)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Invalid line %u: adding entries must precede bindings\n",
|
||||
restore_line);
|
||||
restore_size += settype->adt_size;
|
||||
restore_size += ALIGNED(settype->adt_size);
|
||||
DP("restore_size (A): %u", restore_size);
|
||||
break;
|
||||
}
|
||||
case 'B': {
|
||||
bindings = 1;
|
||||
restore_size += sizeof(struct ip_set_hash_save);
|
||||
DP("restore_size (B): %u", restore_size);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Unrecognized restore command in line %u\n",
|
||||
@@ -1471,12 +1380,13 @@ static void set_restore(char *argv0)
|
||||
if (!restore)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Missing COMMIT line\n");
|
||||
restore_size += ALIGNED(sizeof(struct ip_set_restore)); /* marker */
|
||||
DP("restore_size: %u", restore_size);
|
||||
restore_data = ipset_malloc(restore_size);
|
||||
header = (struct ip_set_req_setnames *) restore_data;
|
||||
header->op = IP_SET_OP_RESTORE;
|
||||
header->size = restore_size;
|
||||
restore_offset = sizeof(struct ip_set_req_setnames);
|
||||
restore_offset = ALIGNED(sizeof(struct ip_set_req_setnames));
|
||||
|
||||
/* Rewind to scan the file again */
|
||||
fseek(in, 0L, SEEK_SET);
|
||||
@@ -1508,17 +1418,15 @@ static void set_restore(char *argv0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Broken restore file\n");
|
||||
do_restore:
|
||||
if (bindings == 0
|
||||
&& restore_size ==
|
||||
(restore_offset + sizeof(struct ip_set_restore))) {
|
||||
if (restore_size == (restore_offset + ALIGNED(sizeof(struct ip_set_restore)))) {
|
||||
/* No bindings */
|
||||
struct ip_set_restore *marker =
|
||||
(struct ip_set_restore *) (restore_data + restore_offset);
|
||||
|
||||
DP("restore marker");
|
||||
marker->index = IP_SET_INVALID_ID;
|
||||
marker->header_size = marker->members_size = 0;
|
||||
restore_offset += sizeof(struct ip_set_restore);
|
||||
restore_offset += ALIGNED(sizeof(struct ip_set_restore));
|
||||
DP("restore marker, restore_offset: %zu", restore_offset);
|
||||
}
|
||||
if (restore_size != restore_offset)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
@@ -1550,8 +1458,10 @@ static struct set *set_adt_get(const char *name)
|
||||
|
||||
DP("%s", name);
|
||||
|
||||
check_protocolversion();
|
||||
|
||||
req_adt_get.op = IP_SET_OP_ADT_GET;
|
||||
req_adt_get.version = IP_SET_PROTOCOL_VERSION;
|
||||
req_adt_get.version = protocol_version;
|
||||
strcpy(req_adt_get.set.name, name);
|
||||
size = sizeof(struct ip_set_req_adt_get);
|
||||
|
||||
@@ -1579,15 +1489,15 @@ static int set_adtip(struct set *set, const char *adt,
|
||||
DP("%s -> %s", set->name, adt);
|
||||
|
||||
/* Alloc memory for the data to send */
|
||||
size = sizeof(struct ip_set_req_adt) + set->settype->adt_size ;
|
||||
DP("alloc size %d", size);
|
||||
size = ALIGNED(sizeof(struct ip_set_req_adt)) + set->settype->adt_size ;
|
||||
DP("alloc size %zu", size);
|
||||
data = ipset_malloc(size);
|
||||
|
||||
/* Fill out the request */
|
||||
req_adt = (struct ip_set_req_adt *) data;
|
||||
req_adt->op = op;
|
||||
req_adt->index = set->index;
|
||||
memcpy(data + sizeof(struct ip_set_req_adt),
|
||||
memcpy(data + ALIGNED(sizeof(struct ip_set_req_adt)),
|
||||
set->settype->data, set->settype->adt_size);
|
||||
|
||||
if (kernel_sendto_handleerrno(cmd, data, size) == -1)
|
||||
@@ -1625,155 +1535,22 @@ static void set_restore_add(struct set *set, const char *adt UNUSED)
|
||||
{
|
||||
DP("%s %s", set->name, adt);
|
||||
/* Sanity checking */
|
||||
if (restore_offset + set->settype->adt_size > restore_size)
|
||||
if (restore_offset + ALIGNED(set->settype->adt_size) > restore_size)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Giving up, restore file is screwed up!");
|
||||
|
||||
memcpy(restore_data + restore_offset,
|
||||
set->settype->data, set->settype->adt_size);
|
||||
restore_set->members_size += set->settype->adt_size;
|
||||
restore_offset += set->settype->adt_size;
|
||||
}
|
||||
restore_set->members_size += ALIGNED(set->settype->adt_size);
|
||||
restore_offset += ALIGNED(set->settype->adt_size);
|
||||
|
||||
/*
|
||||
* Send bind/unbind/test binding order to kernel for a set
|
||||
*/
|
||||
static int set_bind(struct set *set, const char *adt,
|
||||
const char *binding,
|
||||
unsigned op, unsigned cmd)
|
||||
{
|
||||
struct ip_set_req_bind *req_bind;
|
||||
size_t size;
|
||||
void *data;
|
||||
int res = 0;
|
||||
|
||||
/* set may be null: '-U :all: :all:|:default:' */
|
||||
DP("(%s, %s) -> %s", set ? set->name : IPSET_TOKEN_ALL, adt, binding);
|
||||
|
||||
/* Ugly */
|
||||
if (set != NULL
|
||||
&& ((strcmp(set->settype->typename, "iptreemap") == 0)
|
||||
|| (strcmp(set->settype->typename, "ipportiphash") == 0)
|
||||
|| (strcmp(set->settype->typename, "ipportnethash") == 0)
|
||||
|| (strcmp(set->settype->typename, "setlist") == 0)))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"%s type of sets cannot be used at binding operations\n",
|
||||
set->settype->typename);
|
||||
/* Alloc memory for the data to send */
|
||||
size = sizeof(struct ip_set_req_bind);
|
||||
if (op != IP_SET_OP_UNBIND_SET && adt[0] == ':')
|
||||
/* Set default binding */
|
||||
size += IP_SET_MAXNAMELEN;
|
||||
else if (!(op == IP_SET_OP_UNBIND_SET && set == NULL))
|
||||
size += set->settype->adt_size;
|
||||
DP("alloc size %d", size);
|
||||
data = ipset_malloc(size);
|
||||
|
||||
/* Fill out the request */
|
||||
req_bind = (struct ip_set_req_bind *) data;
|
||||
req_bind->op = op;
|
||||
req_bind->index = set ? set->index : IP_SET_INVALID_ID;
|
||||
if (adt[0] == ':') {
|
||||
/* ':default:' and ':all:' */
|
||||
strncpy(req_bind->binding, adt, IP_SET_MAXNAMELEN);
|
||||
if (op != IP_SET_OP_UNBIND_SET && adt[0] == ':')
|
||||
strncpy(data + sizeof(struct ip_set_req_bind),
|
||||
binding, IP_SET_MAXNAMELEN);
|
||||
} else {
|
||||
strncpy(req_bind->binding, binding, IP_SET_MAXNAMELEN);
|
||||
memcpy(data + sizeof(struct ip_set_req_bind),
|
||||
set->settype->data, set->settype->adt_size);
|
||||
}
|
||||
|
||||
if (op == IP_SET_OP_TEST_BIND_SET) {
|
||||
if (kernel_sendto_handleerrno(cmd, data, size) == -1) {
|
||||
ipset_printf("%s in set %s is bound to %s.",
|
||||
adt, set->name, binding);
|
||||
res = 0;
|
||||
} else {
|
||||
ipset_printf("%s in set %s is NOT bound to %s.",
|
||||
adt, set->name, binding);
|
||||
res = 1;
|
||||
}
|
||||
} else
|
||||
kernel_sendto(cmd, data, size);
|
||||
free(data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void set_restore_bind(struct set *set,
|
||||
const char *adt,
|
||||
const char *binding)
|
||||
{
|
||||
struct ip_set_hash_save *hash_restore;
|
||||
|
||||
if (restore == 1) {
|
||||
/* Marker */
|
||||
struct ip_set_restore *marker =
|
||||
(struct ip_set_restore *) (restore_data + restore_offset);
|
||||
|
||||
DP("restore marker");
|
||||
if (restore_offset + sizeof(struct ip_set_restore)
|
||||
> restore_size)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Giving up, restore file is screwed up!");
|
||||
marker->index = IP_SET_INVALID_ID;
|
||||
marker->header_size = marker->members_size = 0;
|
||||
restore_offset += sizeof(struct ip_set_restore);
|
||||
restore = 2;
|
||||
}
|
||||
/* Sanity checking */
|
||||
if (restore_offset + sizeof(struct ip_set_hash_save) > restore_size)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Giving up, restore file is screwed up!");
|
||||
|
||||
hash_restore = (struct ip_set_hash_save *) (restore_data + restore_offset);
|
||||
DP("%s -> %s", adt, binding);
|
||||
if (strcmp(adt, IPSET_TOKEN_DEFAULT) == 0)
|
||||
hash_restore->ip = 0;
|
||||
else {
|
||||
if (!set->settype->bindip_parse)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Internal error, binding is not supported with set %s"
|
||||
" of settype %s\n",
|
||||
set->name, set->settype->typename);
|
||||
set->settype->bindip_parse(adt, &hash_restore->ip);
|
||||
}
|
||||
hash_restore->id = set->index;
|
||||
hash_restore->binding = (set_find_byname(binding))->index;
|
||||
DP("id %u, ip %u, binding %u",
|
||||
hash_restore->id, hash_restore->ip, hash_restore->binding);
|
||||
restore_offset += sizeof(struct ip_set_hash_save);
|
||||
DP("restore_offset: %zu", restore_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print operation
|
||||
*/
|
||||
|
||||
static void print_bindings(struct set *set,
|
||||
void *data, size_t size, unsigned options,
|
||||
char * (*printip)(struct set *set,
|
||||
ip_set_ip_t ip, unsigned options))
|
||||
{
|
||||
size_t offset = 0;
|
||||
struct ip_set_hash_list *hash;
|
||||
|
||||
if (offset < size && !printip)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"Internal error, binding is not supported with set %s"
|
||||
" of settype %s\n",
|
||||
set->name, set->settype->typename);
|
||||
|
||||
while (offset < size) {
|
||||
hash = (struct ip_set_hash_list *) (data + offset);
|
||||
printf("%s -> %s\n",
|
||||
printip(set, hash->ip, options),
|
||||
set_list[hash->binding]->name);
|
||||
offset += sizeof(struct ip_set_hash_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* Help function to set_list() */
|
||||
static size_t print_set(void *data, unsigned options)
|
||||
{
|
||||
@@ -1783,15 +1560,14 @@ static size_t print_set(void *data, unsigned options)
|
||||
size_t offset;
|
||||
|
||||
/* Pretty print the set */
|
||||
DP("header size: %u, members size: %u",
|
||||
setlist->header_size, setlist->members_size);
|
||||
printf("Name: %s\n", set->name);
|
||||
printf("Type: %s\n", settype->typename);
|
||||
printf("References: %d\n", setlist->ref);
|
||||
printf("Default binding: %s\n",
|
||||
setlist->binding == IP_SET_INVALID_ID ? ""
|
||||
: set_list[setlist->binding]->name);
|
||||
|
||||
/* Init header */
|
||||
offset = sizeof(struct ip_set_list);
|
||||
offset = ALIGNED(sizeof(struct ip_set_list));
|
||||
settype->initheader(set, data + offset);
|
||||
|
||||
/* Pretty print the type header */
|
||||
@@ -1801,24 +1577,20 @@ static size_t print_set(void *data, unsigned options)
|
||||
/* Pretty print all IPs */
|
||||
printf("Members:\n");
|
||||
offset += setlist->header_size;
|
||||
DP("Aligned: %u, offset: %zu, members_size %u\n", !DONT_ALIGN, offset,
|
||||
setlist->members_size);
|
||||
if (options & OPT_SORTED)
|
||||
settype->printips_sorted(set, data + offset,
|
||||
setlist->members_size, options);
|
||||
setlist->members_size, options,
|
||||
DONT_ALIGN);
|
||||
else
|
||||
settype->printips(set, data + offset,
|
||||
setlist->members_size, options);
|
||||
|
||||
/* Print bindings */
|
||||
printf("Bindings:\n");
|
||||
offset += setlist->members_size;
|
||||
if (set->settype->bindip_tostring)
|
||||
print_bindings(set,
|
||||
data + offset, setlist->bindings_size, options,
|
||||
settype->bindip_tostring);
|
||||
setlist->members_size, options,
|
||||
DONT_ALIGN);
|
||||
|
||||
printf("\n"); /* One newline between sets */
|
||||
|
||||
return (offset + setlist->bindings_size);
|
||||
return (offset + setlist->members_size);
|
||||
}
|
||||
|
||||
static int try_list_sets(const char name[IP_SET_MAXNAMELEN],
|
||||
@@ -1889,9 +1661,9 @@ static void set_help(const struct settype *settype)
|
||||
"Usage: %s -N new-set settype [options]\n"
|
||||
" %s -[XFLSH] [set] [options]\n"
|
||||
" %s -[EW] from-set to-set\n"
|
||||
" %s -[ADTU] set IP\n"
|
||||
" %s -B set IP option\n"
|
||||
" %s -[ADT] set IP\n"
|
||||
" %s -R\n"
|
||||
" %s -v\n"
|
||||
" %s -h (print this help information)\n\n",
|
||||
program_name, program_version,
|
||||
program_name, program_name, program_name,
|
||||
@@ -1922,13 +1694,6 @@ static void set_help(const struct settype *settype)
|
||||
" Deletes an IP from a set\n"
|
||||
" --test -T setname IP \n"
|
||||
" Tests if an IP exists in a set.\n"
|
||||
" --bind -B setname IP|:default: -b bind-setname\n"
|
||||
" Bind the IP in setname to bind-setname.\n"
|
||||
" --unbind -U setname IP|:all:|:default:\n"
|
||||
" Delete binding belonging to IP,\n"
|
||||
" all bindings or default binding of setname.\n"
|
||||
" --unbind -U :all: :all:|:default:\n"
|
||||
" Delete all bindings or all default bindings.\n"
|
||||
" --help -H [settype]\n"
|
||||
" Prints this help, and settype specific help\n"
|
||||
" --version -V\n"
|
||||
@@ -1937,8 +1702,7 @@ static void set_help(const struct settype *settype)
|
||||
" --sorted -s Numeric sort of the IPs in -L\n"
|
||||
" --numeric -n Numeric output of addresses in a -L (default)\n"
|
||||
" --resolve -r Try to resolve addresses in a -L\n"
|
||||
" --quiet -q Suppress any output to stdout and stderr.\n"
|
||||
" --binding -b Specifies the binding for -B\n");
|
||||
" --quiet -q Suppress any output to stdout and stderr.\n");
|
||||
#ifdef IPSET_DEBUG
|
||||
printf(" --debug -z Enable debugging\n\n");
|
||||
#else
|
||||
@@ -1970,40 +1734,13 @@ static int parse_adt_cmdline(int command,
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
/* -U :all: :all:|:default: */
|
||||
if (command == CMD_UNBIND) {
|
||||
if (strcmp(name, IPSET_TOKEN_ALL) == 0) {
|
||||
if (strcmp(adt, IPSET_TOKEN_DEFAULT) == 0
|
||||
|| strcmp(adt, IPSET_TOKEN_ALL) == 0) {
|
||||
*set = NULL;
|
||||
*settype = NULL;
|
||||
return 1;
|
||||
} else
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"-U %s requires %s or %s as binding name",
|
||||
IPSET_TOKEN_ALL,
|
||||
IPSET_TOKEN_DEFAULT,
|
||||
IPSET_TOKEN_ALL);
|
||||
}
|
||||
}
|
||||
*set = restore ? set_find_byname(name)
|
||||
: set_adt_get(name);
|
||||
*set = restore ? set_find_byname(name) : set_adt_get(name);
|
||||
|
||||
/* Reset space for adt data */
|
||||
*settype = (*set)->settype;
|
||||
memset((*settype)->data, 0, (*settype)->adt_size);
|
||||
|
||||
if ((command == CMD_TEST
|
||||
|| command == CMD_BIND
|
||||
|| command == CMD_UNBIND)
|
||||
&& (strcmp(adt, IPSET_TOKEN_DEFAULT) == 0
|
||||
|| strcmp(adt, IPSET_TOKEN_ALL) == 0))
|
||||
res = 1;
|
||||
else
|
||||
res = (*settype)->adt_parser(
|
||||
command,
|
||||
adt,
|
||||
(*settype)->data);
|
||||
res = (*settype)->adt_parser(command, adt, (*settype)->data);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -2018,9 +1755,8 @@ int parse_commandline(int argc, char *argv[])
|
||||
|
||||
char *name = NULL; /* All except -H, -R */
|
||||
char *newname = NULL; /* -E, -W */
|
||||
char *adt = NULL; /* -A, -D, -T, -B, -U */
|
||||
char *binding = NULL; /* -B */
|
||||
struct set *set = NULL; /* -A, -D, -T, -B, -U */
|
||||
char *adt = NULL; /* -A, -D, -T */
|
||||
struct set *set = NULL; /* -A, -D, -T */
|
||||
struct settype *settype = NULL; /* -N, -H */
|
||||
char all_sets[] = IPSET_TOKEN_ALL;
|
||||
|
||||
@@ -2054,11 +1790,14 @@ int parse_commandline(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
case 'V':{ /* Version */
|
||||
printf("%s v%s Protocol version %u.\n",
|
||||
case 'V':
|
||||
case 'v': { /* Version */
|
||||
printf("%s v%s, protocol version %u.\n",
|
||||
program_name, program_version,
|
||||
IP_SET_PROTOCOL_VERSION);
|
||||
check_protocolversion();
|
||||
printf("Kernel module protocol version %u.\n",
|
||||
protocol_version);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -2067,7 +1806,7 @@ int parse_commandline(int argc, char *argv[])
|
||||
|
||||
name = check_set_name(optarg);
|
||||
|
||||
/* Protect reserved names (binding) */
|
||||
/* Protect reserved names */
|
||||
if (name[0] == ':')
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"setname might not start with colon",
|
||||
@@ -2142,9 +1881,7 @@ int parse_commandline(int argc, char *argv[])
|
||||
|
||||
case 'A': /* Add IP */
|
||||
case 'D': /* Del IP */
|
||||
case 'T': /* Test IP */
|
||||
case 'B': /* Bind IP */
|
||||
case 'U':{ /* Unbind IP */
|
||||
case 'T':{ /* Test IP */
|
||||
set_command(&command, find_cmd(c));
|
||||
|
||||
name = check_set_name(optarg);
|
||||
@@ -2197,11 +1934,6 @@ int parse_commandline(int argc, char *argv[])
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'b':
|
||||
add_option(&options, OPT_BINDING);
|
||||
binding = check_set_name(optarg);
|
||||
break;
|
||||
|
||||
case 1: /* non option */
|
||||
printf("Bad argument `%s'\n", optarg);
|
||||
exit_tryhelp(PARAMETER_PROBLEM);
|
||||
@@ -2248,6 +1980,8 @@ int parse_commandline(int argc, char *argv[])
|
||||
generic_opt_check(command, options);
|
||||
|
||||
DP("cmd: %c", cmd2char(command));
|
||||
|
||||
check_protocolversion();
|
||||
|
||||
switch (command) {
|
||||
case CMD_CREATE:
|
||||
@@ -2298,26 +2032,7 @@ int parse_commandline(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case CMD_TEST:
|
||||
if (binding)
|
||||
res = set_bind(set, adt, binding,
|
||||
IP_SET_OP_TEST_BIND_SET, CMD_TEST);
|
||||
else
|
||||
res = set_adtip(set, adt,
|
||||
IP_SET_OP_TEST_IP, CMD_TEST);
|
||||
break;
|
||||
|
||||
case CMD_BIND:
|
||||
fprintf(stderr, "Warning: binding will be removed from the next release.\n"
|
||||
"Please replace bindigs with sets of ipportmap and ipportiphash types\n");
|
||||
if (restore)
|
||||
set_restore_bind(set, adt, binding);
|
||||
else
|
||||
set_bind(set, adt, binding,
|
||||
IP_SET_OP_BIND_SET, CMD_BIND);
|
||||
break;
|
||||
|
||||
case CMD_UNBIND:
|
||||
set_bind(set, adt, "", IP_SET_OP_UNBIND_SET, CMD_UNBIND);
|
||||
res = set_adtip(set, adt, IP_SET_OP_TEST_IP, CMD_TEST);
|
||||
break;
|
||||
|
||||
case CMD_HELP:
|
||||
|
Reference in New Issue
Block a user