linux/net/netfilter/xt_osf.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2003+ Evgeniy Polyakov <zbr@ioremap.net>
   3 *
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18 */
  19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  20#include <linux/module.h>
  21#include <linux/kernel.h>
  22
  23#include <linux/if.h>
  24#include <linux/inetdevice.h>
  25#include <linux/ip.h>
  26#include <linux/list.h>
  27#include <linux/rculist.h>
  28#include <linux/skbuff.h>
  29#include <linux/slab.h>
  30#include <linux/tcp.h>
  31
  32#include <net/ip.h>
  33#include <net/tcp.h>
  34
  35#include <linux/netfilter/nfnetlink.h>
  36#include <linux/netfilter/x_tables.h>
  37#include <net/netfilter/nf_log.h>
  38#include <linux/netfilter/xt_osf.h>
  39
  40struct xt_osf_finger {
  41        struct rcu_head                 rcu_head;
  42        struct list_head                finger_entry;
  43        struct xt_osf_user_finger       finger;
  44};
  45
  46enum osf_fmatch_states {
  47        /* Packet does not match the fingerprint */
  48        FMATCH_WRONG = 0,
  49        /* Packet matches the fingerprint */
  50        FMATCH_OK,
  51        /* Options do not match the fingerprint, but header does */
  52        FMATCH_OPT_WRONG,
  53};
  54
  55/*
  56 * Indexed by dont-fragment bit.
  57 * It is the only constant value in the fingerprint.
  58 */
  59static struct list_head xt_osf_fingers[2];
  60
  61static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = {
  62        [OSF_ATTR_FINGER]       = { .len = sizeof(struct xt_osf_user_finger) },
  63};
  64
  65static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb,
  66                               const struct nlmsghdr *nlh,
  67                               const struct nlattr * const osf_attrs[])
  68{
  69        struct xt_osf_user_finger *f;
  70        struct xt_osf_finger *kf = NULL, *sf;
  71        int err = 0;
  72
  73        if (!osf_attrs[OSF_ATTR_FINGER])
  74                return -EINVAL;
  75
  76        if (!(nlh->nlmsg_flags & NLM_F_CREATE))
  77                return -EINVAL;
  78
  79        f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
  80
  81        kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL);
  82        if (!kf)
  83                return -ENOMEM;
  84
  85        memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger));
  86
  87        list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
  88                if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
  89                        continue;
  90
  91                kfree(kf);
  92                kf = NULL;
  93
  94                if (nlh->nlmsg_flags & NLM_F_EXCL)
  95                        err = -EEXIST;
  96                break;
  97        }
  98
  99        /*
 100         * We are protected by nfnl mutex.
 101         */
 102        if (kf)
 103                list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]);
 104
 105        return err;
 106}
 107
 108static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb,
 109                                  const struct nlmsghdr *nlh,
 110                                  const struct nlattr * const osf_attrs[])
 111{
 112        struct xt_osf_user_finger *f;
 113        struct xt_osf_finger *sf;
 114        int err = -ENOENT;
 115
 116        if (!osf_attrs[OSF_ATTR_FINGER])
 117                return -EINVAL;
 118
 119        f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
 120
 121        list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
 122                if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
 123                        continue;
 124
 125                /*
 126                 * We are protected by nfnl mutex.
 127                 */
 128                list_del_rcu(&sf->finger_entry);
 129                kfree_rcu(sf, rcu_head);
 130
 131                err = 0;
 132                break;
 133        }
 134
 135        return err;
 136}
 137
 138static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = {
 139        [OSF_MSG_ADD]   = {
 140                .call           = xt_osf_add_callback,
 141                .attr_count     = OSF_ATTR_MAX,
 142                .policy         = xt_osf_policy,
 143        },
 144        [OSF_MSG_REMOVE]        = {
 145                .call           = xt_osf_remove_callback,
 146                .attr_count     = OSF_ATTR_MAX,
 147                .policy         = xt_osf_policy,
 148        },
 149};
 150
 151static const struct nfnetlink_subsystem xt_osf_nfnetlink = {
 152        .name                   = "osf",
 153        .subsys_id              = NFNL_SUBSYS_OSF,
 154        .cb_count               = OSF_MSG_MAX,
 155        .cb                     = xt_osf_nfnetlink_callbacks,
 156};
 157
 158static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info *info,
 159                            unsigned char f_ttl)
 160{
 161        const struct iphdr *ip = ip_hdr(skb);
 162
 163        if (info->flags & XT_OSF_TTL) {
 164                if (info->ttl == XT_OSF_TTL_TRUE)
 165                        return ip->ttl == f_ttl;
 166                if (info->ttl == XT_OSF_TTL_NOCHECK)
 167                        return 1;
 168                else if (ip->ttl <= f_ttl)
 169                        return 1;
 170                else {
 171                        struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
 172                        int ret = 0;
 173
 174                        for_ifa(in_dev) {
 175                                if (inet_ifa_match(ip->saddr, ifa)) {
 176                                        ret = (ip->ttl == f_ttl);
 177                                        break;
 178                                }
 179                        }
 180                        endfor_ifa(in_dev);
 181
 182                        return ret;
 183                }
 184        }
 185
 186        return ip->ttl == f_ttl;
 187}
 188
 189static bool
 190xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
 191{
 192        const struct xt_osf_info *info = p->matchinfo;
 193        const struct iphdr *ip = ip_hdr(skb);
 194        const struct tcphdr *tcp;
 195        struct tcphdr _tcph;
 196        int fmatch = FMATCH_WRONG, fcount = 0;
 197        unsigned int optsize = 0, check_WSS = 0;
 198        u16 window, totlen, mss = 0;
 199        bool df;
 200        const unsigned char *optp = NULL, *_optp = NULL;
 201        unsigned char opts[MAX_IPOPTLEN];
 202        const struct xt_osf_finger *kf;
 203        const struct xt_osf_user_finger *f;
 204        struct net *net = dev_net(p->in ? p->in : p->out);
 205
 206        if (!info)
 207                return false;
 208
 209        tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph);
 210        if (!tcp)
 211                return false;
 212
 213        if (!tcp->syn)
 214                return false;
 215
 216        totlen = ntohs(ip->tot_len);
 217        df = ntohs(ip->frag_off) & IP_DF;
 218        window = ntohs(tcp->window);
 219
 220        if (tcp->doff * 4 > sizeof(struct tcphdr)) {
 221                optsize = tcp->doff * 4 - sizeof(struct tcphdr);
 222
 223                _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) +
 224                                sizeof(struct tcphdr), optsize, opts);
 225        }
 226
 227        rcu_read_lock();
 228        list_for_each_entry_rcu(kf, &xt_osf_fingers[df], finger_entry) {
 229                f = &kf->finger;
 230
 231                if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre))
 232                        continue;
 233
 234                optp = _optp;
 235                fmatch = FMATCH_WRONG;
 236
 237                if (totlen == f->ss && xt_osf_ttl(skb, info, f->ttl)) {
 238                        int foptsize, optnum;
 239
 240                        /*
 241                         * Should not happen if userspace parser was written correctly.
 242                         */
 243                        if (f->wss.wc >= OSF_WSS_MAX)
 244                                continue;
 245
 246                        /* Check options */
 247
 248                        foptsize = 0;
 249                        for (optnum = 0; optnum < f->opt_num; ++optnum)
 250                                foptsize += f->opt[optnum].length;
 251
 252                        if (foptsize > MAX_IPOPTLEN ||
 253                                optsize > MAX_IPOPTLEN ||
 254                                optsize != foptsize)
 255                                continue;
 256
 257                        check_WSS = f->wss.wc;
 258
 259                        for (optnum = 0; optnum < f->opt_num; ++optnum) {
 260                                if (f->opt[optnum].kind == (*optp)) {
 261                                        __u32 len = f->opt[optnum].length;
 262                                        const __u8 *optend = optp + len;
 263                                        int loop_cont = 0;
 264
 265                                        fmatch = FMATCH_OK;
 266
 267                                        switch (*optp) {
 268                                        case OSFOPT_MSS:
 269                                                mss = optp[3];
 270                                                mss <<= 8;
 271                                                mss |= optp[2];
 272
 273                                                mss = ntohs((__force __be16)mss);
 274                                                break;
 275                                        case OSFOPT_TS:
 276                                                loop_cont = 1;
 277                                                break;
 278                                        }
 279
 280                                        optp = optend;
 281                                } else
 282                                        fmatch = FMATCH_OPT_WRONG;
 283
 284                                if (fmatch != FMATCH_OK)
 285                                        break;
 286                        }
 287
 288                        if (fmatch != FMATCH_OPT_WRONG) {
 289                                fmatch = FMATCH_WRONG;
 290
 291                                switch (check_WSS) {
 292                                case OSF_WSS_PLAIN:
 293                                        if (f->wss.val == 0 || window == f->wss.val)
 294                                                fmatch = FMATCH_OK;
 295                                        break;
 296                                case OSF_WSS_MSS:
 297                                        /*
 298                                         * Some smart modems decrease mangle MSS to 
 299                                         * SMART_MSS_2, so we check standard, decreased
 300                                         * and the one provided in the fingerprint MSS
 301                                         * values.
 302                                         */
 303#define SMART_MSS_1     1460
 304#define SMART_MSS_2     1448
 305                                        if (window == f->wss.val * mss ||
 306                                            window == f->wss.val * SMART_MSS_1 ||
 307                                            window == f->wss.val * SMART_MSS_2)
 308                                                fmatch = FMATCH_OK;
 309                                        break;
 310                                case OSF_WSS_MTU:
 311                                        if (window == f->wss.val * (mss + 40) ||
 312                                            window == f->wss.val * (SMART_MSS_1 + 40) ||
 313                                            window == f->wss.val * (SMART_MSS_2 + 40))
 314                                                fmatch = FMATCH_OK;
 315                                        break;
 316                                case OSF_WSS_MODULO:
 317                                        if ((window % f->wss.val) == 0)
 318                                                fmatch = FMATCH_OK;
 319                                        break;
 320                                }
 321                        }
 322
 323                        if (fmatch != FMATCH_OK)
 324                                continue;
 325
 326                        fcount++;
 327
 328                        if (info->flags & XT_OSF_LOG)
 329                                nf_log_packet(net, p->family, p->hooknum, skb,
 330                                        p->in, p->out, NULL,
 331                                        "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
 332                                        f->genre, f->version, f->subtype,
 333                                        &ip->saddr, ntohs(tcp->source),
 334                                        &ip->daddr, ntohs(tcp->dest),
 335                                        f->ttl - ip->ttl);
 336
 337                        if ((info->flags & XT_OSF_LOG) &&
 338                            info->loglevel == XT_OSF_LOGLEVEL_FIRST)
 339                                break;
 340                }
 341        }
 342        rcu_read_unlock();
 343
 344        if (!fcount && (info->flags & XT_OSF_LOG))
 345                nf_log_packet(net, p->family, p->hooknum, skb, p->in,
 346                              p->out, NULL,
 347                        "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
 348                                &ip->saddr, ntohs(tcp->source),
 349                                &ip->daddr, ntohs(tcp->dest));
 350
 351        if (fcount)
 352                fmatch = FMATCH_OK;
 353
 354        return fmatch == FMATCH_OK;
 355}
 356
 357static struct xt_match xt_osf_match = {
 358        .name           = "osf",
 359        .revision       = 0,
 360        .family         = NFPROTO_IPV4,
 361        .proto          = IPPROTO_TCP,
 362        .hooks          = (1 << NF_INET_LOCAL_IN) |
 363                                (1 << NF_INET_PRE_ROUTING) |
 364                                (1 << NF_INET_FORWARD),
 365        .match          = xt_osf_match_packet,
 366        .matchsize      = sizeof(struct xt_osf_info),
 367        .me             = THIS_MODULE,
 368};
 369
 370static int __init xt_osf_init(void)
 371{
 372        int err = -EINVAL;
 373        int i;
 374
 375        for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i)
 376                INIT_LIST_HEAD(&xt_osf_fingers[i]);
 377
 378        err = nfnetlink_subsys_register(&xt_osf_nfnetlink);
 379        if (err < 0) {
 380                pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err);
 381                goto err_out_exit;
 382        }
 383
 384        err = xt_register_match(&xt_osf_match);
 385        if (err) {
 386                pr_err("Failed to register OS fingerprint "
 387                       "matching module (%d)\n", err);
 388                goto err_out_remove;
 389        }
 390
 391        return 0;
 392
 393err_out_remove:
 394        nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
 395err_out_exit:
 396        return err;
 397}
 398
 399static void __exit xt_osf_fini(void)
 400{
 401        struct xt_osf_finger *f;
 402        int i;
 403
 404        nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
 405        xt_unregister_match(&xt_osf_match);
 406
 407        rcu_read_lock();
 408        for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i) {
 409
 410                list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) {
 411                        list_del_rcu(&f->finger_entry);
 412                        kfree_rcu(f, rcu_head);
 413                }
 414        }
 415        rcu_read_unlock();
 416
 417        rcu_barrier();
 418}
 419
 420module_init(xt_osf_init);
 421module_exit(xt_osf_fini);
 422
 423MODULE_LICENSE("GPL");
 424MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 425MODULE_DESCRIPTION("Passive OS fingerprint matching.");
 426MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);
 427
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.