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
  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 void xt_osf_finger_free_rcu(struct rcu_head *rcu_head)
  66{
  67        struct xt_osf_finger *f = container_of(rcu_head, struct xt_osf_finger, rcu_head);
  68
  69        kfree(f);
  70}
  71
  72static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb,
  73                               const struct nlmsghdr *nlh,
  74                               const struct nlattr * const osf_attrs[])
  75{
  76        struct xt_osf_user_finger *f;
  77        struct xt_osf_finger *kf = NULL, *sf;
  78        int err = 0;
  79
  80        if (!osf_attrs[OSF_ATTR_FINGER])
  81                return -EINVAL;
  82
  83        if (!(nlh->nlmsg_flags & NLM_F_CREATE))
  84                return -EINVAL;
  85
  86        f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
  87
  88        kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL);
  89        if (!kf)
  90                return -ENOMEM;
  91
  92        memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger));
  93
  94        list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
  95                if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
  96                        continue;
  97
  98                kfree(kf);
  99                kf = NULL;
 100
 101                if (nlh->nlmsg_flags & NLM_F_EXCL)
 102                        err = -EEXIST;
 103                break;
 104        }
 105
 106        /*
 107         * We are protected by nfnl mutex.
 108         */
 109        if (kf)
 110                list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]);
 111
 112        return err;
 113}
 114
 115static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb,
 116                                  const struct nlmsghdr *nlh,
 117                                  const struct nlattr * const osf_attrs[])
 118{
 119        struct xt_osf_user_finger *f;
 120        struct xt_osf_finger *sf;
 121        int err = -ENOENT;
 122
 123        if (!osf_attrs[OSF_ATTR_FINGER])
 124                return -EINVAL;
 125
 126        f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
 127
 128        list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
 129                if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
 130                        continue;
 131
 132                /*
 133                 * We are protected by nfnl mutex.
 134                 */
 135                list_del_rcu(&sf->finger_entry);
 136                call_rcu(&sf->rcu_head, xt_osf_finger_free_rcu);
 137
 138                err = 0;
 139                break;
 140        }
 141
 142        return err;
 143}
 144
 145static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = {
 146        [OSF_MSG_ADD]   = {
 147                .call           = xt_osf_add_callback,
 148                .attr_count     = OSF_ATTR_MAX,
 149                .policy         = xt_osf_policy,
 150        },
 151        [OSF_MSG_REMOVE]        = {
 152                .call           = xt_osf_remove_callback,
 153                .attr_count     = OSF_ATTR_MAX,
 154                .policy         = xt_osf_policy,
 155        },
 156};
 157
 158static const struct nfnetlink_subsystem xt_osf_nfnetlink = {
 159        .name                   = "osf",
 160        .subsys_id              = NFNL_SUBSYS_OSF,
 161        .cb_count               = OSF_MSG_MAX,
 162        .cb                     = xt_osf_nfnetlink_callbacks,
 163};
 164
 165static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info *info,
 166                            unsigned char f_ttl)
 167{
 168        const struct iphdr *ip = ip_hdr(skb);
 169
 170        if (info->flags & XT_OSF_TTL) {
 171                if (info->ttl == XT_OSF_TTL_TRUE)
 172                        return ip->ttl == f_ttl;
 173                if (info->ttl == XT_OSF_TTL_NOCHECK)
 174                        return 1;
 175                else if (ip->ttl <= f_ttl)
 176                        return 1;
 177                else {
 178                        struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
 179                        int ret = 0;
 180
 181                        for_ifa(in_dev) {
 182                                if (inet_ifa_match(ip->saddr, ifa)) {
 183                                        ret = (ip->ttl == f_ttl);
 184                                        break;
 185                                }
 186                        }
 187                        endfor_ifa(in_dev);
 188
 189                        return ret;
 190                }
 191        }
 192
 193        return ip->ttl == f_ttl;
 194}
 195
 196static bool xt_osf_match_packet(const struct sk_buff *skb,
 197                const struct xt_match_param *p)
 198{
 199        const struct xt_osf_info *info = p->matchinfo;
 200        const struct iphdr *ip = ip_hdr(skb);
 201        const struct tcphdr *tcp;
 202        struct tcphdr _tcph;
 203        int fmatch = FMATCH_WRONG, fcount = 0;
 204        unsigned int optsize = 0, check_WSS = 0;
 205        u16 window, totlen, mss = 0;
 206        bool df;
 207        const unsigned char *optp = NULL, *_optp = NULL;
 208        unsigned char opts[MAX_IPOPTLEN];
 209        const struct xt_osf_finger *kf;
 210        const struct xt_osf_user_finger *f;
 211
 212        if (!info)
 213                return false;
 214
 215        tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph);
 216        if (!tcp)
 217                return false;
 218
 219        if (!tcp->syn)
 220                return false;
 221
 222        totlen = ntohs(ip->tot_len);
 223        df = ntohs(ip->frag_off) & IP_DF;
 224        window = ntohs(tcp->window);
 225
 226        if (tcp->doff * 4 > sizeof(struct tcphdr)) {
 227                optsize = tcp->doff * 4 - sizeof(struct tcphdr);
 228
 229                _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) +
 230                                sizeof(struct tcphdr), optsize, opts);
 231        }
 232
 233        rcu_read_lock();
 234        list_for_each_entry_rcu(kf, &xt_osf_fingers[df], finger_entry) {
 235                f = &kf->finger;
 236
 237                if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre))
 238                        continue;
 239
 240                optp = _optp;
 241                fmatch = FMATCH_WRONG;
 242
 243                if (totlen == f->ss && xt_osf_ttl(skb, info, f->ttl)) {
 244                        int foptsize, optnum;
 245
 246                        /*
 247                         * Should not happen if userspace parser was written correctly.
 248                         */
 249                        if (f->wss.wc >= OSF_WSS_MAX)
 250                                continue;
 251
 252                        /* Check options */
 253
 254                        foptsize = 0;
 255                        for (optnum = 0; optnum < f->opt_num; ++optnum)
 256                                foptsize += f->opt[optnum].length;
 257
 258                        if (foptsize > MAX_IPOPTLEN ||
 259                                optsize > MAX_IPOPTLEN ||
 260                                optsize != foptsize)
 261                                continue;
 262
 263                        check_WSS = f->wss.wc;
 264
 265                        for (optnum = 0; optnum < f->opt_num; ++optnum) {
 266                                if (f->opt[optnum].kind == (*optp)) {
 267                                        __u32 len = f->opt[optnum].length;
 268                                        const __u8 *optend = optp + len;
 269                                        int loop_cont = 0;
 270
 271                                        fmatch = FMATCH_OK;
 272
 273                                        switch (*optp) {
 274                                        case OSFOPT_MSS:
 275                                                mss = optp[3];
 276                                                mss <<= 8;
 277                                                mss |= optp[2];
 278
 279                                                mss = ntohs(mss);
 280                                                break;
 281                                        case OSFOPT_TS:
 282                                                loop_cont = 1;
 283                                                break;
 284                                        }
 285
 286                                        optp = optend;
 287                                } else
 288                                        fmatch = FMATCH_OPT_WRONG;
 289
 290                                if (fmatch != FMATCH_OK)
 291                                        break;
 292                        }
 293
 294                        if (fmatch != FMATCH_OPT_WRONG) {
 295                                fmatch = FMATCH_WRONG;
 296
 297                                switch (check_WSS) {
 298                                case OSF_WSS_PLAIN:
 299                                        if (f->wss.val == 0 || window == f->wss.val)
 300                                                fmatch = FMATCH_OK;
 301                                        break;
 302                                case OSF_WSS_MSS:
 303                                        /*
 304                                         * Some smart modems decrease mangle MSS to 
 305                                         * SMART_MSS_2, so we check standard, decreased
 306                                         * and the one provided in the fingerprint MSS
 307                                         * values.
 308                                         */
 309#define SMART_MSS_1     1460
 310#define SMART_MSS_2     1448
 311                                        if (window == f->wss.val * mss ||
 312                                            window == f->wss.val * SMART_MSS_1 ||
 313                                            window == f->wss.val * SMART_MSS_2)
 314                                                fmatch = FMATCH_OK;
 315                                        break;
 316                                case OSF_WSS_MTU:
 317                                        if (window == f->wss.val * (mss + 40) ||
 318                                            window == f->wss.val * (SMART_MSS_1 + 40) ||
 319                                            window == f->wss.val * (SMART_MSS_2 + 40))
 320                                                fmatch = FMATCH_OK;
 321                                        break;
 322                                case OSF_WSS_MODULO:
 323                                        if ((window % f->wss.val) == 0)
 324                                                fmatch = FMATCH_OK;
 325                                        break;
 326                                }
 327                        }
 328
 329                        if (fmatch != FMATCH_OK)
 330                                continue;
 331
 332                        fcount++;
 333
 334                        if (info->flags & XT_OSF_LOG)
 335                                nf_log_packet(p->family, p->hooknum, skb,
 336                                        p->in, p->out, NULL,
 337                                        "%s [%s:%s] : %pi4:%d -> %pi4:%d hops=%d\n",
 338                                        f->genre, f->version, f->subtype,
 339                                        &ip->saddr, ntohs(tcp->source),
 340                                        &ip->daddr, ntohs(tcp->dest),
 341                                        f->ttl - ip->ttl);
 342
 343                        if ((info->flags & XT_OSF_LOG) &&
 344                            info->loglevel == XT_OSF_LOGLEVEL_FIRST)
 345                                break;
 346                }
 347        }
 348        rcu_read_unlock();
 349
 350        if (!fcount && (info->flags & XT_OSF_LOG))
 351                nf_log_packet(p->family, p->hooknum, skb, p->in, p->out, NULL,
 352                        "Remote OS is not known: %pi4:%u -> %pi4:%u\n",
 353                                &ip->saddr, ntohs(tcp->source),
 354                                &ip->daddr, ntohs(tcp->dest));
 355
 356        if (fcount)
 357                fmatch = FMATCH_OK;
 358
 359        return fmatch == FMATCH_OK;
 360}
 361
 362static struct xt_match xt_osf_match = {
 363        .name           = "osf",
 364        .revision       = 0,
 365        .family         = NFPROTO_IPV4,
 366        .proto          = IPPROTO_TCP,
 367        .hooks          = (1 << NF_INET_LOCAL_IN) |
 368                                (1 << NF_INET_PRE_ROUTING) |
 369                                (1 << NF_INET_FORWARD),
 370        .match          = xt_osf_match_packet,
 371        .matchsize      = sizeof(struct xt_osf_info),
 372        .me             = THIS_MODULE,
 373};
 374
 375static int __init xt_osf_init(void)
 376{
 377        int err = -EINVAL;
 378        int i;
 379
 380        for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i)
 381                INIT_LIST_HEAD(&xt_osf_fingers[i]);
 382
 383        err = nfnetlink_subsys_register(&xt_osf_nfnetlink);
 384        if (err < 0) {
 385                printk(KERN_ERR "Failed (%d) to register OSF nsfnetlink helper.\n", err);
 386                goto err_out_exit;
 387        }
 388
 389        err = xt_register_match(&xt_osf_match);
 390        if (err) {
 391                printk(KERN_ERR "Failed (%d) to register OS fingerprint "
 392                                "matching module.\n", err);
 393                goto err_out_remove;
 394        }
 395
 396        return 0;
 397
 398err_out_remove:
 399        nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
 400err_out_exit:
 401        return err;
 402}
 403
 404static void __exit xt_osf_fini(void)
 405{
 406        struct xt_osf_finger *f;
 407        int i;
 408
 409        nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
 410        xt_unregister_match(&xt_osf_match);
 411
 412        rcu_read_lock();
 413        for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i) {
 414
 415                list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) {
 416                        list_del_rcu(&f->finger_entry);
 417                        call_rcu(&f->rcu_head, xt_osf_finger_free_rcu);
 418                }
 419        }
 420        rcu_read_unlock();
 421
 422        rcu_barrier();
 423}
 424
 425module_init(xt_osf_init);
 426module_exit(xt_osf_fini);
 427
 428MODULE_LICENSE("GPL");
 429MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 430MODULE_DESCRIPTION("Passive OS fingerprint matching.");
 431MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);
 432