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, see <http://www.gnu.org/licenses/>.
  17 */
  18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  19#include <linux/module.h>
  20#include <linux/kernel.h>
  21
  22#include <linux/if.h>
  23#include <linux/inetdevice.h>
  24#include <linux/ip.h>
  25#include <linux/list.h>
  26#include <linux/rculist.h>
  27#include <linux/skbuff.h>
  28#include <linux/slab.h>
  29#include <linux/tcp.h>
  30
  31#include <net/ip.h>
  32#include <net/tcp.h>
  33
  34#include <linux/netfilter/nfnetlink.h>
  35#include <linux/netfilter/x_tables.h>
  36#include <net/netfilter/nf_log.h>
  37#include <linux/netfilter/xt_osf.h>
  38
  39struct xt_osf_finger {
  40        struct rcu_head                 rcu_head;
  41        struct list_head                finger_entry;
  42        struct xt_osf_user_finger       finger;
  43};
  44
  45enum osf_fmatch_states {
  46        /* Packet does not match the fingerprint */
  47        FMATCH_WRONG = 0,
  48        /* Packet matches the fingerprint */
  49        FMATCH_OK,
  50        /* Options do not match the fingerprint, but header does */
  51        FMATCH_OPT_WRONG,
  52};
  53
  54/*
  55 * Indexed by dont-fragment bit.
  56 * It is the only constant value in the fingerprint.
  57 */
  58static struct list_head xt_osf_fingers[2];
  59
  60static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = {
  61        [OSF_ATTR_FINGER]       = { .len = sizeof(struct xt_osf_user_finger) },
  62};
  63
  64static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb,
  65                               const struct nlmsghdr *nlh,
  66                               const struct nlattr * const osf_attrs[])
  67{
  68        struct xt_osf_user_finger *f;
  69        struct xt_osf_finger *kf = NULL, *sf;
  70        int err = 0;
  71
  72        if (!osf_attrs[OSF_ATTR_FINGER])
  73                return -EINVAL;
  74
  75        if (!(nlh->nlmsg_flags & NLM_F_CREATE))
  76                return -EINVAL;
  77
  78        f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
  79
  80        kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL);
  81        if (!kf)
  82                return -ENOMEM;
  83
  84        memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger));
  85
  86        list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
  87                if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
  88                        continue;
  89
  90                kfree(kf);
  91                kf = NULL;
  92
  93                if (nlh->nlmsg_flags & NLM_F_EXCL)
  94                        err = -EEXIST;
  95                break;
  96        }
  97
  98        /*
  99         * We are protected by nfnl mutex.
 100         */
 101        if (kf)
 102                list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]);
 103
 104        return err;
 105}
 106
 107static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb,
 108                                  const struct nlmsghdr *nlh,
 109                                  const struct nlattr * const osf_attrs[])
 110{
 111        struct xt_osf_user_finger *f;
 112        struct xt_osf_finger *sf;
 113        int err = -ENOENT;
 114
 115        if (!osf_attrs[OSF_ATTR_FINGER])
 116                return -EINVAL;
 117
 118        f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
 119
 120        list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
 121                if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
 122                        continue;
 123
 124                /*
 125                 * We are protected by nfnl mutex.
 126                 */
 127                list_del_rcu(&sf->finger_entry);
 128                kfree_rcu(sf, rcu_head);
 129
 130                err = 0;
 131                break;
 132        }
 133
 134        return err;
 135}
 136
 137static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = {
 138        [OSF_MSG_ADD]   = {
 139                .call           = xt_osf_add_callback,
 140                .attr_count     = OSF_ATTR_MAX,
 141                .policy         = xt_osf_policy,
 142        },
 143        [OSF_MSG_REMOVE]        = {
 144                .call           = xt_osf_remove_callback,
 145                .attr_count     = OSF_ATTR_MAX,
 146                .policy         = xt_osf_policy,
 147        },
 148};
 149
 150static const struct nfnetlink_subsystem xt_osf_nfnetlink = {
 151        .name                   = "osf",
 152        .subsys_id              = NFNL_SUBSYS_OSF,
 153        .cb_count               = OSF_MSG_MAX,
 154        .cb                     = xt_osf_nfnetlink_callbacks,
 155};
 156
 157static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info *info,
 158                            unsigned char f_ttl)
 159{
 160        const struct iphdr *ip = ip_hdr(skb);
 161
 162        if (info->flags & XT_OSF_TTL) {
 163                if (info->ttl == XT_OSF_TTL_TRUE)
 164                        return ip->ttl == f_ttl;
 165                if (info->ttl == XT_OSF_TTL_NOCHECK)
 166                        return 1;
 167                else if (ip->ttl <= f_ttl)
 168                        return 1;
 169                else {
 170                        struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
 171                        int ret = 0;
 172
 173                        for_ifa(in_dev) {
 174                                if (inet_ifa_match(ip->saddr, ifa)) {
 175                                        ret = (ip->ttl == f_ttl);
 176                                        break;
 177                                }
 178                        }
 179                        endfor_ifa(in_dev);
 180
 181                        return ret;
 182                }
 183        }
 184
 185        return ip->ttl == f_ttl;
 186}
 187
 188static bool
 189xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
 190{
 191        const struct xt_osf_info *info = p->matchinfo;
 192        const struct iphdr *ip = ip_hdr(skb);
 193        const struct tcphdr *tcp;
 194        struct tcphdr _tcph;
 195        int fmatch = FMATCH_WRONG, fcount = 0;
 196        unsigned int optsize = 0, check_WSS = 0;
 197        u16 window, totlen, mss = 0;
 198        bool df;
 199        const unsigned char *optp = NULL, *_optp = NULL;
 200        unsigned char opts[MAX_IPOPTLEN];
 201        const struct xt_osf_finger *kf;
 202        const struct xt_osf_user_finger *f;
 203        struct net *net = dev_net(p->in ? p->in : p->out);
 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                int foptsize, optnum;
 229
 230                f = &kf->finger;
 231
 232                if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre))
 233                        continue;
 234
 235                optp = _optp;
 236                fmatch = FMATCH_WRONG;
 237
 238                if (totlen != f->ss || !xt_osf_ttl(skb, info, f->ttl))
 239                        continue;
 240
 241                /*
 242                 * Should not happen if userspace parser was written correctly.
 243                 */
 244                if (f->wss.wc >= OSF_WSS_MAX)
 245                        continue;
 246
 247                /* Check options */
 248
 249                foptsize = 0;
 250                for (optnum = 0; optnum < f->opt_num; ++optnum)
 251                        foptsize += f->opt[optnum].length;
 252
 253                if (foptsize > MAX_IPOPTLEN ||
 254                    optsize > MAX_IPOPTLEN ||
 255                    optsize != foptsize)
 256                        continue;
 257
 258                check_WSS = f->wss.wc;
 259
 260                for (optnum = 0; optnum < f->opt_num; ++optnum) {
 261                        if (f->opt[optnum].kind == (*optp)) {
 262                                __u32 len = f->opt[optnum].length;
 263                                const __u8 *optend = optp + len;
 264                                int loop_cont = 0;
 265
 266                                fmatch = FMATCH_OK;
 267
 268                                switch (*optp) {
 269                                case OSFOPT_MSS:
 270                                        mss = optp[3];
 271                                        mss <<= 8;
 272                                        mss |= optp[2];
 273
 274                                        mss = ntohs((__force __be16)mss);
 275                                        break;
 276                                case OSFOPT_TS:
 277                                        loop_cont = 1;
 278                                        break;
 279                                }
 280
 281                                optp = optend;
 282                        } else
 283                                fmatch = FMATCH_OPT_WRONG;
 284
 285                        if (fmatch != FMATCH_OK)
 286                                break;
 287                }
 288
 289                if (fmatch != FMATCH_OPT_WRONG) {
 290                        fmatch = FMATCH_WRONG;
 291
 292                        switch (check_WSS) {
 293                        case OSF_WSS_PLAIN:
 294                                if (f->wss.val == 0 || window == f->wss.val)
 295                                        fmatch = FMATCH_OK;
 296                                break;
 297                        case OSF_WSS_MSS:
 298                                /*
 299                                 * Some smart modems decrease mangle MSS to
 300                                 * SMART_MSS_2, so we check standard, decreased
 301                                 * and the one provided in the fingerprint MSS
 302                                 * values.
 303                                 */
 304#define SMART_MSS_1     1460
 305#define SMART_MSS_2     1448
 306                                if (window == f->wss.val * mss ||
 307                                    window == f->wss.val * SMART_MSS_1 ||
 308                                    window == f->wss.val * SMART_MSS_2)
 309                                        fmatch = FMATCH_OK;
 310                                break;
 311                        case OSF_WSS_MTU:
 312                                if (window == f->wss.val * (mss + 40) ||
 313                                    window == f->wss.val * (SMART_MSS_1 + 40) ||
 314                                    window == f->wss.val * (SMART_MSS_2 + 40))
 315                                        fmatch = FMATCH_OK;
 316                                break;
 317                        case OSF_WSS_MODULO:
 318                                if ((window % f->wss.val) == 0)
 319                                        fmatch = FMATCH_OK;
 320                                break;
 321                        }
 322                }
 323
 324                if (fmatch != FMATCH_OK)
 325                        continue;
 326
 327                fcount++;
 328
 329                if (info->flags & XT_OSF_LOG)
 330                        nf_log_packet(net, p->family, p->hooknum, skb,
 331                                      p->in, p->out, NULL,
 332                                      "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
 333                                      f->genre, f->version, f->subtype,
 334                                      &ip->saddr, ntohs(tcp->source),
 335                                      &ip->daddr, ntohs(tcp->dest),
 336                                      f->ttl - ip->ttl);
 337
 338                if ((info->flags & XT_OSF_LOG) &&
 339                    info->loglevel == XT_OSF_LOGLEVEL_FIRST)
 340                        break;
 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("ipt_osf");
 427MODULE_ALIAS("ip6t_osf");
 428MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);
 429