1/* 2 * ebt_arp 3 * 4 * Authors: 5 * Bart De Schuymer <bdschuym@pandora.be> 6 * Tim Gardner <timg@tpi.com> 7 * 8 * April, 2002 9 * 10 */ 11#include <linux/if_arp.h> 12#include <linux/if_ether.h> 13#include <linux/module.h> 14#include <linux/netfilter/x_tables.h> 15#include <linux/netfilter_bridge/ebtables.h> 16#include <linux/netfilter_bridge/ebt_arp.h> 17 18static bool 19ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) 20{ 21 const struct ebt_arp_info *info = par->matchinfo; 22 const struct arphdr *ah; 23 struct arphdr _arph; 24 25 ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); 26 if (ah == NULL) 27 return false; 28 if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != 29 ah->ar_op, EBT_ARP_OPCODE)) 30 return false; 31 if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != 32 ah->ar_hrd, EBT_ARP_HTYPE)) 33 return false; 34 if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != 35 ah->ar_pro, EBT_ARP_PTYPE)) 36 return false; 37 38 if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) { 39 const __be32 *sap, *dap; 40 __be32 saddr, daddr; 41 42 if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP)) 43 return false; 44 sap = skb_header_pointer(skb, sizeof(struct arphdr) + 45 ah->ar_hln, sizeof(saddr), 46 &saddr); 47 if (sap == NULL) 48 return false; 49 dap = skb_header_pointer(skb, sizeof(struct arphdr) + 50 2*ah->ar_hln+sizeof(saddr), 51 sizeof(daddr), &daddr); 52 if (dap == NULL) 53 return false; 54 if (info->bitmask & EBT_ARP_SRC_IP && 55 FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP)) 56 return false; 57 if (info->bitmask & EBT_ARP_DST_IP && 58 FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP)) 59 return false; 60 if (info->bitmask & EBT_ARP_GRAT && 61 FWINV(*dap != *sap, EBT_ARP_GRAT)) 62 return false; 63 } 64 65 if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { 66 const unsigned char *mp; 67 unsigned char _mac[ETH_ALEN]; 68 uint8_t verdict, i; 69 70 if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER)) 71 return false; 72 if (info->bitmask & EBT_ARP_SRC_MAC) { 73 mp = skb_header_pointer(skb, sizeof(struct arphdr), 74 sizeof(_mac), &_mac); 75 if (mp == NULL) 76 return false; 77 verdict = 0; 78 for (i = 0; i < 6; i++) 79 verdict |= (mp[i] ^ info->smaddr[i]) & 80 info->smmsk[i]; 81 if (FWINV(verdict != 0, EBT_ARP_SRC_MAC)) 82 return false; 83 } 84 85 if (info->bitmask & EBT_ARP_DST_MAC) { 86 mp = skb_header_pointer(skb, sizeof(struct arphdr) + 87 ah->ar_hln + ah->ar_pln, 88 sizeof(_mac), &_mac); 89 if (mp == NULL) 90 return false; 91 verdict = 0; 92 for (i = 0; i < 6; i++) 93 verdict |= (mp[i] ^ info->dmaddr[i]) & 94 info->dmmsk[i]; 95 if (FWINV(verdict != 0, EBT_ARP_DST_MAC)) 96 return false; 97 } 98 } 99 100 return true; 101} 102 103static int ebt_arp_mt_check(const struct xt_mtchk_param *par) 104{ 105 const struct ebt_arp_info *info = par->matchinfo; 106 const struct ebt_entry *e = par->entryinfo; 107 108 if ((e->ethproto != htons(ETH_P_ARP) && 109 e->ethproto != htons(ETH_P_RARP)) || 110 e->invflags & EBT_IPROTO) 111 return -EINVAL; 112 if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK) 113 return -EINVAL; 114 return 0; 115} 116 117static struct xt_match ebt_arp_mt_reg __read_mostly = { 118 .name = "arp", 119 .revision = 0, 120 .family = NFPROTO_BRIDGE, 121 .match = ebt_arp_mt, 122 .checkentry = ebt_arp_mt_check, 123 .matchsize = sizeof(struct ebt_arp_info), 124 .me = THIS_MODULE, 125}; 126 127static int __init ebt_arp_init(void) 128{ 129 return xt_register_match(&ebt_arp_mt_reg); 130} 131 132static void __exit ebt_arp_fini(void) 133{ 134 xt_unregister_match(&ebt_arp_mt_reg); 135} 136 137module_init(ebt_arp_init); 138module_exit(ebt_arp_fini); 139MODULE_DESCRIPTION("Ebtables: ARP protocol packet match"); 140MODULE_LICENSE("GPL"); 141