+
+ for (i = 0; i < len && buffer[i] != '\0'; ++i) {
+ if (buffer[i] == ':')
+ cnt++;
+ }
+
+ if (cnt != 8) {
+ uloga("Wrong input line '%s': cnt: %d, must be 8, i: %d, must be %d.\n", ctx, buffer, cnt, i, len);
+ return -EINVAL;
+ }
+
+ memset(obuf, 0, sizeof(obuf));
+
+ pbeg = buffer;
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ if (pbeg[0] == 'S') {
+ f.wss.wc = OSF_WSS_MSS;
+ if (pbeg[1] == '%')
+ f.wss.val = strtoul(&pbeg[2], NULL, 10);
+ else if (pbeg[1] == '*')
+ f.wss.val = 0;
+ else
+ f.wss.val = strtoul(&pbeg[1], NULL, 10);
+ } else if (pbeg[0] == 'T') {
+ f.wss.wc = OSF_WSS_MTU;
+ if (pbeg[1] == '%')
+ f.wss.val = strtoul(&pbeg[2], NULL, 10);
+ else if (pbeg[1] == '*')
+ f.wss.val = 0;
+ else
+ f.wss.val = strtoul(&pbeg[1], NULL, 10);
+ } else if (pbeg[0] == '%') {
+ f.wss.wc = OSF_WSS_MODULO;
+ f.wss.val = strtoul(&pbeg[1], NULL, 10);
+ } else if (isdigit(pbeg[0])) {
+ f.wss.wc = OSF_WSS_PLAIN;
+ f.wss.val = strtoul(&pbeg[0], NULL, 10);
+ }
+
+ pbeg = pend + 1;
+ }
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ f.ttl = strtoul(pbeg, NULL, 10);
+ pbeg = pend + 1;
+ }
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ f.df = strtoul(pbeg, NULL, 10);
+ pbeg = pend + 1;
+ }
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ f.ss = strtoul(pbeg, NULL, 10);
+ pbeg = pend + 1;
+ }
+
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ cnt = snprintf(obuf, sizeof(obuf), "%s,", pbeg);
+ pbeg = pend + 1;
+ }
+
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ if (pbeg[0] == '@' || pbeg[0] == '*')
+ cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg + 1);
+ else
+ cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg);
+ pbeg = pend + 1;
+ }
+
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ cnt = snprintf(f.version, sizeof(f.version), "%s", pbeg);
+ pbeg = pend + 1;
+ }
+
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ cnt =
+ snprintf(f.subtype, sizeof(f.subtype), "%s", pbeg);
+ pbeg = pend + 1;
+ }
+
+ nf_osf_parse_opt(f.opt, &f.opt_num, obuf, sizeof(obuf));
+
+ memset(buf, 0, sizeof(buf));
+
+ if (del) {
+ nlh = nftnl_nlmsg_build_hdr(buf, (NFNL_SUBSYS_OSF << 8) |
+ OSF_MSG_REMOVE, AF_UNSPEC,
+ NLM_F_REQUEST | NLM_F_ACK,
+ ctx->seqnum);
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = AF_UNSPEC;
+ nfg->version = NFNETLINK_V0;
+ nfg->res_id = 0;
+ } else {
+ nlh = nftnl_nlmsg_build_hdr(buf, (NFNL_SUBSYS_OSF << 8) |
+ OSF_MSG_ADD, AF_UNSPEC,
+ NLM_F_REQUEST | NLM_F_CREATE |
+ NLM_F_ACK, ctx->seqnum);
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = AF_UNSPEC;
+ nfg->version = NFNETLINK_V0;
+ nfg->res_id = 0;
+
+ mnl_attr_put(nlh, OSF_ATTR_FINGER, sizeof(struct nf_osf_user_finger), &f);
+ }
+
+ return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, 0, NULL);
+}
+
+static int osf_load_entries(int del, struct mnl_socket *nl,
+ struct netlink_ctx *ctx)
+{
+ FILE *inf;
+ int err = 0;
+ char buf[1024];
+
+ inf = fopen(OS_SIGNATURES, "r");
+ if (!inf) {
+ uloga("Failed to open file '%s'", ctx, OS_SIGNATURES);
+ return -1;
+ }
+
+ while(fgets(buf, sizeof(buf), inf)) {
+ int len;
+
+ if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
+ continue;
+
+ len = strlen(buf) - 1;
+
+ if (len <= 0)
+ continue;
+
+ buf[len] = '\0';
+
+ err = osf_load_line(buf, len, del, nl, ctx);
+ if (err)
+ break;
+
+ memset(buf, 0, sizeof(buf));
+ }
+
+ fclose(inf);
+ return err;
+}
+
+int nfnl_osf_load_fingerprints(struct netlink_ctx *ctx, int del)
+{
+ int err;
+ struct mnl_socket *nl;
+
+ nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (nl == NULL) {
+ err = -EINVAL;
+ uloga("Failed to open mnl socket", ctx);
+ goto err_out_exit;
+ }
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ err = -EINVAL;
+ uloga("Failed to bind mnl socket", ctx);
+ goto err_out_exit;
+ }
+
+#ifndef NFNL_SUBSYS_OSF
+#define NFNL_SUBSYS_OSF 5
+#endif
+ err = osf_load_entries(del, nl, ctx);
+ if (err < 0)
+ goto err_out_close;
+
+ return 0;
+
+err_out_close:
+ mnl_socket_close(nl);
+err_out_exit:
+ return err;
+}
diff --git a/src/osf.c b/src/osf.c
index 131d54e..210bfbe 100644
--- a/src/osf.c
+++ b/src/osf.c
@@ -3,6 +3,7 @@
#include <utils.h>
#include <string.h>
#include <osf.h>
+#include <nfnl_osf.h>
static void osf_expr_print(const struct expr *expr, struct output_ctx *octx)
{
@@ -26,6 +27,7 @@ struct expr *osf_expr_alloc(const struct location *loc)
const struct datatype *type = &string_type;
struct expr *expr;
+ osf_init = true;
expr = expr_alloc(loc, &osf_expr_ops, type,
BYTEORDER_HOST_ENDIAN, len);
diff --git a/src/rule.c b/src/rule.c
index 7a7ac73..7421ffc 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -22,6 +22,7 @@
#include <netdb.h>
#include <netlink.h>
#include <json.h>
+#include <nfnl_osf.h>
#include <libnftnl/common.h>
#include <libnftnl/ruleset.h>
@@ -2135,6 +2136,9 @@ int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
default:
BUG("invalid command object type %u\n", cmd->obj);
}
+
+ if (osf_init)
+ nfnl_osf_load_fingerprints(ctx, 0);