Re: Passive OS fingerprint xtables match.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thursday 2009-02-12 18:12, Evgeniy Polyakov wrote:
>
>You will find something like this in the syslog:
>ipt_osf: Windows [2000:SP3:Windows XP Pro SP1, 2000 SP3]: 11.22.33.55:4024 -> 11.22.33.44:139
>
>Passive OS fingerprint homepage (archives, examples):
>http://www.ioremap.net/projects/osf

>diff --git a/include/linux/netfilter_ipv4/ipt_osf.h b/include/linux/netfilter_ipv4/ipt_osf.h
>new file mode 100644
>index 0000000..c2d2c7a
>--- /dev/null
>+++ b/include/linux/netfilter_ipv4/ipt_osf.h

Much of this I think should be upgraded to the xt_ prefixing
already, even if it does not do IPv6 yet.

>+struct ipt_osf_info {
>+	char			genre[MAXGENRELEN];
>+	__u32			len;
>+	__u32			flags;
>+	__u32			loglevel;
>+	__u32			ttl;
>+};

I do not think you need an entire u32 for loglevel and ttl.


Could there at least be some description as to what the
following fields are?
 +/**
>+ * Wildcard MSS (kind of).
   * @wc:	wild card what(?)
   * @val:	some value?
>+ */
>+struct ipt_osf_wc {
>+	__u32			wc;
>+	__u32			val;
>+};

>+struct ipt_osf_user_finger {
>+	struct ipt_osf_wc wss;
>+
>+	__u8 ttl, df;
>+	__u16 ss, mss;
>+	int opt_num;
>+
>+	char genre[MAXGENRELEN];
>+	char version[MAXGENRELEN];
>+	char subtype[MAXGENRELEN];
>+
>+	/* MAX_IPOPTLEN is maximum if all options are NOPs or EOLs */
>+	struct ipt_osf_opt opt[MAX_IPOPTLEN];
>+};

Are you sure it is safe to use arch-dependent types like 'int'?

>+/* Defines for IANA option kinds */
>+
>+#define OSFOPT_EOL		0	/* End of options */
>+#define OSFOPT_NOP		1	/* NOP */
>+#define OSFOPT_MSS		2	/* Maximum segment size */
>+#define OSFOPT_WSO		3	/* Window scale option */
>+#define OSFOPT_SACKP		4	/* SACK permitted */
>+#define OSFOPT_SACK		5	/* SACK */
>+#define OSFOPT_ECHO		6
>+#define OSFOPT_ECHOREPLY	7
>+#define OSFOPT_TS		8	/* Timestamp option */
>+#define OSFOPT_POCP		9	/* Partial Order Connection Permitted */
>+#define OSFOPT_POSP		10	/* Partial Order Service Profile */
>+#define OSFOPT_EMPTY		255
>+/* Others are not used in current OSF */

Wrapping this into an enum seems to look nicer.

>+#ifdef __KERNEL__
>+
>+#include <linux/list.h>
>+#include <net/tcp.h>
>+
>+struct ipt_osf_finger {
>+	struct rcu_head			rcu_head;
>+	struct list_head		finger_entry;
>+	struct ipt_osf_user_finger	finger;
>+};
>+
>+#endif				/* __KERNEL__ */
>+
>+#endif				/* _IPT_OSF_H */

Move this section to the .c file.

>+config IP_NF_MATCH_OSF
>+	tristate '"osf" match support'
>+	depends on NETFILTER_ADVANCED && CONNECTOR
>+	help
>+	  Passive OS fingerprint matching module.
>+	  You should download and install rule loading software from
>+	  http://www.ioremap.net/projects/osf
>+
>+	  To compile it as a module, choose M here.  If unsure, say N.
>+

Please do use NETFILTER_XT_ and its section.

