Author: pluto Date: Thu Sep 15 08:19:36 2005 GMT Module: SOURCES Tag: LINUX_2_6 ---- Log message: - [base] osf match.
---- Files affected: SOURCES: linux-2.6-nf-osf.patch (NONE -> 1.1.2.1) (NEW) ---- Diffs: ================================================================ Index: SOURCES/linux-2.6-nf-osf.patch diff -u /dev/null SOURCES/linux-2.6-nf-osf.patch:1.1.2.1 --- /dev/null Thu Sep 15 10:19:36 2005 +++ SOURCES/linux-2.6-nf-osf.patch Thu Sep 15 10:19:31 2005 @@ -0,0 +1,1055 @@ + include/linux/netfilter_ipv4/ipt_osf.h | 151 +++++ + net/ipv4/netfilter/Kconfig | 22 + net/ipv4/netfilter/Makefile | 3 + net/ipv4/netfilter/ipt_osf.c | 854 +++++++++++++++++++++++++++++++++ + 4 files changed, 1030 insertions(+) + +diff -uNr linux-2.6.13.1/include.orig/linux/netfilter_ipv4/ipt_osf.h linux-2.6.13.1/include/linux/netfilter_ipv4/ipt_osf.h +--- linux-2.6.13.1/include.orig/linux/netfilter_ipv4/ipt_osf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.13.1/include/linux/netfilter_ipv4/ipt_osf.h 2005-09-15 10:18:40.315124250 +0200 +@@ -0,0 +1,151 @@ ++/* ++ * ipt_osf.h ++ * ++ * Copyright (c) 2003 Evgeniy Polyakov <[EMAIL PROTECTED]> ++ * ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef _IPT_OSF_H ++#define _IPT_OSF_H ++ ++#define MAXGENRELEN 32 ++#define MAXDETLEN 64 ++ ++#define IPT_OSF_GENRE 1 ++#define IPT_OSF_SMART 2 ++#define IPT_OSF_LOG 4 ++#define IPT_OSF_NETLINK 8 ++#define IPT_OSF_CONNECTOR 16 ++ ++#define IPT_OSF_LOGLEVEL_ALL 0 ++#define IPT_OSF_LOGLEVEL_FIRST 1 ++ ++#ifndef __KERNEL__ ++#include <netinet/ip.h> ++#include <netinet/tcp.h> ++ ++struct list_head ++{ ++ struct list_head *prev, *next; ++}; ++#endif ++ ++struct ipt_osf_info ++{ ++ char genre[MAXGENRELEN]; ++ int len; ++ unsigned long flags; ++ int loglevel; ++ int invert; /* UNSUPPORTED */ ++}; ++ ++struct osf_wc ++{ ++ char wc; ++ unsigned long val; ++}; ++ ++/* This struct represents IANA options ++ * http://www.iana.org/assignments/tcp-parameters ++ */ ++struct osf_opt ++{ ++ unsigned char kind; ++ unsigned char length; ++ struct osf_wc wc; ++}; ++ ++struct osf_finger ++{ ++ struct list_head flist; ++ struct osf_wc wss; ++ unsigned char ttl; ++ unsigned char df; ++ unsigned long ss; ++ unsigned char genre[MAXGENRELEN]; ++ unsigned char version[MAXGENRELEN], subtype[MAXGENRELEN]; ++ ++ /* Not needed, but for consistency with original table from Michal Zalewski */ ++ unsigned char details[MAXDETLEN]; ++ ++ int opt_num; ++ struct osf_opt opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */ ++ ++}; ++ ++struct ipt_osf_nlmsg ++{ ++ struct osf_finger f; ++ struct iphdr ip; ++ struct tcphdr tcp; ++}; ++ ++#ifdef __KERNEL__ ++ ++#include <linux/list.h> ++#include <net/tcp.h> ++ ++ ++/* 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 */ ++/* Others are not used in current OSF */ ++ ++static struct osf_opt IANA_opts[] = ++{ ++ {0, 1,}, ++ {1, 1,}, ++ {2, 4,}, ++ {3, 3,}, ++ {4, 2,}, ++ {5, 1 ,}, /* SACK length is not defined */ ++ {6, 6,}, ++ {7, 6,}, ++ {8, 10,}, ++ {9, 2,}, ++ {10, 3,}, ++ {11, 1,}, /* CC: Suppose 1 */ ++ {12, 1,}, /* the same */ ++ {13, 1,}, /* and here too */ ++ {14, 3,}, ++ {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */ ++ {16, 1,}, ++ {17, 1,}, ++ {18, 3,}, ++ {19, 18,}, ++ {20, 1,}, ++ {21, 1,}, ++ {22, 1,}, ++ {23, 1,}, ++ {24, 1,}, ++ {25, 1,}, ++ {26, 1,}, ++}; ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _IPT_OSF_H */ +diff -uNr linux-2.6.13.1/net.orig/ipv4/netfilter/ipt_osf.c linux-2.6.13.1/net/ipv4/netfilter/ipt_osf.c +--- linux-2.6.13.1/net.orig/ipv4/netfilter/ipt_osf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.13.1/net/ipv4/netfilter/ipt_osf.c 2005-09-15 10:18:40.319124500 +0200 +@@ -0,0 +1,854 @@ ++/* ++ * ipt_osf.c ++ * ++ * Copyright (c) 2003-2005 Evgeniy Polyakov <[EMAIL PROTECTED]> ++ * ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++/* ++ * OS fingerprint matching module. ++ * It simply compares various parameters from SYN packet with ++ * some hardcoded ones. ++ * ++ * Original table was created by Michal Zalewski <[EMAIL PROTECTED]> ++ * for his p0f. ++ */ ++ ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/string.h> ++#include <linux/smp.h> ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/file.h> ++#include <linux/ip.h> ++#include <linux/proc_fs.h> ++#include <linux/fs.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/ctype.h> ++#include <linux/list.h> ++#include <linux/if.h> ++#include <linux/inetdevice.h> ++#include <net/ip.h> ++#include <linux/tcp.h> ++ ++#include <linux/netfilter_ipv4/ip_tables.h> ++ ++#include <linux/netfilter_ipv4/ipt_osf.h> ++ ++#define OSF_DEBUG ++ ++#ifdef OSF_DEBUG ++#define log(x...) printk(KERN_INFO "ipt_osf: " x) ++#define loga(x...) printk(x) ++#else ++#define log(x...) do {} while(0) ++#define loga(x...) do {} while(0) ++#endif ++ ++#define FMATCH_WRONG 0 ++#define FMATCH_OK 1 ++#define FMATCH_OPT_WRONG 2 ++ ++#define OPTDEL ',' ++#define OSFPDEL ':' ++#define MAXOPTSTRLEN 128 ++#define OSFFLUSH "FLUSH" ++ ++static rwlock_t osf_lock = RW_LOCK_UNLOCKED; ++static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED; ++static struct list_head finger_list; ++static int match(const struct sk_buff *, const struct net_device *, const struct net_device *, ++ const void *, int, ++ int *); ++static int checkentry(const char *, const struct ipt_ip *, void *, ++ unsigned int, unsigned int); ++ ++static unsigned long seq, ipt_osf_groups = 1; ++static struct sock *nts; ++ ++static struct ipt_match osf_match = { ++ .name = "osf", ++ .match = &match, ++ .checkentry = &checkentry, ++ .me = THIS_MODULE ++}; ++ ++ ++#ifdef CONFIG_CONNECTOR ++#include <linux/connector.h> ++ ++/* ++ * They should live in connector.h. ++ */ ++#define CN_IDX_OSF 0x0001 ++#define CN_VAL_OSF 0x0000 ++ ++static char osf_finger_buf[sizeof(struct ipt_osf_nlmsg) + sizeof(struct cn_msg)]; ++static struct cb_id osf_id = {CN_IDX_OSF, CN_VAL_OSF}; ++static u32 osf_seq; ++ ++static void ipt_osf_send_connector(struct osf_finger *f, const struct sk_buff *sk) ++{ ++ struct cn_msg *m; ++ struct ipt_osf_nlmsg *data; ++ ++ m = (struct cn_msg *)osf_finger_buf; ++ data = (struct ipt_osf_nlmsg *)(m+1); ++ ++ memcpy(&m->id, &osf_id, sizeof(m->id)); ++ m->seq = osf_seq++; ++ m->ack = 0; ++ m->len = sizeof(*data); ++ ++ memcpy(&data->f, f, sizeof(struct osf_finger)); ++ memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr)); ++ memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr)); ++ ++ cn_netlink_send(m, m->id.idx, GFP_ATOMIC); ++} ++#else ++static void ipt_osf_send_connector(struct osf_finger *f, const struct sk_buff *sk) ++{ ++} ++#endif ++ ++static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk) ++{ ++ unsigned int size; ++ struct sk_buff *skb; ++ struct ipt_osf_nlmsg *data; ++ struct nlmsghdr *nlh; ++ ++ if (!nts) ++ return; ++ ++ size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg)); ++ ++ skb = alloc_skb(size, GFP_ATOMIC); ++ if (!skb) { ++ log("skb_alloc() failed.\n"); ++ return; ++ } ++ ++ nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh)); ++ ++ data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh); ++ ++ memcpy(&data->f, f, sizeof(struct osf_finger)); ++ memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr)); ++ memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr)); ++ ++ NETLINK_CB(skb).dst_groups = ipt_osf_groups; ++ netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC); ++ ++nlmsg_failure: ++ return; ++} ++ ++static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl) ++{ ++ struct iphdr *ip = skb->nh.iph; ++ ++ if (flags & IPT_OSF_SMART) { ++ struct in_device *in_dev = in_dev_get(skb->dev); ++ ++ for_ifa(in_dev) { ++ if (inet_ifa_match(ip->saddr, ifa)) { ++ in_dev_put(in_dev); ++ return (ip->ttl == f_ttl); ++ } ++ } ++ endfor_ifa(in_dev); ++ ++ in_dev_put(in_dev); ++ return (ip->ttl <= f_ttl); ++ } ++ else ++ return (ip->ttl == f_ttl); ++} ++ ++static int ++match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, ++ const void *matchinfo, int offset, ++ int *hotdrop) ++{ ++ struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo; ++ struct iphdr _iph, *ip; ++ struct tcphdr _tcph, *tcp; ++ int fmatch = FMATCH_WRONG, fcount = 0; ++ unsigned long totlen, optsize = 0, window; ++ unsigned char df, *optp = NULL, *_optp = NULL; ++ unsigned char opts[MAX_IPOPTLEN]; ++ char check_WSS = 0; ++ struct osf_finger *f; ++ int off; ++ ++ if (!info) ++ return 0; ++ ++ off = 0; ++ ++ ip = skb_header_pointer(skb, off, sizeof(_iph), &_iph); ++ if (!ip) ++ return 0; ++ ++ tcp = skb_header_pointer(skb, off + ip->ihl * 4, sizeof(_tcph), &_tcph); ++ if (!tcp) ++ return 0; ++ ++ if (!tcp->syn) ++ return 0; ++ ++ totlen = ntohs(ip->tot_len); ++ df = ((ntohs(ip->frag_off) & IP_DF)?1:0); ++ window = ntohs(tcp->window); ++ ++ if (tcp->doff*4 > sizeof(struct tcphdr)) { ++ optsize = tcp->doff*4 - sizeof(struct tcphdr); ++ ++ if (optsize > sizeof(opts)) { ++ log("%s: BUG: too big options size: optsize=%lu, max=%zu.\n", ++ __func__, optsize, sizeof(opts)); ++ optsize = sizeof(opts); ++ } ++ ++ _optp = optp = skb_header_pointer(skb, off + ip->ihl*4 + sizeof(_tcph), optsize, opts); ++ } ++ ++ /* Actually we can create hash/table of all genres and search ++ * only in appropriate part, but here is initial variant, ++ * so will use slow path. ++ */ ++ read_lock(&osf_lock); ++ list_for_each_entry(f, &finger_list, flist) { ++ ++ if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre)) ++ continue; ++ ++ optp = _optp; ++ fmatch = FMATCH_WRONG; ++ ++ if (totlen == f->ss && df == f->df && ++ smart_dec(skb, info->flags, f->ttl)) { ++ unsigned long foptsize; ++ int optnum; ++ unsigned short mss = 0; ++ ++ check_WSS = 0; ++ ++ switch (f->wss.wc) { ++ case 0: check_WSS = 0; break; ++ case 'S': check_WSS = 1; break; ++ case 'T': check_WSS = 2; break; ++ case '%': check_WSS = 3; break; ++ default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", ++ f->wss.wc, f->genre, f->details); ++ check_WSS = 4; ++ break; ++ } ++ if (check_WSS == 4) ++ continue; ++ ++ /* Check options */ ++ ++ foptsize = 0; ++ for (optnum=0; optnum<f->opt_num; ++optnum) ++ foptsize += f->opt[optnum].length; ++ ++ ++ if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize) ++ continue; ++ ++ if (!optp) { ++ fmatch = FMATCH_OK; ++ loga("\tYEP : matching without options.\n"); ++ if ((info->flags & IPT_OSF_LOG) && ++ info->loglevel == IPT_OSF_LOGLEVEL_FIRST) ++ break; ++ else ++ continue; ++ } ++ ++ for (optnum=0; optnum<f->opt_num; ++optnum) { ++ if (f->opt[optnum].kind == (*optp)) { ++ unsigned char len = f->opt[optnum].length; ++ unsigned char *optend = optp + len; ++ int loop_cont = 0; ++ ++ fmatch = FMATCH_OK; ++ ++ ++ switch (*optp) { ++ case OSFOPT_MSS: ++ mss = ntohs(*(unsigned short *)(optp+2)); ++ break; ++ case OSFOPT_TS: ++ loop_cont = 1; ++ break; ++ } ++ ++ if (loop_cont) { ++ optp = optend; ++ continue; ++ } ++ ++ if (len != 1) { ++ /* Skip kind and length fields*/ ++ optp += 2; ++ ++ if (f->opt[optnum].wc.val != 0) { ++ unsigned long tmp = 0; ++ ++ /* Hmmm... It looks a bit ugly. :) */ ++ memcpy(&tmp, optp, ++ (len > sizeof(unsigned long)? ++ sizeof(unsigned long):len)); ++ /* 2 + 2: optlen(2 bytes) + ++ * kind(1 byte) + length(1 byte) */ ++ if (len == 4) ++ tmp = ntohs(tmp); ++ else ++ tmp = ntohl(tmp); ++ ++ if (f->opt[optnum].wc.wc == '%') { ++ if ((tmp % f->opt[optnum].wc.val) != 0) ++ fmatch = FMATCH_OPT_WRONG; ++ } ++ else if (tmp != f->opt[optnum].wc.val) ++ fmatch = FMATCH_OPT_WRONG; ++ } ++ } ++ ++ optp = optend; ++ } else ++ fmatch = FMATCH_OPT_WRONG; ++ ++ if (fmatch != FMATCH_OK) ++ break; ++ } ++ ++ if (fmatch != FMATCH_OPT_WRONG) { ++ fmatch = FMATCH_WRONG; ++ ++ switch (check_WSS) { ++ case 0: ++ if (f->wss.val == 0 || window == f->wss.val) ++ fmatch = FMATCH_OK; ++ break; ++ case 1: /* MSS */ ++/* Lurked in OpenBSD */ ++#define SMART_MSS 1460 ++ if (window == f->wss.val*mss || ++ window == f->wss.val*SMART_MSS) ++ fmatch = FMATCH_OK; ++ break; ++ case 2: /* MTU */ ++ if (window == f->wss.val*(mss+40) || ++ window == f->wss.val*(SMART_MSS+40)) ++ fmatch = FMATCH_OK; ++ break; ++ case 3: /* MOD */ ++ if ((window % f->wss.val) == 0) ++ fmatch = FMATCH_OK; ++ break; ++ } ++ } ++ ++ ++ if (fmatch == FMATCH_OK) { ++ fcount++; ++ log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n", ++ f->genre, f->version, ++ f->subtype, f->details, ++ NIPQUAD(ip->saddr), ntohs(tcp->source), ++ NIPQUAD(ip->daddr), ntohs(tcp->dest), ++ f->ttl - ip->ttl); ++ if (info->flags & IPT_OSF_NETLINK) { ++ spin_lock_bh(&ipt_osf_netlink_lock); ++ ipt_osf_nlsend(f, skb); ++ spin_unlock_bh(&ipt_osf_netlink_lock); ++ } ++ if (info->flags & IPT_OSF_CONNECTOR) { ++ spin_lock_bh(&ipt_osf_netlink_lock); ++ ipt_osf_send_connector(f, skb); ++ spin_unlock_bh(&ipt_osf_netlink_lock); ++ } ++ if ((info->flags & IPT_OSF_LOG) && ++ info->loglevel == IPT_OSF_LOGLEVEL_FIRST) ++ break; ++ } ++ } ++ } ++ if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK | IPT_OSF_CONNECTOR))) { ++ unsigned char opt[4 * 15 - sizeof(struct tcphdr)]; ++ unsigned int i, optsize; ++ struct osf_finger fg; ++ ++ memset(&fg, 0, sizeof(fg)); ++ ++ if ((info->flags & IPT_OSF_LOG)) ++ log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen); ++ if (optp) { ++ optsize = tcp->doff * 4 - sizeof(struct tcphdr); ++ if (skb_copy_bits(skb, off + ip->ihl*4 + sizeof(struct tcphdr), ++ opt, optsize) < 0) { ++ if (info->flags & IPT_OSF_LOG) ++ loga("TRUNCATED"); ++ if (info->flags & IPT_OSF_NETLINK) ++ strcpy(fg.details, "TRUNCATED"); ++ } else { ++ for (i = 0; i < optsize; i++) { ++ if (info->flags & IPT_OSF_LOG) ++ loga("%02X", opt[i]); ++ } ++ if (info->flags & IPT_OSF_NETLINK) ++ memcpy(fg.details, opt, MAXDETLEN); ++ } ++ } ++ if ((info->flags & IPT_OSF_LOG)) ++ loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", <<Diff was trimmed, longer than 597 lines>> _______________________________________________ pld-cvs-commit mailing list pld-cvs-commit@lists.pld-linux.org http://lists.pld-linux.org/mailman/listinfo/pld-cvs-commit