linux/net/bridge/netfilter/ebt_ip.c
<<
>>
Prefs
   1/*
   2 *  ebt_ip
   3 *
   4 *      Authors:
   5 *      Bart De Schuymer <bdschuym@pandora.be>
   6 *
   7 *  April, 2002
   8 *
   9 *  Changes:
  10 *    added ip-sport and ip-dport
  11 *    Innominate Security Technologies AG <mhopf@innominate.com>
  12 *    September, 2002
  13 */
  14#include <linux/ip.h>
  15#include <net/ip.h>
  16#include <linux/in.h>
  17#include <linux/module.h>
  18#include <linux/netfilter/x_tables.h>
  19#include <linux/netfilter_bridge/ebtables.h>
  20#include <linux/netfilter_bridge/ebt_ip.h>
  21
  22union pkthdr {
  23        struct {
  24                __be16 src;
  25                __be16 dst;
  26        } tcpudphdr;
  27        struct {
  28                u8 type;
  29                u8 code;
  30        } icmphdr;
  31        struct {
  32                u8 type;
  33        } igmphdr;
  34};
  35
  36static bool
  37ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par)
  38{
  39        const struct ebt_ip_info *info = par->matchinfo;
  40        const struct iphdr *ih;
  41        struct iphdr _iph;
  42        const union pkthdr *pptr;
  43        union pkthdr _pkthdr;
  44
  45        ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
  46        if (ih == NULL)
  47                return false;
  48        if ((info->bitmask & EBT_IP_TOS) &&
  49            NF_INVF(info, EBT_IP_TOS, info->tos != ih->tos))
  50                return false;
  51        if ((info->bitmask & EBT_IP_SOURCE) &&
  52            NF_INVF(info, EBT_IP_SOURCE,
  53                    (ih->saddr & info->smsk) != info->saddr))
  54                return false;
  55        if ((info->bitmask & EBT_IP_DEST) &&
  56            NF_INVF(info, EBT_IP_DEST,
  57                    (ih->daddr & info->dmsk) != info->daddr))
  58                return false;
  59        if (info->bitmask & EBT_IP_PROTO) {
  60                if (NF_INVF(info, EBT_IP_PROTO, info->protocol != ih->protocol))
  61                        return false;
  62                if (!(info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT |
  63                                       EBT_IP_ICMP | EBT_IP_IGMP)))
  64                        return true;
  65                if (ntohs(ih->frag_off) & IP_OFFSET)
  66                        return false;
  67
  68                /* min icmp/igmp headersize is 4, so sizeof(_pkthdr) is ok. */
  69                pptr = skb_header_pointer(skb, ih->ihl*4,
  70                                          sizeof(_pkthdr), &_pkthdr);
  71                if (pptr == NULL)
  72                        return false;
  73                if (info->bitmask & EBT_IP_DPORT) {
  74                        u32 dst = ntohs(pptr->tcpudphdr.dst);
  75                        if (NF_INVF(info, EBT_IP_DPORT,
  76                                    dst < info->dport[0] ||
  77                                    dst > info->dport[1]))
  78                                return false;
  79                }
  80                if (info->bitmask & EBT_IP_SPORT) {
  81                        u32 src = ntohs(pptr->tcpudphdr.src);
  82                        if (NF_INVF(info, EBT_IP_SPORT,
  83                                    src < info->sport[0] ||
  84                                    src > info->sport[1]))
  85                                return false;
  86                }
  87                if ((info->bitmask & EBT_IP_ICMP) &&
  88                    NF_INVF(info, EBT_IP_ICMP,
  89                            pptr->icmphdr.type < info->icmp_type[0] ||
  90                            pptr->icmphdr.type > info->icmp_type[1] ||
  91                            pptr->icmphdr.code < info->icmp_code[0] ||
  92                            pptr->icmphdr.code > info->icmp_code[1]))
  93                        return false;
  94                if ((info->bitmask & EBT_IP_IGMP) &&
  95                    NF_INVF(info, EBT_IP_IGMP,
  96                            pptr->igmphdr.type < info->igmp_type[0] ||
  97                            pptr->igmphdr.type > info->igmp_type[1]))
  98                        return false;
  99        }
 100        return true;
 101}
 102
 103static int ebt_ip_mt_check(const struct xt_mtchk_param *par)
 104{
 105        const struct ebt_ip_info *info = par->matchinfo;
 106        const struct ebt_entry *e = par->entryinfo;
 107
 108        if (e->ethproto != htons(ETH_P_IP) ||
 109           e->invflags & EBT_IPROTO)
 110                return -EINVAL;
 111        if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
 112                return -EINVAL;
 113        if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) {
 114                if (info->invflags & EBT_IP_PROTO)
 115                        return -EINVAL;
 116                if (info->protocol != IPPROTO_TCP &&
 117                    info->protocol != IPPROTO_UDP &&
 118                    info->protocol != IPPROTO_UDPLITE &&
 119                    info->protocol != IPPROTO_SCTP &&
 120                    info->protocol != IPPROTO_DCCP)
 121                         return -EINVAL;
 122        }
 123        if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1])
 124                return -EINVAL;
 125        if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
 126                return -EINVAL;
 127        if (info->bitmask & EBT_IP_ICMP) {
 128                if ((info->invflags & EBT_IP_PROTO) ||
 129                    info->protocol != IPPROTO_ICMP)
 130                        return -EINVAL;
 131                if (info->icmp_type[0] > info->icmp_type[1] ||
 132                    info->icmp_code[0] > info->icmp_code[1])
 133                        return -EINVAL;
 134        }
 135        if (info->bitmask & EBT_IP_IGMP) {
 136                if ((info->invflags & EBT_IP_PROTO) ||
 137                    info->protocol != IPPROTO_IGMP)
 138                        return -EINVAL;
 139                if (info->igmp_type[0] > info->igmp_type[1])
 140                        return -EINVAL;
 141        }
 142        return 0;
 143}
 144
 145static struct xt_match ebt_ip_mt_reg __read_mostly = {
 146        .name           = "ip",
 147        .revision       = 0,
 148        .family         = NFPROTO_BRIDGE,
 149        .match          = ebt_ip_mt,
 150        .checkentry     = ebt_ip_mt_check,
 151        .matchsize      = sizeof(struct ebt_ip_info),
 152        .me             = THIS_MODULE,
 153};
 154
 155static int __init ebt_ip_init(void)
 156{
 157        return xt_register_match(&ebt_ip_mt_reg);
 158}
 159
 160static void __exit ebt_ip_fini(void)
 161{
 162        xt_unregister_match(&ebt_ip_mt_reg);
 163}
 164
 165module_init(ebt_ip_init);
 166module_exit(ebt_ip_fini);
 167MODULE_DESCRIPTION("Ebtables: IPv4 protocol packet match");
 168MODULE_LICENSE("GPL");
 169