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
 205        if (!info)
 206                return false;
 207
 208        tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph);
 209        if (!tcp)
 210                return false;
 211
 212        if (!tcp->syn)
 213                return false;
 214
 215        totlen = ntohs(ip->tot_len);
 216        df = ntohs(ip->frag_off) & IP_DF;
 217        window = ntohs(tcp->window);
 218
 219        if (tcp->doff * 4 > sizeof(struct tcphdr)) {
 220                optsize = tcp->doff * 4 - sizeof(struct tcphdr);
 221
 222                _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) +
 223                                sizeof(struct tcphdr), optsize, opts);
 224        }
 225
 226        rcu_read_lock();
 227        list_for_each_entry_rcu(kf, &xt_osf_fingers[df], finger_entry) {
 228                f = &kf->finger;
 229
 230                if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre))
 231                        continue;
 232
 233                optp = _optp;
 234                fmatch = FMATCH_WRONG;
 235
 236                if (totlen == f->ss && xt_osf_ttl(skb, info, f->ttl)) {
 237                        int foptsize, optnum;
 238
 239                        /*
 240                         * Should not happen if userspace parser was written correctly.
 241                         */
 242                        if (f->wss.wc >= OSF_WSS_MAX)
 243                                continue;
 244
 245                        /* Check options */
 246
 247                        foptsize = 0;
 248                        for (optnum = 0; optnum < f->opt_num; ++optnum)
 249                                foptsize += f->opt[optnum].length;
 250
 251                        if (foptsize > MAX_IPOPTLEN ||
 252                                optsize > MAX_IPOPTLEN ||
 253                                optsize != foptsize)
 254                                continue;
 255
 256                        check_WSS = f->wss.wc;
 257
 258                        for (optnum = 0; optnum < f->opt_num; ++optnum) {
 259                                if (f->opt[optnum].kind == (*optp)) {
 260                                        __u32 len = f->opt[optnum].length;
 261                                        const __u8 *optend = optp + len;
 262                                        int loop_cont = 0;
 263
 264                                        fmatch = FMATCH_OK;
 265
 266                                        switch (*optp) {
 267                                        case OSFOPT_MSS:
 268                                                mss = optp[3];
 269                                                mss <<= 8;
 270                                                mss |= optp[2];
 271
 272                                                mss = ntohs(mss);
 273                                                break;
 274                                        case OSFOPT_TS:
 275                                                loop_cont = 1;
 276                                                break;
 277                                        }
 278
 279                                        optp = optend;
 280                                } else
 281                                        fmatch = FMATCH_OPT_WRONG;
 282
 283                                if (fmatch != FMATCH_OK)
 284                                        break;
 285                        }
 286
 287                        if (fmatch != FMATCH_OPT_WRONG) {
 288                                fmatch = FMATCH_WRONG;
 289
 290                                switch (check_WSS) {
 291                                case OSF_WSS_PLAIN:
 292                                        if (f->wss.val == 0 || window == f->wss.val)
 293                                                fmatch = FMATCH_OK;
 294                                        break;
 295                                case OSF_WSS_MSS:
 296                                        /*
 297                                         * Some smart modems decrease mangle MSS to 
 298                                         * SMART_MSS_2, so we check standard, decreased
 299                                         * and the one provided in the fingerprint MSS
 300                                         * values.
 301                                         */
 302#define SMART_MSS_1     1460
 303#define SMART_MSS_2     1448
 304                                        if (window == f->wss.val * mss ||
 305                                            window == f->wss.val * SMART_MSS_1 ||
 306                                            window == f->wss.val * SMART_MSS_2)
 307                                                fmatch = FMATCH_OK;
 308                                        break;
 309                                case OSF_WSS_MTU:
 310                                        if (window == f->wss.val * (mss + 40) ||
 311                                            window == f->wss.val * (SMART_MSS_1 + 40) ||
 312                                            window == f->wss.val * (SMART_MSS_2 + 40))
 313                                                fmatch = FMATCH_OK;
 314                                        break;
 315                                case OSF_WSS_MODULO:
 316                                        if ((window % f->wss.val) == 0)
 317                                                fmatch = FMATCH_OK;
 318                                        break;
 319                                }
 320                        }
 321
 322                        if (fmatch != FMATCH_OK)
 323                                continue;
 324
 325                        fcount++;
 326
 327                        if (info->flags & XT_OSF_LOG)
 328                                nf_log_packet(p->family, p->hooknum, skb,
 329                                        p->in, p->out, NULL,
 330                                        "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
 331                                        f->genre, f->version, f->subtype,
 332                                        &ip->saddr, ntohs(tcp->source),
 333                                        &ip->daddr, ntohs(tcp->dest),
 334                                        f->ttl - ip->ttl);
 335
 336                        if ((info->flags & XT_OSF_LOG) &&
 337                            info->loglevel == XT_OSF_LOGLEVEL_FIRST)
 338                                break;
 339                }
 340        }
 341        rcu_read_unlock();
 342
 343        if (!fcount && (info->flags & XT_OSF_LOG))
 344                nf_log_packet(p->family, p->hooknum, skb, p->in, p->out, NULL,
 345                        "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
 346                                &ip->saddr, ntohs(tcp->source),
 347                                &ip->daddr, ntohs(tcp->dest));
 348
 349        if (fcount)
 350                fmatch = FMATCH_OK;
 351
 352        return fmatch == FMATCH_OK;
 353}
 354
 355static struct xt_match xt_osf_match = {
 356        .name           = "osf",
 357        .revision       = 0,
 358        .family         = NFPROTO_IPV4,
 359        .proto          = IPPROTO_TCP,
 360        .hooks          = (1 << NF_INET_LOCAL_IN) |
 361                                (1 << NF_INET_PRE_ROUTING) |
 362                                (1 << NF_INET_FORWARD),
 363        .match          = xt_osf_match_packet,
 364        .matchsize      = sizeof(struct xt_osf_info),
 365        .me             = THIS_MODULE,
 366};
 367
 368static int __init xt_osf_init(void)
 369{
 370        int err = -EINVAL;
 371        int i;
 372
 373        for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i)
 374                INIT_LIST_HEAD(&xt_osf_fingers[i]);
 375
 376        err = nfnetlink_subsys_register(&xt_osf_nfnetlink);
 377        if (err < 0) {
 378                pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err);
 379                goto err_out_exit;
 380        }
 381
 382        err = xt_register_match(&xt_osf_match);
 383        if (err) {
 384                pr_err("Failed to register OS fingerprint "
 385                       "matching module (%d)\n", err);
 386                goto err_out_remove;
 387        }
 388
 389        return 0;
 390
 391err_out_remove:
 392        nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
 393err_out_exit:
 394        return err;
 395}
 396
 397static void __exit xt_osf_fini(void)
 398{
 399        struct xt_osf_finger *f;
 400        int i;
 401
 402        nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
 403        xt_unregister_match(&xt_osf_match);
 404
 405        rcu_read_lock();
 406        for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i) {
 407
 408                list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) {
 409                        list_del_rcu(&f->finger_entry);
 410                        kfree_rcu(f, rcu_head);
 411                }
 412        }
 413        rcu_read_unlock();
 414
 415        rcu_barrier();
 416}
 417
 418module_init(xt_osf_init);
 419module_exit(xt_osf_fini);
 420
 421MODULE_LICENSE("GPL");
 422MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 423MODULE_DESCRIPTION("Passive OS fingerprint matching.");
 424MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);
 425
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.