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 22struct tcpudphdr { 23 __be16 src; 24 __be16 dst; 25}; 26 27static bool 28ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) 29{ 30 const struct ebt_ip_info *info = par->matchinfo; 31 const struct iphdr *ih; 32 struct iphdr _iph; 33 const struct tcpudphdr *pptr; 34 struct tcpudphdr _ports; 35 36 ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); 37 if (ih == NULL) 38 return false; 39 if (info->bitmask & EBT_IP_TOS && 40 FWINV(info->tos != ih->tos, EBT_IP_TOS)) 41 return false; 42 if (info->bitmask & EBT_IP_SOURCE && 43 FWINV((ih->saddr & info->smsk) != 44 info->saddr, EBT_IP_SOURCE)) 45 return false; 46 if ((info->bitmask & EBT_IP_DEST) && 47 FWINV((ih->daddr & info->dmsk) != 48 info->daddr, EBT_IP_DEST)) 49 return false; 50 if (info->bitmask & EBT_IP_PROTO) { 51 if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO)) 52 return false; 53 if (!(info->bitmask & EBT_IP_DPORT) && 54 !(info->bitmask & EBT_IP_SPORT)) 55 return true; 56 if (ntohs(ih->frag_off) & IP_OFFSET) 57 return false; 58 pptr = skb_header_pointer(skb, ih->ihl*4, 59 sizeof(_ports), &_ports); 60 if (pptr == NULL) 61 return false; 62 if (info->bitmask & EBT_IP_DPORT) { 63 u32 dst = ntohs(pptr->dst); 64 if (FWINV(dst < info->dport[0] || 65 dst > info->dport[1], 66 EBT_IP_DPORT)) 67 return false; 68 } 69 if (info->bitmask & EBT_IP_SPORT) { 70 u32 src = ntohs(pptr->src); 71 if (FWINV(src < info->sport[0] || 72 src > info->sport[1], 73 EBT_IP_SPORT)) 74 return false; 75 } 76 } 77 return true; 78} 79 80static int ebt_ip_mt_check(const struct xt_mtchk_param *par) 81{ 82 const struct ebt_ip_info *info = par->matchinfo; 83 const struct ebt_entry *e = par->entryinfo; 84 85 if (e->ethproto != htons(ETH_P_IP) || 86 e->invflags & EBT_IPROTO) 87 return -EINVAL; 88 if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK) 89 return -EINVAL; 90 if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) { 91 if (info->invflags & EBT_IP_PROTO) 92 return -EINVAL; 93 if (info->protocol != IPPROTO_TCP && 94 info->protocol != IPPROTO_UDP && 95 info->protocol != IPPROTO_UDPLITE && 96 info->protocol != IPPROTO_SCTP && 97 info->protocol != IPPROTO_DCCP) 98 return -EINVAL; 99 } 100 if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1]) 101 return -EINVAL; 102 if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1]) 103 return -EINVAL; 104 return 0; 105} 106 107static struct xt_match ebt_ip_mt_reg __read_mostly = { 108 .name = "ip", 109 .revision = 0, 110 .family = NFPROTO_BRIDGE, 111 .match = ebt_ip_mt, 112 .checkentry = ebt_ip_mt_check, 113 .matchsize = sizeof(struct ebt_ip_info), 114 .me = THIS_MODULE, 115}; 116 117static int __init ebt_ip_init(void) 118{ 119 return xt_register_match(&ebt_ip_mt_reg); 120} 121 122static void __exit ebt_ip_fini(void) 123{ 124 xt_unregister_match(&ebt_ip_mt_reg); 125} 126 127module_init(ebt_ip_init); 128module_exit(ebt_ip_fini); 129MODULE_DESCRIPTION("Ebtables: IPv4 protocol packet match"); 130MODULE_LICENSE("GPL"); 131