>--- /dev/null
>+++ b/net/ipv4/netfilter/ipt_osf.c
>+
>+static inline int ipt_osf_ttl(const struct sk_buff *skb, struct ipt_osf_info *info,
>+			    unsigned char f_ttl)
>+{
>+	struct iphdr *ip = ip_hdr(skb);
>+
>+	if (info->flags & IPT_OSF_TTL) {
>+		if (info->ttl == IPT_OSF_TTL_TRUE)
>+			return (ip->ttl == f_ttl);
>+		if (info->ttl == IPT_OSF_TTL_NOCHECK)
>+			return 1;
>+		else if (ip->ttl <= f_ttl)
>+			return 1;
>+		else {
>+			struct in_device *in_dev = in_dev_get(skb->dev);
>+			int ret = 0;
>+
>+			for_ifa(in_dev) {
>+				if (inet_ifa_match(ip->saddr, ifa)) {
>+					ret = (ip->ttl == f_ttl);
>+					break;
>+				}
>+			}
>+			endfor_ifa(in_dev);
>+
>+			in_dev_put(in_dev);
>+			return ret;
>+		}
>+	}
>+	
>+	return (ip->ttl == f_ttl);
>+}
>+
>+static bool ipt_osf_match_packet(const struct sk_buff *skb,
>+		const struct xt_match_param *p)
>+{
>+	struct ipt_osf_info *info = (struct ipt_osf_info *)p->matchinfo;
>+	struct iphdr *ip;
>+	struct tcphdr _tcph, *tcp;
>+	int fmatch = FMATCH_WRONG, fcount = 0;
>+	unsigned int optsize = 0, check_WSS = 0;
>+	u16 window, totlen, mss = 0;
>+	unsigned char df, *optp = NULL, *_optp = NULL;

Maybe this should be 'bool df'?

>+	unsigned char opts[MAX_IPOPTLEN];
>+	struct ipt_osf_finger *kf;
>+	struct ipt_osf_user_finger *f;
>+	struct ipt_osf_finger_storage *st;
>+
>+	if (!info)
>+		return 0;

Use 'false' - the function returns bool.

>+
>+	ip = ip_hdr(skb);
>+	if (!ip)
>+		return 0;
>+
>+	tcp = skb_header_pointer(skb, ip->ihl * 4, sizeof(struct tcphdr), &_tcph);

Use ip_hdrlen(skb) instead of ihl*4.

>+	df = ((ntohs(ip->frag_off) & IP_DF) ? 1 : 0);

Together with bool df, it's just  df = ntohs(ip_frag_off) & IP_DF;

>+	st = &ipt_osf_fingers[!!df];

And the !! becomes redundant.

>+			for (optnum = 0; optnum < f->opt_num; ++optnum) {
>+				if (f->opt[optnum].kind == (*optp)) {
>+					__u32 len = f->opt[optnum].length;
>+					__u8 *optend = optp + len;
>+					int loop_cont = 0;
>+					
>+					fmatch = FMATCH_OK;
>+
>+					switch (*optp) {
>+					case OSFOPT_MSS:
>+						mss = ntohs(*(u16 *)(optp + 2));

This needs get_unaligned(), in case someone sends a malicious packet.

>+			if (info->flags & IPT_OSF_LOG)
>+				printk(KERN_INFO "%s [%s:%s] : "
>+					"%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n",
>+					f->genre, f->version, f->subtype, 
>+					NIPQUAD(ip->saddr), ntohs(tcp->source), 
>+					NIPQUAD(ip->daddr), ntohs(tcp->dest), 
>+					f->ttl - ip->ttl);

Dave told me NIPQUAD is slated for ripout. Though, I have not
looked if there is already a new format specifier for v4 addresses.

>+	return (fmatch == FMATCH_OK) ? 1 : 0;

Just fmatch == FMATCH_OK is sufficient for bool-returning functions.

>+static bool
>+ipt_osf_checkentry(const struct xt_mtchk_param *m)
>+{
>+	struct ipt_ip *ip = (struct ipt_ip *)m->entryinfo;
>+
>+	if (ip->proto != IPPROTO_TCP)
>+		return false;
>+
>+	return true;
>+}

Do this function via
	.proto = IPPROTO_TCP,
in the osf_match struct instead:

>+static struct xt_match ipt_osf_match = {
>+	.name 		= "osf",
>+	.revision	= 0,
>+	.family		= AF_INET,

	.family = NFPROTO_IPV4

>+	.hooks      	= (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_PRE_ROUTING),
>+	.match 		= ipt_osf_match_packet,
>+	.checkentry	= ipt_osf_checkentry,
>+	.matchsize	= sizeof(struct ipt_osf_info),
>+	.me		= THIS_MODULE,
>+};

>+	if (kf) {
>+		spin_lock_bh(&st->finger_lock);
>+		list_add_tail_rcu(&kf->finger_entry, &st->finger_list);
>+		spin_unlock_bh(&st->finger_lock);
>+
>+		printk("%s: added rule for %s:%s:%s.\n", __func__, kf->finger.genre, kf->finger.version, kf->finger.subtype);

Missing verbosity level.

>+static void __devexit ipt_osf_fini(void)

Why __devinit and __devexit, should not this be __init/__exit?

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux