I am trying to get the timeout value of an ipset programmatically (not using the userspace ipset
tool).
The following example tries to get the timeout from set named "my_set" which had been created with this command:
ipset create my_set hash:ip timeout 86400
Here's the example code where I tried a few different ways to access the timeout data field:
#include "stdlib.h"
#include <libipset/types.h>
#include <libipset/session.h>
int main(int argc, char* argv[]) {
ipset_load_types();
struct ipset_session *session;
session = ipset_session_init(NULL, NULL);
ipset_session_data_set(session, IPSET_SETNAME, "my_set");
/* Validate set exist */
if (ipset_type_get(session, IPSET_CMD_TEST) == NULL) {
printf("Error: Can't find set\n");
exit(1);
}
if ((const uint32_t*)ipset_session_data_get(session, IPSET_OPT_TIMEOUT) == NULL)
printf("Timeout field is NULL\n");
const struct ipset_data* data = ipset_session_data(session);
if (!ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_TIMEOUT)))
printf("Timeout field is not present\n");
if (!ipset_data_test(data, IPSET_OPT_TIMEOUT))
printf("Timeout field is not present\n");
if ((const uint32_t*)ipset_session_data_get(session, IPSET_OPT_TIMEOUT) == NULL)
printf("Timeout field is NULL\n");
}
Compile with:
gcc -lipset test.c
Output is:
Timeout field is NULL
Timeout field is not present
Timeout field is not present
Timeout field is NULL
I think the timeout is not being provided by the kernel, but I don't know how to use the ipset API to ask the kernel for that information. I can't find any API documentation and I'm trying to use examples from the ipset source I found here or here
The API here is not useful for this task.
CodePudding user response:
From what I can see, libipset
has some quite silly interface. There is no decent way to obtain the properties of a given set through the library, and the associated command line tool (ipset(8)
) also does not offer a simple way to query them. However, they are available when issuing a "list" command.
It seems that the information you want is only queried on-the-fly by the library when needed and then deleted, leaving no trace. This means that even after executing something like ipset_cmd(session, IPSET_CMD_LIST, 0)
, checking with ipset_session_data_get(session, IPSET_OPT_TIMEOUT)
will yield absolutely nothing! Pretty funny.
The "proper" way to obtain this information would be to use a raw netlink socket and exchange the appropriate messages directly with the ipset netlink subsystem (NFNL_SUBSYS_IPSET
), which is what libipset
does under the hood, but that's quite the predicament...
However, since the library allows you to create a "session" registering a callback function to call for printing information, you can [ab]use this to get what you want.
Here's a working example:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <libipset/types.h>
#include <libipset/session.h>
struct info {
uint32_t timeout;
bool ok;
};
/* Callback print function executed by libipset when information is available.
* Extract whatever information is needed and store it through the private data
* pointer.
*/
static int dummy_print_fn(struct ipset_session *session, void *data, const char *_fmt, ...) {
struct info *out = data;
const uint32_t *ptr = ipset_session_data_get(session, IPSET_OPT_TIMEOUT);
if (ptr != NULL) {
out->timeout = *ptr;
out->ok = true;
} else {
out->ok = false;
}
return 0;
}
int main(int argc, char* argv[]) {
ipset_load_types();
struct ipset_session *session;
/* Passed as private data pointer to dummy_print_fn. */
struct info info;
/* Register dummy print callback and &info as private data ptr. */
if ((session = ipset_session_init(dummy_print_fn, &info)) == NULL) {
printf("Error: Can't initialize session\n");
exit(1);
}
if (ipset_session_data_set(session, IPSET_SETNAME, "my_set") != 0) {
printf("Error: Can't give set name\n");
exit(1);
}
/* Validate set exists */
if (ipset_type_get(session, IPSET_CMD_TEST) == NULL) {
printf("Error: Can't find set\n");
exit(1);
}
/* Execute a list command to get the information you want through the
* registered callback function.
*/
if (ipset_cmd(session, IPSET_CMD_LIST, 0) != 0) {
printf("Error: list command failed\n");
exit(1);
}
if (info.ok)
printf("Timeout: %u\n", info.timeout);
else
printf("Timeout: field unavailable\n");
return 0;
}