linux/net/bridge/netfilter/ebt_among.c
<<
>>
Prefs
   1/*
   2 *  ebt_among
   3 *
   4 *      Authors:
   5 *      Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
   6 *
   7 *  August, 2003
   8 *
   9 */
  10#include <linux/ip.h>
  11#include <linux/if_arp.h>
  12#include <linux/module.h>
  13#include <linux/netfilter/x_tables.h>
  14#include <linux/netfilter_bridge/ebtables.h>
  15#include <linux/netfilter_bridge/ebt_among.h>
  16
  17static bool ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
  18                                      const char *mac, __be32 ip)
  19{
  20        /* You may be puzzled as to how this code works.
  21         * Some tricks were used, refer to
  22         *      include/linux/netfilter_bridge/ebt_among.h
  23         * as there you can find a solution of this mystery.
  24         */
  25        const struct ebt_mac_wormhash_tuple *p;
  26        int start, limit, i;
  27        uint32_t cmp[2] = { 0, 0 };
  28        int key = ((const unsigned char *)mac)[5];
  29
  30        memcpy(((char *) cmp) + 2, mac, 6);
  31        start = wh->table[key];
  32        limit = wh->table[key + 1];
  33        if (ip) {
  34                for (i = start; i < limit; i++) {
  35                        p = &wh->pool[i];
  36                        if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0])
  37                                if (p->ip == 0 || p->ip == ip)
  38                                        return true;
  39                }
  40        } else {
  41                for (i = start; i < limit; i++) {
  42                        p = &wh->pool[i];
  43                        if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0])
  44                                if (p->ip == 0)
  45                                        return true;
  46                }
  47        }
  48        return false;
  49}
  50
  51static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
  52                                            *wh)
  53{
  54        int i;
  55
  56        for (i = 0; i < 256; i++) {
  57                if (wh->table[i] > wh->table[i + 1])
  58                        return -0x100 - i;
  59                if (wh->table[i] < 0)
  60                        return -0x200 - i;
  61                if (wh->table[i] > wh->poolsize)
  62                        return -0x300 - i;
  63        }
  64        if (wh->table[256] > wh->poolsize)
  65                return -0xc00;
  66        return 0;
  67}
  68
  69static int get_ip_dst(const struct sk_buff *skb, __be32 *addr)
  70{
  71        if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
  72                const struct iphdr *ih;
  73                struct iphdr _iph;
  74
  75                ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
  76                if (ih == NULL)
  77                        return -1;
  78                *addr = ih->daddr;
  79        } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
  80                const struct arphdr *ah;
  81                struct arphdr _arph;
  82                const __be32 *bp;
  83                __be32 buf;
  84
  85                ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
  86                if (ah == NULL ||
  87                    ah->ar_pln != sizeof(__be32) ||
  88                    ah->ar_hln != ETH_ALEN)
  89                        return -1;
  90                bp = skb_header_pointer(skb, sizeof(struct arphdr) +
  91                                        2 * ETH_ALEN + sizeof(__be32),
  92                                        sizeof(__be32), &buf);
  93                if (bp == NULL)
  94                        return -1;
  95                *addr = *bp;
  96        }
  97        return 0;
  98}
  99
 100static int get_ip_src(const struct sk_buff *skb, __be32 *addr)
 101{
 102        if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
 103                const struct iphdr *ih;
 104                struct iphdr _iph;
 105
 106                ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
 107                if (ih == NULL)
 108                        return -1;
 109                *addr = ih->saddr;
 110        } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
 111                const struct arphdr *ah;
 112                struct arphdr _arph;
 113                const __be32 *bp;
 114                __be32 buf;
 115
 116                ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
 117                if (ah == NULL ||
 118                    ah->ar_pln != sizeof(__be32) ||
 119                    ah->ar_hln != ETH_ALEN)
 120                        return -1;
 121                bp = skb_header_pointer(skb, sizeof(struct arphdr) +
 122                                        ETH_ALEN, sizeof(__be32), &buf);
 123                if (bp == NULL)
 124                        return -1;
 125                *addr = *bp;
 126        }
 127        return 0;
 128}
 129
 130static bool
 131ebt_among_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 132{
 133        const struct ebt_among_info *info = par->matchinfo;
 134        const char *dmac, *smac;
 135        const struct ebt_mac_wormhash *wh_dst, *wh_src;
 136        __be32 dip = 0, sip = 0;
 137
 138        wh_dst = ebt_among_wh_dst(info);
 139        wh_src = ebt_among_wh_src(info);
 140
 141        if (wh_src) {
 142                smac = eth_hdr(skb)->h_source;
 143                if (get_ip_src(skb, &sip))
 144                        return false;
 145                if (!(info->bitmask & EBT_AMONG_SRC_NEG)) {
 146                        /* we match only if it contains */
 147                        if (!ebt_mac_wormhash_contains(wh_src, smac, sip))
 148                                return false;
 149                } else {
 150                        /* we match only if it DOES NOT contain */
 151                        if (ebt_mac_wormhash_contains(wh_src, smac, sip))
 152                                return false;
 153                }
 154        }
 155
 156        if (wh_dst) {
 157                dmac = eth_hdr(skb)->h_dest;
 158                if (get_ip_dst(skb, &dip))
 159                        return false;
 160                if (!(info->bitmask & EBT_AMONG_DST_NEG)) {
 161                        /* we match only if it contains */
 162                        if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip))
 163                                return false;
 164                } else {
 165                        /* we match only if it DOES NOT contain */
 166                        if (ebt_mac_wormhash_contains(wh_dst, dmac, dip))
 167                                return false;
 168                }
 169        }
 170
 171        return true;
 172}
 173
 174static bool ebt_among_mt_check(const struct xt_mtchk_param *par)
 175{
 176        const struct ebt_among_info *info = par->matchinfo;
 177        const struct ebt_entry_match *em =
 178                container_of(par->matchinfo, const struct ebt_entry_match, data);
 179        int expected_length = sizeof(struct ebt_among_info);
 180        const struct ebt_mac_wormhash *wh_dst, *wh_src;
 181        int err;
 182
 183        wh_dst = ebt_among_wh_dst(info);
 184        wh_src = ebt_among_wh_src(info);
 185        expected_length += ebt_mac_wormhash_size(wh_dst);
 186        expected_length += ebt_mac_wormhash_size(wh_src);
 187
 188        if (em->match_size != EBT_ALIGN(expected_length)) {
 189                printk(KERN_WARNING
 190                       "ebtables: among: wrong size: %d "
 191                       "against expected %d, rounded to %Zd\n",
 192                       em->match_size, expected_length,
 193                       EBT_ALIGN(expected_length));
 194                return false;
 195        }
 196        if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
 197                printk(KERN_WARNING
 198                       "ebtables: among: dst integrity fail: %x\n", -err);
 199                return false;
 200        }
 201        if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
 202                printk(KERN_WARNING
 203                       "ebtables: among: src integrity fail: %x\n", -err);
 204                return false;
 205        }
 206        return true;
 207}
 208
 209static struct xt_match ebt_among_mt_reg __read_mostly = {
 210        .name           = "among",
 211        .revision       = 0,
 212        .family         = NFPROTO_BRIDGE,
 213        .match          = ebt_among_mt,
 214        .checkentry     = ebt_among_mt_check,
 215        .matchsize      = -1, /* special case */
 216        .me             = THIS_MODULE,
 217};
 218
 219static int __init ebt_among_init(void)
 220{
 221        return xt_register_match(&ebt_among_mt_reg);
 222}
 223
 224static void __exit ebt_among_fini(void)
 225{
 226        xt_unregister_match(&ebt_among_mt_reg);
 227}
 228
 229module_init(ebt_among_init);
 230module_exit(ebt_among_fini);
 231MODULE_DESCRIPTION("Ebtables: Combined MAC/IP address list matching");
 232MODULE_LICENSE("GPL");
 233