1/* IP tables module for matching the value of the IPv4 and TCP ECN bits 2 * 3 * (C) 2002 by Harald Welte <laforge@gnumonks.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10#include <linux/in.h> 11#include <linux/ip.h> 12#include <net/ip.h> 13#include <linux/module.h> 14#include <linux/skbuff.h> 15#include <linux/tcp.h> 16 17#include <linux/netfilter/x_tables.h> 18#include <linux/netfilter_ipv4/ip_tables.h> 19#include <linux/netfilter_ipv4/ipt_ecn.h> 20 21MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 22MODULE_DESCRIPTION("iptables ECN matching module"); 23MODULE_LICENSE("GPL"); 24 25static inline int match_ip(const struct sk_buff *skb, 26 const struct ipt_ecn_info *einfo) 27{ 28 return (ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect; 29} 30 31static inline int match_tcp(const struct sk_buff *skb, 32 const struct ipt_ecn_info *einfo, 33 int *hotdrop) 34{ 35 struct tcphdr _tcph, *th; 36 37 /* In practice, TCP match does this, so can't fail. But let's 38 * be good citizens. 39 */ 40 th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph); 41 if (th == NULL) { 42 *hotdrop = 0; 43 return 0; 44 } 45 46 if (einfo->operation & IPT_ECN_OP_MATCH_ECE) { 47 if (einfo->invert & IPT_ECN_OP_MATCH_ECE) { 48 if (th->ece == 1) 49 return 0; 50 } else { 51 if (th->ece == 0) 52 return 0; 53 } 54 } 55 56 if (einfo->operation & IPT_ECN_OP_MATCH_CWR) { 57 if (einfo->invert & IPT_ECN_OP_MATCH_CWR) { 58 if (th->cwr == 1) 59 return 0; 60 } else { 61 if (th->cwr == 0) 62 return 0; 63 } 64 } 65 66 return 1; 67} 68 69static int match(const struct sk_buff *skb, 70 const struct net_device *in, const struct net_device *out, 71 const struct xt_match *match, const void *matchinfo, 72 int offset, unsigned int protoff, int *hotdrop) 73{ 74 const struct ipt_ecn_info *info = matchinfo; 75 76 if (info->operation & IPT_ECN_OP_MATCH_IP) 77 if (!match_ip(skb, info)) 78 return 0; 79 80 if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) { 81 if (ip_hdr(skb)->protocol != IPPROTO_TCP) 82 return 0; 83 if (!match_tcp(skb, info, hotdrop)) 84 return 0; 85 } 86 87 return 1; 88} 89 90static int checkentry(const char *tablename, const void *ip_void, 91 const struct xt_match *match, 92 void *matchinfo, unsigned int hook_mask) 93{ 94 const struct ipt_ecn_info *info = matchinfo; 95 const struct ipt_ip *ip = ip_void; 96 97 if (info->operation & IPT_ECN_OP_MATCH_MASK) 98 return 0; 99 100 if (info->invert & IPT_ECN_OP_MATCH_MASK) 101 return 0; 102 103 if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR) 104 && ip->proto != IPPROTO_TCP) { 105 printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for" 106 " non-tcp packets\n"); 107 return 0; 108 } 109 110 return 1; 111} 112 113static struct xt_match ecn_match = { 114 .name = "ecn", 115 .family = AF_INET, 116 .match = match, 117 .matchsize = sizeof(struct ipt_ecn_info), 118 .checkentry = checkentry, 119 .me = THIS_MODULE, 120}; 121 122static int __init ipt_ecn_init(void) 123{ 124 return xt_register_match(&ecn_match); 125} 126 127static void __exit ipt_ecn_fini(void) 128{ 129 xt_unregister_match(&ecn_match); 130} 131 132module_init(ipt_ecn_init); 133module_exit(ipt_ecn_fini); 134