1/* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports: 2 ports are in the same place so we can treat them as equal. */ 3 4/* (C) 1999-2001 Paul `Rusty' Russell 5 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/module.h> 13#include <linux/types.h> 14#include <linux/udp.h> 15#include <linux/skbuff.h> 16#include <linux/in.h> 17 18#include <linux/netfilter/xt_multiport.h> 19#include <linux/netfilter/x_tables.h> 20#include <linux/netfilter_ipv4/ip_tables.h> 21#include <linux/netfilter_ipv6/ip6_tables.h> 22 23MODULE_LICENSE("GPL"); 24MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 25MODULE_DESCRIPTION("x_tables multiple port match module"); 26MODULE_ALIAS("ipt_multiport"); 27MODULE_ALIAS("ip6t_multiport"); 28 29#define duprintf(format, args...) 30 31/* Returns 1 if the port is matched by the test, 0 otherwise. */ 32static inline int 33ports_match(const u_int16_t *portlist, enum xt_multiport_flags flags, 34 u_int8_t count, u_int16_t src, u_int16_t dst) 35{ 36 unsigned int i; 37 for (i = 0; i < count; i++) { 38 if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src) 39 return 1; 40 41 if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst) 42 return 1; 43 } 44 45 return 0; 46} 47 48/* Returns 1 if the port is matched by the test, 0 otherwise. */ 49static inline int 50ports_match_v1(const struct xt_multiport_v1 *minfo, 51 u_int16_t src, u_int16_t dst) 52{ 53 unsigned int i; 54 u_int16_t s, e; 55 56 for (i = 0; i < minfo->count; i++) { 57 s = minfo->ports[i]; 58 59 if (minfo->pflags[i]) { 60 /* range port matching */ 61 e = minfo->ports[++i]; 62 duprintf("src or dst matches with %d-%d?\n", s, e); 63 64 if (minfo->flags == XT_MULTIPORT_SOURCE 65 && src >= s && src <= e) 66 return 1 ^ minfo->invert; 67 if (minfo->flags == XT_MULTIPORT_DESTINATION 68 && dst >= s && dst <= e) 69 return 1 ^ minfo->invert; 70 if (minfo->flags == XT_MULTIPORT_EITHER 71 && ((dst >= s && dst <= e) 72 || (src >= s && src <= e))) 73 return 1 ^ minfo->invert; 74 } else { 75 /* exact port matching */ 76 duprintf("src or dst matches with %d?\n", s); 77 78 if (minfo->flags == XT_MULTIPORT_SOURCE 79 && src == s) 80 return 1 ^ minfo->invert; 81 if (minfo->flags == XT_MULTIPORT_DESTINATION 82 && dst == s) 83 return 1 ^ minfo->invert; 84 if (minfo->flags == XT_MULTIPORT_EITHER 85 && (src == s || dst == s)) 86 return 1 ^ minfo->invert; 87 } 88 } 89 90 return minfo->invert; 91} 92 93static int 94match(const struct sk_buff *skb, 95 const struct net_device *in, 96 const struct net_device *out, 97 const struct xt_match *match, 98 const void *matchinfo, 99 int offset, 100 unsigned int protoff, 101 int *hotdrop) 102{ 103 __be16 _ports[2], *pptr; 104 const struct xt_multiport *multiinfo = matchinfo; 105 106 if (offset) 107 return 0; 108 109 pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports); 110 if (pptr == NULL) { 111 /* We've been asked to examine this packet, and we 112 * can't. Hence, no choice but to drop. 113 */ 114 duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n"); 115 *hotdrop = 1; 116 return 0; 117 } 118 119 return ports_match(multiinfo->ports, 120 multiinfo->flags, multiinfo->count, 121 ntohs(pptr[0]), ntohs(pptr[1])); 122} 123 124static int 125match_v1(const struct sk_buff *skb, 126 const struct net_device *in, 127 const struct net_device *out, 128 const struct xt_match *match, 129 const void *matchinfo, 130 int offset, 131 unsigned int protoff, 132 int *hotdrop) 133{ 134 __be16 _ports[2], *pptr; 135 const struct xt_multiport_v1 *multiinfo = matchinfo; 136 137 if (offset) 138 return 0; 139 140 pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports); 141 if (pptr == NULL) { 142 /* We've been asked to examine this packet, and we 143 * can't. Hence, no choice but to drop. 144 */ 145 duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n"); 146 *hotdrop = 1; 147 return 0; 148 } 149 150 return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); 151} 152 153static inline int 154check(u_int16_t proto, 155 u_int8_t ip_invflags, 156 u_int8_t match_flags, 157 u_int8_t count) 158{ 159 /* Must specify supported protocol, no unknown flags or bad count */ 160 return (proto == IPPROTO_TCP || proto == IPPROTO_UDP 161 || proto == IPPROTO_UDPLITE 162 || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP) 163 && !(ip_invflags & XT_INV_PROTO) 164 && (match_flags == XT_MULTIPORT_SOURCE 165 || match_flags == XT_MULTIPORT_DESTINATION 166 || match_flags == XT_MULTIPORT_EITHER) 167 && count <= XT_MULTI_PORTS; 168} 169 170/* Called when user tries to insert an entry of this type. */ 171static int 172checkentry(const char *tablename, 173 const void *info, 174 const struct xt_match *match, 175 void *matchinfo, 176 unsigned int hook_mask) 177{ 178 const struct ipt_ip *ip = info; 179 const struct xt_multiport *multiinfo = matchinfo; 180 181 return check(ip->proto, ip->invflags, multiinfo->flags, 182 multiinfo->count); 183} 184 185static int 186checkentry_v1(const char *tablename, 187 const void *info, 188 const struct xt_match *match, 189 void *matchinfo, 190 unsigned int hook_mask) 191{ 192 const struct ipt_ip *ip = info; 193 const struct xt_multiport_v1 *multiinfo = matchinfo; 194 195 return check(ip->proto, ip->invflags, multiinfo->flags, 196 multiinfo->count); 197} 198 199static int 200checkentry6(const char *tablename, 201 const void *info, 202 const struct xt_match *match, 203 void *matchinfo, 204 unsigned int hook_mask) 205{ 206 const struct ip6t_ip6 *ip = info; 207 const struct xt_multiport *multiinfo = matchinfo; 208 209 return check(ip->proto, ip->invflags, multiinfo->flags, 210 multiinfo->count); 211} 212 213static int 214checkentry6_v1(const char *tablename, 215 const void *info, 216 const struct xt_match *match, 217 void *matchinfo, 218 unsigned int hook_mask) 219{ 220 const struct ip6t_ip6 *ip = info; 221 const struct xt_multiport_v1 *multiinfo = matchinfo; 222 223 return check(ip->proto, ip->invflags, multiinfo->flags, 224 multiinfo->count); 225} 226 227static struct xt_match xt_multiport_match[] = { 228 { 229 .name = "multiport", 230 .family = AF_INET, 231 .revision = 0, 232 .checkentry = checkentry, 233 .match = match, 234 .matchsize = sizeof(struct xt_multiport), 235 .me = THIS_MODULE, 236 }, 237 { 238 .name = "multiport", 239 .family = AF_INET, 240 .revision = 1, 241 .checkentry = checkentry_v1, 242 .match = match_v1, 243 .matchsize = sizeof(struct xt_multiport_v1), 244 .me = THIS_MODULE, 245 }, 246 { 247 .name = "multiport", 248 .family = AF_INET6, 249 .revision = 0, 250 .checkentry = checkentry6, 251 .match = match, 252 .matchsize = sizeof(struct xt_multiport), 253 .me = THIS_MODULE, 254 }, 255 { 256 .name = "multiport", 257 .family = AF_INET6, 258 .revision = 1, 259 .checkentry = checkentry6_v1, 260 .match = match_v1, 261 .matchsize = sizeof(struct xt_multiport_v1), 262 .me = THIS_MODULE, 263 }, 264}; 265 266static int __init xt_multiport_init(void) 267{ 268 return xt_register_matches(xt_multiport_match, 269 ARRAY_SIZE(xt_multiport_match)); 270} 271 272static void __exit xt_multiport_fini(void) 273{ 274 xt_unregister_matches(xt_multiport_match, 275 ARRAY_SIZE(xt_multiport_match)); 276} 277 278module_init(xt_multiport_init); 279module_exit(xt_multiport_fini); 280