Home > Enterprise >  How to get ipset timeout programmatically?
How to get ipset timeout programmatically?

Time:01-18

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;
}
  • Related