|
@@ -37,21 +37,6 @@
|
|
|
#include <net/netfilter/nf_log.h>
|
|
|
#include <linux/netfilter/xt_osf.h>
|
|
|
|
|
|
-struct xt_osf_finger {
|
|
|
- struct rcu_head rcu_head;
|
|
|
- struct list_head finger_entry;
|
|
|
- struct xt_osf_user_finger finger;
|
|
|
-};
|
|
|
-
|
|
|
-enum osf_fmatch_states {
|
|
|
- /* Packet does not match the fingerprint */
|
|
|
- FMATCH_WRONG = 0,
|
|
|
- /* Packet matches the fingerprint */
|
|
|
- FMATCH_OK,
|
|
|
- /* Options do not match the fingerprint, but header does */
|
|
|
- FMATCH_OPT_WRONG,
|
|
|
-};
|
|
|
-
|
|
|
/*
|
|
|
* Indexed by dont-fragment bit.
|
|
|
* It is the only constant value in the fingerprint.
|
|
@@ -164,200 +149,17 @@ static const struct nfnetlink_subsystem xt_osf_nfnetlink = {
|
|
|
.cb = xt_osf_nfnetlink_callbacks,
|
|
|
};
|
|
|
|
|
|
-static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info *info,
|
|
|
- unsigned char f_ttl)
|
|
|
-{
|
|
|
- const struct iphdr *ip = ip_hdr(skb);
|
|
|
-
|
|
|
- if (info->flags & XT_OSF_TTL) {
|
|
|
- if (info->ttl == XT_OSF_TTL_TRUE)
|
|
|
- return ip->ttl == f_ttl;
|
|
|
- if (info->ttl == XT_OSF_TTL_NOCHECK)
|
|
|
- return 1;
|
|
|
- else if (ip->ttl <= f_ttl)
|
|
|
- return 1;
|
|
|
- else {
|
|
|
- struct in_device *in_dev = __in_dev_get_rcu(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);
|
|
|
-
|
|
|
- return ret;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return ip->ttl == f_ttl;
|
|
|
-}
|
|
|
-
|
|
|
static bool
|
|
|
xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
|
|
|
{
|
|
|
const struct xt_osf_info *info = p->matchinfo;
|
|
|
- const struct iphdr *ip = ip_hdr(skb);
|
|
|
- const struct tcphdr *tcp;
|
|
|
- struct tcphdr _tcph;
|
|
|
- int fmatch = FMATCH_WRONG, fcount = 0;
|
|
|
- unsigned int optsize = 0, check_WSS = 0;
|
|
|
- u16 window, totlen, mss = 0;
|
|
|
- bool df;
|
|
|
- const unsigned char *optp = NULL, *_optp = NULL;
|
|
|
- unsigned char opts[MAX_IPOPTLEN];
|
|
|
- const struct xt_osf_finger *kf;
|
|
|
- const struct xt_osf_user_finger *f;
|
|
|
struct net *net = xt_net(p);
|
|
|
|
|
|
if (!info)
|
|
|
return false;
|
|
|
|
|
|
- tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph);
|
|
|
- if (!tcp)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (!tcp->syn)
|
|
|
- return false;
|
|
|
-
|
|
|
- totlen = ntohs(ip->tot_len);
|
|
|
- df = ntohs(ip->frag_off) & IP_DF;
|
|
|
- window = ntohs(tcp->window);
|
|
|
-
|
|
|
- if (tcp->doff * 4 > sizeof(struct tcphdr)) {
|
|
|
- optsize = tcp->doff * 4 - sizeof(struct tcphdr);
|
|
|
-
|
|
|
- _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) +
|
|
|
- sizeof(struct tcphdr), optsize, opts);
|
|
|
- }
|
|
|
-
|
|
|
- list_for_each_entry_rcu(kf, &xt_osf_fingers[df], finger_entry) {
|
|
|
- int foptsize, optnum;
|
|
|
-
|
|
|
- f = &kf->finger;
|
|
|
-
|
|
|
- if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre))
|
|
|
- continue;
|
|
|
-
|
|
|
- optp = _optp;
|
|
|
- fmatch = FMATCH_WRONG;
|
|
|
-
|
|
|
- if (totlen != f->ss || !xt_osf_ttl(skb, info, f->ttl))
|
|
|
- continue;
|
|
|
-
|
|
|
- /*
|
|
|
- * Should not happen if userspace parser was written correctly.
|
|
|
- */
|
|
|
- if (f->wss.wc >= OSF_WSS_MAX)
|
|
|
- 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;
|
|
|
-
|
|
|
- check_WSS = f->wss.wc;
|
|
|
-
|
|
|
- for (optnum = 0; optnum < f->opt_num; ++optnum) {
|
|
|
- if (f->opt[optnum].kind == (*optp)) {
|
|
|
- __u32 len = f->opt[optnum].length;
|
|
|
- const __u8 *optend = optp + len;
|
|
|
-
|
|
|
- fmatch = FMATCH_OK;
|
|
|
-
|
|
|
- switch (*optp) {
|
|
|
- case OSFOPT_MSS:
|
|
|
- mss = optp[3];
|
|
|
- mss <<= 8;
|
|
|
- mss |= optp[2];
|
|
|
-
|
|
|
- mss = ntohs((__force __be16)mss);
|
|
|
- break;
|
|
|
- case OSFOPT_TS:
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- optp = optend;
|
|
|
- } else
|
|
|
- fmatch = FMATCH_OPT_WRONG;
|
|
|
-
|
|
|
- if (fmatch != FMATCH_OK)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (fmatch != FMATCH_OPT_WRONG) {
|
|
|
- fmatch = FMATCH_WRONG;
|
|
|
-
|
|
|
- switch (check_WSS) {
|
|
|
- case OSF_WSS_PLAIN:
|
|
|
- if (f->wss.val == 0 || window == f->wss.val)
|
|
|
- fmatch = FMATCH_OK;
|
|
|
- break;
|
|
|
- case OSF_WSS_MSS:
|
|
|
- /*
|
|
|
- * Some smart modems decrease mangle MSS to
|
|
|
- * SMART_MSS_2, so we check standard, decreased
|
|
|
- * and the one provided in the fingerprint MSS
|
|
|
- * values.
|
|
|
- */
|
|
|
-#define SMART_MSS_1 1460
|
|
|
-#define SMART_MSS_2 1448
|
|
|
- if (window == f->wss.val * mss ||
|
|
|
- window == f->wss.val * SMART_MSS_1 ||
|
|
|
- window == f->wss.val * SMART_MSS_2)
|
|
|
- fmatch = FMATCH_OK;
|
|
|
- break;
|
|
|
- case OSF_WSS_MTU:
|
|
|
- if (window == f->wss.val * (mss + 40) ||
|
|
|
- window == f->wss.val * (SMART_MSS_1 + 40) ||
|
|
|
- window == f->wss.val * (SMART_MSS_2 + 40))
|
|
|
- fmatch = FMATCH_OK;
|
|
|
- break;
|
|
|
- case OSF_WSS_MODULO:
|
|
|
- if ((window % f->wss.val) == 0)
|
|
|
- fmatch = FMATCH_OK;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (fmatch != FMATCH_OK)
|
|
|
- continue;
|
|
|
-
|
|
|
- fcount++;
|
|
|
-
|
|
|
- if (info->flags & XT_OSF_LOG)
|
|
|
- nf_log_packet(net, xt_family(p), xt_hooknum(p), skb,
|
|
|
- xt_in(p), xt_out(p), NULL,
|
|
|
- "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
|
|
|
- f->genre, f->version, f->subtype,
|
|
|
- &ip->saddr, ntohs(tcp->source),
|
|
|
- &ip->daddr, ntohs(tcp->dest),
|
|
|
- f->ttl - ip->ttl);
|
|
|
-
|
|
|
- if ((info->flags & XT_OSF_LOG) &&
|
|
|
- info->loglevel == XT_OSF_LOGLEVEL_FIRST)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (!fcount && (info->flags & XT_OSF_LOG))
|
|
|
- nf_log_packet(net, xt_family(p), xt_hooknum(p), skb, xt_in(p),
|
|
|
- xt_out(p), NULL,
|
|
|
- "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
|
|
|
- &ip->saddr, ntohs(tcp->source),
|
|
|
- &ip->daddr, ntohs(tcp->dest));
|
|
|
-
|
|
|
- if (fcount)
|
|
|
- fmatch = FMATCH_OK;
|
|
|
-
|
|
|
- return fmatch == FMATCH_OK;
|
|
|
+ return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p),
|
|
|
+ xt_out(p), info, net, xt_osf_fingers);
|
|
|
}
|
|
|
|
|
|
static struct xt_match xt_osf_match = {
|