On Fri, Aug 10, 2018 at 03:02:00PM +0200, Fernando Fernandez Mancera wrote: > Import iptables/utils/nfnl_osf.c into nftables tree with some changes in order > to load OS fingerprints automatically from pf.os file. > > Signed-off-by: Fernando Fernandez Mancera <ffmancera@xxxxxxxxxx> > --- > include/linux/netfilter/nfnetlink_osf.h | 119 +++++++ > include/nfnl_osf.h | 6 + > include/osf.h | 2 + > src/Makefile.am | 1 + > src/nfnl_osf.c | 449 ++++++++++++++++++++++++ > src/osf.c | 2 + > src/rule.c | 5 + > 7 files changed, 584 insertions(+) > create mode 100644 include/linux/netfilter/nfnetlink_osf.h > create mode 100644 include/nfnl_osf.h > create mode 100644 src/nfnl_osf.c > > diff --git a/include/linux/netfilter/nfnetlink_osf.h b/include/linux/netfilter/nfnetlink_osf.h > new file mode 100644 > index 0000000..15a39d2 > --- /dev/null > +++ b/include/linux/netfilter/nfnetlink_osf.h > @@ -0,0 +1,119 @@ > +#ifndef _NF_OSF_H > +#define _NF_OSF_H > + > +#include <linux/types.h> > + > +#define MAXGENRELEN 32 > + > +#define NF_OSF_GENRE (1 << 0) > +#define NF_OSF_TTL (1 << 1) > +#define NF_OSF_LOG (1 << 2) > +#define NF_OSF_INVERT (1 << 3) > + > +#define NF_OSF_LOGLEVEL_ALL 0 /* log all matched fingerprints */ > +#define NF_OSF_LOGLEVEL_FIRST 1 /* log only the first matced fingerprint */ > +#define NF_OSF_LOGLEVEL_ALL_KNOWN 2 /* do not log unknown packets */ > + > +#define NF_OSF_TTL_TRUE 0 /* True ip and fingerprint TTL comparison */ > + > +/* Check if ip TTL is less than fingerprint one */ > +#define NF_OSF_TTL_LESS 1 > + > +/* Do not compare ip and fingerprint TTL at all */ > +#define NF_OSF_TTL_NOCHECK 2 > + > +#define NF_OSF_FLAGMASK (NF_OSF_GENRE | NF_OSF_TTL | \ > + NF_OSF_LOG | NF_OSF_INVERT) > +/* Wildcard MSS (kind of). > + * It is used to implement a state machine for the different wildcard values > + * of the MSS and window sizes. > + */ > +struct nf_osf_wc { > + __u32 wc; > + __u32 val; > +}; > + > +/* This struct represents IANA options > + * http://www.iana.org/assignments/tcp-parameters > + */ > +struct nf_osf_opt { > + __u16 kind, length; > + struct nf_osf_wc wc; > +}; > + > +struct nf_osf_info { > + char genre[MAXGENRELEN]; > + __u32 len; > + __u32 flags; > + __u32 loglevel; > + __u32 ttl; > +}; > + > +struct nf_osf_user_finger { > + struct nf_osf_wc wss; > + > + __u8 ttl, df; > + __u16 ss, mss; > + __u16 opt_num; > + > + char genre[MAXGENRELEN]; > + char version[MAXGENRELEN]; > + char subtype[MAXGENRELEN]; > + > + /* MAX_IPOPTLEN is maximum if all options are NOPs or EOLs */ > + struct nf_osf_opt opt[MAX_IPOPTLEN]; > +}; > + > +struct nf_osf_nlmsg { > + struct nf_osf_user_finger f; > + struct iphdr ip; > + struct tcphdr tcp; > +}; > + > +/* Defines for IANA option kinds */ > +enum iana_options { > + OSFOPT_EOL = 0, /* End of options */ > + OSFOPT_NOP, /* NOP */ > + OSFOPT_MSS, /* Maximum segment size */ > + OSFOPT_WSO, /* Window scale option */ > + OSFOPT_SACKP, /* SACK permitted */ > + OSFOPT_SACK, /* SACK */ > + OSFOPT_ECHO, > + OSFOPT_ECHOREPLY, > + OSFOPT_TS, /* Timestamp option */ > + OSFOPT_POCP, /* Partial Order Connection Permitted */ > + OSFOPT_POSP, /* Partial Order Service Profile */ > + > + /* Others are not used in the current OSF */ > + OSFOPT_EMPTY = 255, > +}; > + > +/* > + * Initial window size option state machine: multiple of mss, mtu or > + * plain numeric value. Can also be made as plain numeric value which > + * is not a multiple of specified value. > + */ > +enum nf_osf_window_size_options { > + OSF_WSS_PLAIN = 0, > + OSF_WSS_MSS, > + OSF_WSS_MTU, > + OSF_WSS_MODULO, > + OSF_WSS_MAX, > +}; > + > +enum nf_osf_attr_type { > + OSF_ATTR_UNSPEC, > + OSF_ATTR_FINGER, > + OSF_ATTR_MAX, > +}; > + > +/* > + * Add/remove fingerprint from the kernel. > + */ > +enum nf_osf_msg_types { > + OSF_MSG_ADD, > + OSF_MSG_REMOVE, > + OSF_MSG_MAX, > +}; > + > +#endif /* _NF_OSF_H */ > diff --git a/include/nfnl_osf.h b/include/nfnl_osf.h > new file mode 100644 > index 0000000..d9287e9 > --- /dev/null > +++ b/include/nfnl_osf.h > @@ -0,0 +1,6 @@ > +#ifndef _NFNL_OSF_H > +#define _NFNL_OSF_H > + > +int nfnl_osf_load_fingerprints(struct netlink_ctx *ctx, int del); > + > +#endif /* _NFNL_OSF_H */ > diff --git a/include/osf.h b/include/osf.h > index 715b04e..0a35b07 100644 > --- a/include/osf.h > +++ b/include/osf.h > @@ -1,6 +1,8 @@ > #ifndef NFTABLES_OSF_H > #define NFTABLES_OSF_H > > +bool osf_init; I think you can probably place osf_init in struct netlink_ctx? > struct expr *osf_expr_alloc(const struct location *loc); > > #endif /* NFTABLES_OSF_H */ > diff --git a/src/Makefile.am b/src/Makefile.am > index ed3640e..e569029 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -57,6 +57,7 @@ libnftables_la_SOURCES = \ > services.c \ > mergesort.c \ > osf.c \ > + nfnl_osf.c \ > tcpopt.c \ > socket.c \ > libnftables.c > diff --git a/src/nfnl_osf.c b/src/nfnl_osf.c > new file mode 100644 > index 0000000..07bf682 > --- /dev/null > +++ b/src/nfnl_osf.c > @@ -0,0 +1,449 @@ > +/* > + * Copyright (c) 2005 Evgeniy Polyakov <johnpol@xxxxxxxxxx> > + * > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + */ > + > +#include <sys/time.h> > + > +#include <ctype.h> > +#include <errno.h> > +#include <stdlib.h> > +#include <string.h> > +#include <time.h> > + > +#include <netinet/ip.h> > +#include <netinet/tcp.h> > + > +#include <linux/unistd.h> > + > +#include <libmnl/libmnl.h> > + > +#include <linux/netfilter/nfnetlink.h> > +#include <linux/netfilter/nfnetlink_osf.h> > +#include <mnl.h> > +#include <nfnl_osf.h> > + > +#define OPTDEL ',' > +#define OSFPDEL ':' > +#define MAXOPTSTRLEN 128 > + > +static struct nf_osf_opt IANA_opts[] = { > + { .kind = 0, .length = 1,}, > + { .kind=1, .length=1,}, > + { .kind=2, .length=4,}, > + { .kind=3, .length=3,}, > + { .kind=4, .length=2,}, > + { .kind=5, .length=1,}, /* SACK length is not defined */ > + { .kind=6, .length=6,}, > + { .kind=7, .length=6,}, > + { .kind=8, .length=10,}, > + { .kind=9, .length=2,}, > + { .kind=10, .length=3,}, > + { .kind=11, .length=1,}, /* CC: Suppose 1 */ > + { .kind=12, .length=1,}, /* the same */ > + { .kind=13, .length=1,}, /* and here too */ > + { .kind=14, .length=3,}, > + { .kind=15, .length=1,}, /* TCP Alternate Checksum Data. Length is not defined */ > + { .kind=16, .length=1,}, > + { .kind=17, .length=1,}, > + { .kind=18, .length=3,}, > + { .kind=19, .length=18,}, > + { .kind=20, .length=1,}, > + { .kind=21, .length=1,}, > + { .kind=22, .length=1,}, > + { .kind=23, .length=1,}, > + { .kind=24, .length=1,}, > + { .kind=25, .length=1,}, > + { .kind=26, .length=1,}, > +}; > + > +static void uloga(const char *f, struct netlink_ctx *ctx, ...) > +{ > + if (!(ctx->debug_mask & NFT_DEBUG_NETLINK)) > + return; > + > + nft_print(ctx->octx, "%s", f); > +} I think you can use uloga() all the time, so you can remove ulog() function. > +static void ulog(const char *f, struct netlink_ctx *ctx, ...) > +{ > + char str[64]; > + struct tm tm; > + struct timeval tv; > + > + gettimeofday(&tv, NULL); > + localtime_r((time_t *)&tv.tv_sec, &tm); > + strftime(str, sizeof(str), "%F %R:%S", &tm); > + > + if (!(ctx->debug_mask & NFT_DEBUG_NETLINK)) > + return; > + > + nft_print(ctx->octx, "%s.%lu %ld %s", str, tv.tv_usec, > + syscall(__NR_gettid), f); > +} > + > +#define ulog_err(f, ctx, a...) uloga(f ": %s [%d].\n", ctx, ##a, strerror(errno), errno) And this macro too. Other than that, this looks good to me, thanks.