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 17 static 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 51 static 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 69 static 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 100 static 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 130 static bool 131 ebt_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 174 static 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 209 static 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 219 static int __init ebt_among_init(void) 220 { 221 return xt_register_match(&ebt_among_mt_reg); 222 } 223 224 static void __exit ebt_among_fini(void) 225 { 226 xt_unregister_match(&ebt_among_mt_reg); 227 } 228 229 module_init(ebt_among_init); 230 module_exit(ebt_among_fini); 231 MODULE_DESCRIPTION("Ebtables: Combined MAC/IP address list matching"); 232 MODULE_LICENSE("GPL"); 233