linux/net/netfilter/xt_multiport.c
<<
>>
Prefs
   1/* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports:
   2   ports are in the same place so we can treat them as equal. */
   3
   4/* (C) 1999-2001 Paul `Rusty' Russell
   5 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/types.h>
  14#include <linux/udp.h>
  15#include <linux/skbuff.h>
  16#include <linux/in.h>
  17
  18#include <linux/netfilter/xt_multiport.h>
  19#include <linux/netfilter/x_tables.h>
  20#include <linux/netfilter_ipv4/ip_tables.h>
  21#include <linux/netfilter_ipv6/ip6_tables.h>
  22
  23MODULE_LICENSE("GPL");
  24MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
  25MODULE_DESCRIPTION("Xtables: multiple port matching for TCP, UDP, UDP-Lite, SCTP and DCCP");
  26MODULE_ALIAS("ipt_multiport");
  27MODULE_ALIAS("ip6t_multiport");
  28
  29#if 0
  30#define duprintf(format, args...) printk(format , ## args)
  31#else
  32#define duprintf(format, args...)
  33#endif
  34
  35/* Returns 1 if the port is matched by the test, 0 otherwise. */
  36static inline bool
  37ports_match_v0(const u_int16_t *portlist, enum xt_multiport_flags flags,
  38               u_int8_t count, u_int16_t src, u_int16_t dst)
  39{
  40        unsigned int i;
  41        for (i = 0; i < count; i++) {
  42                if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src)
  43                        return true;
  44
  45                if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst)
  46                        return true;
  47        }
  48
  49        return false;
  50}
  51
  52/* Returns 1 if the port is matched by the test, 0 otherwise. */
  53static inline bool
  54ports_match_v1(const struct xt_multiport_v1 *minfo,
  55               u_int16_t src, u_int16_t dst)
  56{
  57        unsigned int i;
  58        u_int16_t s, e;
  59
  60        for (i = 0; i < minfo->count; i++) {
  61                s = minfo->ports[i];
  62
  63                if (minfo->pflags[i]) {
  64                        /* range port matching */
  65                        e = minfo->ports[++i];
  66                        duprintf("src or dst matches with %d-%d?\n", s, e);
  67
  68                        if (minfo->flags == XT_MULTIPORT_SOURCE
  69                            && src >= s && src <= e)
  70                                return true ^ minfo->invert;
  71                        if (minfo->flags == XT_MULTIPORT_DESTINATION
  72                            && dst >= s && dst <= e)
  73                                return true ^ minfo->invert;
  74                        if (minfo->flags == XT_MULTIPORT_EITHER
  75                            && ((dst >= s && dst <= e)
  76                                || (src >= s && src <= e)))
  77                                return true ^ minfo->invert;
  78                } else {
  79                        /* exact port matching */
  80                        duprintf("src or dst matches with %d?\n", s);
  81
  82                        if (minfo->flags == XT_MULTIPORT_SOURCE
  83                            && src == s)
  84                                return true ^ minfo->invert;
  85                        if (minfo->flags == XT_MULTIPORT_DESTINATION
  86                            && dst == s)
  87                                return true ^ minfo->invert;
  88                        if (minfo->flags == XT_MULTIPORT_EITHER
  89                            && (src == s || dst == s))
  90                                return true ^ minfo->invert;
  91                }
  92        }
  93
  94        return minfo->invert;
  95}
  96
  97static bool
  98multiport_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
  99{
 100        const __be16 *pptr;
 101        __be16 _ports[2];
 102        const struct xt_multiport *multiinfo = par->matchinfo;
 103
 104        if (par->fragoff != 0)
 105                return false;
 106
 107        pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports);
 108        if (pptr == NULL) {
 109                /* We've been asked to examine this packet, and we
 110                 * can't.  Hence, no choice but to drop.
 111                 */
 112                duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
 113                *par->hotdrop = true;
 114                return false;
 115        }
 116
 117        return ports_match_v0(multiinfo->ports, multiinfo->flags,
 118               multiinfo->count, ntohs(pptr[0]), ntohs(pptr[1]));
 119}
 120
 121static bool
 122multiport_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 123{
 124        const __be16 *pptr;
 125        __be16 _ports[2];
 126        const struct xt_multiport_v1 *multiinfo = par->matchinfo;
 127
 128        if (par->fragoff != 0)
 129                return false;
 130
 131        pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports);
 132        if (pptr == NULL) {
 133                /* We've been asked to examine this packet, and we
 134                 * can't.  Hence, no choice but to drop.
 135                 */
 136                duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
 137                *par->hotdrop = true;
 138                return false;
 139        }
 140
 141        return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
 142}
 143
 144static inline bool
 145check(u_int16_t proto,
 146      u_int8_t ip_invflags,
 147      u_int8_t match_flags,
 148      u_int8_t count)
 149{
 150        /* Must specify supported protocol, no unknown flags or bad count */
 151        return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
 152                || proto == IPPROTO_UDPLITE
 153                || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
 154                && !(ip_invflags & XT_INV_PROTO)
 155                && (match_flags == XT_MULTIPORT_SOURCE
 156                    || match_flags == XT_MULTIPORT_DESTINATION
 157                    || match_flags == XT_MULTIPORT_EITHER)
 158                && count <= XT_MULTI_PORTS;
 159}
 160
 161static bool multiport_mt_check_v0(const struct xt_mtchk_param *par)
 162{
 163        const struct ipt_ip *ip = par->entryinfo;
 164        const struct xt_multiport *multiinfo = par->matchinfo;
 165
 166        return check(ip->proto, ip->invflags, multiinfo->flags,
 167                     multiinfo->count);
 168}
 169
 170static bool multiport_mt_check(const struct xt_mtchk_param *par)
 171{
 172        const struct ipt_ip *ip = par->entryinfo;
 173        const struct xt_multiport_v1 *multiinfo = par->matchinfo;
 174
 175        return check(ip->proto, ip->invflags, multiinfo->flags,
 176                     multiinfo->count);
 177}
 178
 179static bool multiport_mt6_check_v0(const struct xt_mtchk_param *par)
 180{
 181        const struct ip6t_ip6 *ip = par->entryinfo;
 182        const struct xt_multiport *multiinfo = par->matchinfo;
 183
 184        return check(ip->proto, ip->invflags, multiinfo->flags,
 185                     multiinfo->count);
 186}
 187
 188static bool multiport_mt6_check(const struct xt_mtchk_param *par)
 189{
 190        const struct ip6t_ip6 *ip = par->entryinfo;
 191        const struct xt_multiport_v1 *multiinfo = par->matchinfo;
 192
 193        return check(ip->proto, ip->invflags, multiinfo->flags,
 194                     multiinfo->count);
 195}
 196
 197static struct xt_match multiport_mt_reg[] __read_mostly = {
 198        {
 199                .name           = "multiport",
 200                .family         = NFPROTO_IPV4,
 201                .revision       = 0,
 202                .checkentry     = multiport_mt_check_v0,
 203                .match          = multiport_mt_v0,
 204                .matchsize      = sizeof(struct xt_multiport),
 205                .me             = THIS_MODULE,
 206        },
 207        {
 208                .name           = "multiport",
 209                .family         = NFPROTO_IPV4,
 210                .revision       = 1,
 211                .checkentry     = multiport_mt_check,
 212                .match          = multiport_mt,
 213                .matchsize      = sizeof(struct xt_multiport_v1),
 214                .me             = THIS_MODULE,
 215        },
 216        {
 217                .name           = "multiport",
 218                .family         = NFPROTO_IPV6,
 219                .revision       = 0,
 220                .checkentry     = multiport_mt6_check_v0,
 221                .match          = multiport_mt_v0,
 222                .matchsize      = sizeof(struct xt_multiport),
 223                .me             = THIS_MODULE,
 224        },
 225        {
 226                .name           = "multiport",
 227                .family         = NFPROTO_IPV6,
 228                .revision       = 1,
 229                .checkentry     = multiport_mt6_check,
 230                .match          = multiport_mt,
 231                .matchsize      = sizeof(struct xt_multiport_v1),
 232                .me             = THIS_MODULE,
 233        },
 234};
 235
 236static int __init multiport_mt_init(void)
 237{
 238        return xt_register_matches(multiport_mt_reg,
 239               ARRAY_SIZE(multiport_mt_reg));
 240}
 241
 242static void __exit multiport_mt_exit(void)
 243{
 244        xt_unregister_matches(multiport_mt_reg, ARRAY_SIZE(multiport_mt_reg));
 245}
 246
 247module_init(multiport_mt_init);
 248module_exit(multiport_mt_exit);
 249