1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports: 3 ports are in the same place so we can treat them as equal. */ 4 5 /* (C) 1999-2001 Paul `Rusty' Russell 6 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 7 */ 8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 #include <linux/module.h> 10 #include <linux/types.h> 11 #include <linux/udp.h> 12 #include <linux/skbuff.h> 13 #include <linux/in.h> 14 15 #include <linux/netfilter/xt_multiport.h> 16 #include <linux/netfilter/x_tables.h> 17 #include <linux/netfilter_ipv4/ip_tables.h> 18 #include <linux/netfilter_ipv6/ip6_tables.h> 19 20 MODULE_LICENSE("GPL"); 21 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 22 MODULE_DESCRIPTION("Xtables: multiple port matching for TCP, UDP, UDP-Lite, SCTP and DCCP"); 23 MODULE_ALIAS("ipt_multiport"); 24 MODULE_ALIAS("ip6t_multiport"); 25 26 /* Returns 1 if the port is matched by the test, 0 otherwise. */ 27 static inline bool 28 ports_match_v1(const struct xt_multiport_v1 *minfo, 29 u_int16_t src, u_int16_t dst) 30 { 31 unsigned int i; 32 u_int16_t s, e; 33 34 for (i = 0; i < minfo->count; i++) { 35 s = minfo->ports[i]; 36 37 if (minfo->pflags[i]) { 38 /* range port matching */ 39 e = minfo->ports[++i]; 40 pr_debug("src or dst matches with %d-%d?\n", s, e); 41 42 switch (minfo->flags) { 43 case XT_MULTIPORT_SOURCE: 44 if (src >= s && src <= e) 45 return true ^ minfo->invert; 46 break; 47 case XT_MULTIPORT_DESTINATION: 48 if (dst >= s && dst <= e) 49 return true ^ minfo->invert; 50 break; 51 case XT_MULTIPORT_EITHER: 52 if ((dst >= s && dst <= e) || 53 (src >= s && src <= e)) 54 return true ^ minfo->invert; 55 break; 56 default: 57 break; 58 } 59 } else { 60 /* exact port matching */ 61 pr_debug("src or dst matches with %d?\n", s); 62 63 switch (minfo->flags) { 64 case XT_MULTIPORT_SOURCE: 65 if (src == s) 66 return true ^ minfo->invert; 67 break; 68 case XT_MULTIPORT_DESTINATION: 69 if (dst == s) 70 return true ^ minfo->invert; 71 break; 72 case XT_MULTIPORT_EITHER: 73 if (src == s || dst == s) 74 return true ^ minfo->invert; 75 break; 76 default: 77 break; 78 } 79 } 80 } 81 82 return minfo->invert; 83 } 84 85 static bool 86 multiport_mt(const struct sk_buff *skb, struct xt_action_param *par) 87 { 88 const __be16 *pptr; 89 __be16 _ports[2]; 90 const struct xt_multiport_v1 *multiinfo = par->matchinfo; 91 92 if (par->fragoff != 0) 93 return false; 94 95 pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports); 96 if (pptr == NULL) { 97 /* We've been asked to examine this packet, and we 98 * can't. Hence, no choice but to drop. 99 */ 100 pr_debug("Dropping evil offset=0 tinygram.\n"); 101 par->hotdrop = true; 102 return false; 103 } 104 105 return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); 106 } 107 108 static inline bool 109 check(u_int16_t proto, 110 u_int8_t ip_invflags, 111 u_int8_t match_flags, 112 u_int8_t count) 113 { 114 /* Must specify supported protocol, no unknown flags or bad count */ 115 return (proto == IPPROTO_TCP || proto == IPPROTO_UDP 116 || proto == IPPROTO_UDPLITE 117 || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP) 118 && !(ip_invflags & XT_INV_PROTO) 119 && (match_flags == XT_MULTIPORT_SOURCE 120 || match_flags == XT_MULTIPORT_DESTINATION 121 || match_flags == XT_MULTIPORT_EITHER) 122 && count <= XT_MULTI_PORTS; 123 } 124 125 static int multiport_mt_check(const struct xt_mtchk_param *par) 126 { 127 const struct ipt_ip *ip = par->entryinfo; 128 const struct xt_multiport_v1 *multiinfo = par->matchinfo; 129 130 return check(ip->proto, ip->invflags, multiinfo->flags, 131 multiinfo->count) ? 0 : -EINVAL; 132 } 133 134 static int multiport_mt6_check(const struct xt_mtchk_param *par) 135 { 136 const struct ip6t_ip6 *ip = par->entryinfo; 137 const struct xt_multiport_v1 *multiinfo = par->matchinfo; 138 139 return check(ip->proto, ip->invflags, multiinfo->flags, 140 multiinfo->count) ? 0 : -EINVAL; 141 } 142 143 static struct xt_match multiport_mt_reg[] __read_mostly = { 144 { 145 .name = "multiport", 146 .family = NFPROTO_IPV4, 147 .revision = 1, 148 .checkentry = multiport_mt_check, 149 .match = multiport_mt, 150 .matchsize = sizeof(struct xt_multiport_v1), 151 .me = THIS_MODULE, 152 }, 153 { 154 .name = "multiport", 155 .family = NFPROTO_IPV6, 156 .revision = 1, 157 .checkentry = multiport_mt6_check, 158 .match = multiport_mt, 159 .matchsize = sizeof(struct xt_multiport_v1), 160 .me = THIS_MODULE, 161 }, 162 }; 163 164 static int __init multiport_mt_init(void) 165 { 166 return xt_register_matches(multiport_mt_reg, 167 ARRAY_SIZE(multiport_mt_reg)); 168 } 169 170 static void __exit multiport_mt_exit(void) 171 { 172 xt_unregister_matches(multiport_mt_reg, ARRAY_SIZE(multiport_mt_reg)); 173 } 174 175 module_init(multiport_mt_init); 176 module_exit(multiport_mt_exit); 177
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.