Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.24-rc5 266 lines 6.5 kB view raw
1#include <linux/types.h> 2#include <linux/module.h> 3#include <net/ip.h> 4#include <linux/ipv6.h> 5#include <net/ipv6.h> 6#include <net/tcp.h> 7#include <net/udp.h> 8#include <linux/netfilter/x_tables.h> 9#include <linux/netfilter/xt_tcpudp.h> 10#include <linux/netfilter_ipv4/ip_tables.h> 11#include <linux/netfilter_ipv6/ip6_tables.h> 12 13MODULE_DESCRIPTION("x_tables match for TCP and UDP(-Lite), supports IPv4 and IPv6"); 14MODULE_LICENSE("GPL"); 15MODULE_ALIAS("xt_tcp"); 16MODULE_ALIAS("xt_udp"); 17MODULE_ALIAS("ipt_udp"); 18MODULE_ALIAS("ipt_tcp"); 19MODULE_ALIAS("ip6t_udp"); 20MODULE_ALIAS("ip6t_tcp"); 21 22#ifdef DEBUG_IP_FIREWALL_USER 23#define duprintf(format, args...) printk(format , ## args) 24#else 25#define duprintf(format, args...) 26#endif 27 28 29/* Returns 1 if the port is matched by the range, 0 otherwise */ 30static inline bool 31port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert) 32{ 33 return (port >= min && port <= max) ^ invert; 34} 35 36static bool 37tcp_find_option(u_int8_t option, 38 const struct sk_buff *skb, 39 unsigned int protoff, 40 unsigned int optlen, 41 bool invert, 42 bool *hotdrop) 43{ 44 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ 45 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op; 46 unsigned int i; 47 48 duprintf("tcp_match: finding option\n"); 49 50 if (!optlen) 51 return invert; 52 53 /* If we don't have the whole header, drop packet. */ 54 op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr), 55 optlen, _opt); 56 if (op == NULL) { 57 *hotdrop = true; 58 return false; 59 } 60 61 for (i = 0; i < optlen; ) { 62 if (op[i] == option) return !invert; 63 if (op[i] < 2) i++; 64 else i += op[i+1]?:1; 65 } 66 67 return invert; 68} 69 70static bool 71tcp_match(const struct sk_buff *skb, 72 const struct net_device *in, 73 const struct net_device *out, 74 const struct xt_match *match, 75 const void *matchinfo, 76 int offset, 77 unsigned int protoff, 78 bool *hotdrop) 79{ 80 struct tcphdr _tcph, *th; 81 const struct xt_tcp *tcpinfo = matchinfo; 82 83 if (offset) { 84 /* To quote Alan: 85 86 Don't allow a fragment of TCP 8 bytes in. Nobody normal 87 causes this. Its a cracker trying to break in by doing a 88 flag overwrite to pass the direction checks. 89 */ 90 if (offset == 1) { 91 duprintf("Dropping evil TCP offset=1 frag.\n"); 92 *hotdrop = true; 93 } 94 /* Must not be a fragment. */ 95 return false; 96 } 97 98#define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg))) 99 100 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); 101 if (th == NULL) { 102 /* We've been asked to examine this packet, and we 103 can't. Hence, no choice but to drop. */ 104 duprintf("Dropping evil TCP offset=0 tinygram.\n"); 105 *hotdrop = true; 106 return false; 107 } 108 109 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1], 110 ntohs(th->source), 111 !!(tcpinfo->invflags & XT_TCP_INV_SRCPT))) 112 return false; 113 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], 114 ntohs(th->dest), 115 !!(tcpinfo->invflags & XT_TCP_INV_DSTPT))) 116 return false; 117 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask) 118 == tcpinfo->flg_cmp, 119 XT_TCP_INV_FLAGS)) 120 return false; 121 if (tcpinfo->option) { 122 if (th->doff * 4 < sizeof(_tcph)) { 123 *hotdrop = true; 124 return false; 125 } 126 if (!tcp_find_option(tcpinfo->option, skb, protoff, 127 th->doff*4 - sizeof(_tcph), 128 tcpinfo->invflags & XT_TCP_INV_OPTION, 129 hotdrop)) 130 return false; 131 } 132 return true; 133} 134 135/* Called when user tries to insert an entry of this type. */ 136static bool 137tcp_checkentry(const char *tablename, 138 const void *info, 139 const struct xt_match *match, 140 void *matchinfo, 141 unsigned int hook_mask) 142{ 143 const struct xt_tcp *tcpinfo = matchinfo; 144 145 /* Must specify no unknown invflags */ 146 return !(tcpinfo->invflags & ~XT_TCP_INV_MASK); 147} 148 149static bool 150udp_match(const struct sk_buff *skb, 151 const struct net_device *in, 152 const struct net_device *out, 153 const struct xt_match *match, 154 const void *matchinfo, 155 int offset, 156 unsigned int protoff, 157 bool *hotdrop) 158{ 159 struct udphdr _udph, *uh; 160 const struct xt_udp *udpinfo = matchinfo; 161 162 /* Must not be a fragment. */ 163 if (offset) 164 return false; 165 166 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph); 167 if (uh == NULL) { 168 /* We've been asked to examine this packet, and we 169 can't. Hence, no choice but to drop. */ 170 duprintf("Dropping evil UDP tinygram.\n"); 171 *hotdrop = true; 172 return false; 173 } 174 175 return port_match(udpinfo->spts[0], udpinfo->spts[1], 176 ntohs(uh->source), 177 !!(udpinfo->invflags & XT_UDP_INV_SRCPT)) 178 && port_match(udpinfo->dpts[0], udpinfo->dpts[1], 179 ntohs(uh->dest), 180 !!(udpinfo->invflags & XT_UDP_INV_DSTPT)); 181} 182 183/* Called when user tries to insert an entry of this type. */ 184static bool 185udp_checkentry(const char *tablename, 186 const void *info, 187 const struct xt_match *match, 188 void *matchinfo, 189 unsigned int hook_mask) 190{ 191 const struct xt_udp *udpinfo = matchinfo; 192 193 /* Must specify no unknown invflags */ 194 return !(udpinfo->invflags & ~XT_UDP_INV_MASK); 195} 196 197static struct xt_match xt_tcpudp_match[] __read_mostly = { 198 { 199 .name = "tcp", 200 .family = AF_INET, 201 .checkentry = tcp_checkentry, 202 .match = tcp_match, 203 .matchsize = sizeof(struct xt_tcp), 204 .proto = IPPROTO_TCP, 205 .me = THIS_MODULE, 206 }, 207 { 208 .name = "tcp", 209 .family = AF_INET6, 210 .checkentry = tcp_checkentry, 211 .match = tcp_match, 212 .matchsize = sizeof(struct xt_tcp), 213 .proto = IPPROTO_TCP, 214 .me = THIS_MODULE, 215 }, 216 { 217 .name = "udp", 218 .family = AF_INET, 219 .checkentry = udp_checkentry, 220 .match = udp_match, 221 .matchsize = sizeof(struct xt_udp), 222 .proto = IPPROTO_UDP, 223 .me = THIS_MODULE, 224 }, 225 { 226 .name = "udp", 227 .family = AF_INET6, 228 .checkentry = udp_checkentry, 229 .match = udp_match, 230 .matchsize = sizeof(struct xt_udp), 231 .proto = IPPROTO_UDP, 232 .me = THIS_MODULE, 233 }, 234 { 235 .name = "udplite", 236 .family = AF_INET, 237 .checkentry = udp_checkentry, 238 .match = udp_match, 239 .matchsize = sizeof(struct xt_udp), 240 .proto = IPPROTO_UDPLITE, 241 .me = THIS_MODULE, 242 }, 243 { 244 .name = "udplite", 245 .family = AF_INET6, 246 .checkentry = udp_checkentry, 247 .match = udp_match, 248 .matchsize = sizeof(struct xt_udp), 249 .proto = IPPROTO_UDPLITE, 250 .me = THIS_MODULE, 251 }, 252}; 253 254static int __init xt_tcpudp_init(void) 255{ 256 return xt_register_matches(xt_tcpudp_match, 257 ARRAY_SIZE(xt_tcpudp_match)); 258} 259 260static void __exit xt_tcpudp_fini(void) 261{ 262 xt_unregister_matches(xt_tcpudp_match, ARRAY_SIZE(xt_tcpudp_match)); 263} 264 265module_init(xt_tcpudp_init); 266module_exit(xt_tcpudp_fini);