1 // SPDX-License-Identifier: GPL-2.0-only 2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3 #include <linux/types.h> 4 #include <linux/module.h> 5 #include <net/ip.h> 6 #include <linux/ipv6.h> 7 #include <linux/icmp.h> 8 #include <net/ipv6.h> 9 #include <net/tcp.h> 10 #include <net/udp.h> 11 #include <linux/netfilter/x_tables.h> 12 #include <linux/netfilter/xt_tcpudp.h> 13 #include <linux/netfilter_ipv4/ip_tables.h> 14 #include <linux/netfilter_ipv6/ip6_tables.h> 15 16 MODULE_DESCRIPTION("Xtables: TCP, UDP and UDP-Lite match"); 17 MODULE_LICENSE("GPL"); 18 MODULE_ALIAS("xt_tcp"); 19 MODULE_ALIAS("xt_udp"); 20 MODULE_ALIAS("ipt_udp"); 21 MODULE_ALIAS("ipt_tcp"); 22 MODULE_ALIAS("ip6t_udp"); 23 MODULE_ALIAS("ip6t_tcp"); 24 MODULE_ALIAS("ipt_icmp"); 25 MODULE_ALIAS("ip6t_icmp6"); 26 27 /* Returns 1 if the port is matched by the range, 0 otherwise */ 28 static inline bool 29 port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert) 30 { 31 return (port >= min && port <= max) ^ invert; 32 } 33 34 static bool 35 tcp_find_option(u_int8_t option, 36 const struct sk_buff *skb, 37 unsigned int protoff, 38 unsigned int optlen, 39 bool invert, 40 bool *hotdrop) 41 { 42 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ 43 const u_int8_t *op; 44 u_int8_t _opt[60 - sizeof(struct tcphdr)]; 45 unsigned int i; 46 47 if (!optlen) 48 return invert; 49 50 /* If we don't have the whole header, drop packet. */ 51 op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr), 52 optlen, _opt); 53 if (op == NULL) { 54 *hotdrop = true; 55 return false; 56 } 57 58 for (i = 0; i < optlen; ) { 59 if (op[i] == option) return !invert; 60 if (op[i] < 2 || i == optlen - 1) 61 i++; 62 else 63 i += op[i + 1] ? : 1; 64 } 65 66 return invert; 67 } 68 69 static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par) 70 { 71 const struct tcphdr *th; 72 struct tcphdr _tcph; 73 const struct xt_tcp *tcpinfo = par->matchinfo; 74 75 if (par->fragoff != 0) { 76 /* To quote Alan: 77 78 Don't allow a fragment of TCP 8 bytes in. Nobody normal 79 causes this. Its a cracker trying to break in by doing a 80 flag overwrite to pass the direction checks. 81 */ 82 if (par->fragoff == 1) 83 par->hotdrop = true; 84 /* Must not be a fragment. */ 85 return false; 86 } 87 88 th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph); 89 if (th == NULL) { 90 /* We've been asked to examine this packet, and we 91 can't. Hence, no choice but to drop. */ 92 par->hotdrop = true; 93 return false; 94 } 95 96 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1], 97 ntohs(th->source), 98 !!(tcpinfo->invflags & XT_TCP_INV_SRCPT))) 99 return false; 100 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], 101 ntohs(th->dest), 102 !!(tcpinfo->invflags & XT_TCP_INV_DSTPT))) 103 return false; 104 if (!NF_INVF(tcpinfo, XT_TCP_INV_FLAGS, 105 (((unsigned char *)th)[13] & tcpinfo->flg_mask) == tcpinfo->flg_cmp)) 106 return false; 107 if (tcpinfo->option) { 108 if (th->doff * 4 < sizeof(_tcph)) { 109 par->hotdrop = true; 110 return false; 111 } 112 if (!tcp_find_option(tcpinfo->option, skb, par->thoff, 113 th->doff*4 - sizeof(_tcph), 114 tcpinfo->invflags & XT_TCP_INV_OPTION, 115 &par->hotdrop)) 116 return false; 117 } 118 return true; 119 } 120 121 static int tcp_mt_check(const struct xt_mtchk_param *par) 122 { 123 const struct xt_tcp *tcpinfo = par->matchinfo; 124 125 /* Must specify no unknown invflags */ 126 return (tcpinfo->invflags & ~XT_TCP_INV_MASK) ? -EINVAL : 0; 127 } 128 129 static bool udp_mt(const struct sk_buff *skb, struct xt_action_param *par) 130 { 131 const struct udphdr *uh; 132 struct udphdr _udph; 133 const struct xt_udp *udpinfo = par->matchinfo; 134 135 /* Must not be a fragment. */ 136 if (par->fragoff != 0) 137 return false; 138 139 uh = skb_header_pointer(skb, par->thoff, sizeof(_udph), &_udph); 140 if (uh == NULL) { 141 /* We've been asked to examine this packet, and we 142 can't. Hence, no choice but to drop. */ 143 par->hotdrop = true; 144 return false; 145 } 146 147 return port_match(udpinfo->spts[0], udpinfo->spts[1], 148 ntohs(uh->source), 149 !!(udpinfo->invflags & XT_UDP_INV_SRCPT)) 150 && port_match(udpinfo->dpts[0], udpinfo->dpts[1], 151 ntohs(uh->dest), 152 !!(udpinfo->invflags & XT_UDP_INV_DSTPT)); 153 } 154 155 static int udp_mt_check(const struct xt_mtchk_param *par) 156 { 157 const struct xt_udp *udpinfo = par->matchinfo; 158 159 /* Must specify no unknown invflags */ 160 return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0; 161 } 162 163 /* Returns 1 if the type and code is matched by the range, 0 otherwise */ 164 static bool type_code_in_range(u8 test_type, u8 min_code, u8 max_code, 165 u8 type, u8 code) 166 { 167 return type == test_type && code >= min_code && code <= max_code; 168 } 169 170 static bool icmp_type_code_match(u8 test_type, u8 min_code, u8 max_code, 171 u8 type, u8 code, bool invert) 172 { 173 return (test_type == 0xFF || 174 type_code_in_range(test_type, min_code, max_code, type, code)) 175 ^ invert; 176 } 177 178 static bool icmp6_type_code_match(u8 test_type, u8 min_code, u8 max_code, 179 u8 type, u8 code, bool invert) 180 { 181 return type_code_in_range(test_type, min_code, max_code, type, code) ^ invert; 182 } 183 184 static bool 185 icmp_match(const struct sk_buff *skb, struct xt_action_param *par) 186 { 187 const struct icmphdr *ic; 188 struct icmphdr _icmph; 189 const struct ipt_icmp *icmpinfo = par->matchinfo; 190 191 /* Must not be a fragment. */ 192 if (par->fragoff != 0) 193 return false; 194 195 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph); 196 if (!ic) { 197 /* We've been asked to examine this packet, and we 198 * can't. Hence, no choice but to drop. 199 */ 200 par->hotdrop = true; 201 return false; 202 } 203 204 return icmp_type_code_match(icmpinfo->type, 205 icmpinfo->code[0], 206 icmpinfo->code[1], 207 ic->type, ic->code, 208 !!(icmpinfo->invflags & IPT_ICMP_INV)); 209 } 210 211 static bool 212 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par) 213 { 214 const struct icmp6hdr *ic; 215 struct icmp6hdr _icmph; 216 const struct ip6t_icmp *icmpinfo = par->matchinfo; 217 218 /* Must not be a fragment. */ 219 if (par->fragoff != 0) 220 return false; 221 222 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph); 223 if (!ic) { 224 /* We've been asked to examine this packet, and we 225 * can't. Hence, no choice but to drop. 226 */ 227 par->hotdrop = true; 228 return false; 229 } 230 231 return icmp6_type_code_match(icmpinfo->type, 232 icmpinfo->code[0], 233 icmpinfo->code[1], 234 ic->icmp6_type, ic->icmp6_code, 235 !!(icmpinfo->invflags & IP6T_ICMP_INV)); 236 } 237 238 static int icmp_checkentry(const struct xt_mtchk_param *par) 239 { 240 const struct ipt_icmp *icmpinfo = par->matchinfo; 241 242 return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0; 243 } 244 245 static int icmp6_checkentry(const struct xt_mtchk_param *par) 246 { 247 const struct ip6t_icmp *icmpinfo = par->matchinfo; 248 249 return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0; 250 } 251 252 static struct xt_match tcpudp_mt_reg[] __read_mostly = { 253 { 254 .name = "tcp", 255 .family = NFPROTO_IPV4, 256 .checkentry = tcp_mt_check, 257 .match = tcp_mt, 258 .matchsize = sizeof(struct xt_tcp), 259 .proto = IPPROTO_TCP, 260 .me = THIS_MODULE, 261 }, 262 { 263 .name = "tcp", 264 .family = NFPROTO_IPV6, 265 .checkentry = tcp_mt_check, 266 .match = tcp_mt, 267 .matchsize = sizeof(struct xt_tcp), 268 .proto = IPPROTO_TCP, 269 .me = THIS_MODULE, 270 }, 271 { 272 .name = "udp", 273 .family = NFPROTO_IPV4, 274 .checkentry = udp_mt_check, 275 .match = udp_mt, 276 .matchsize = sizeof(struct xt_udp), 277 .proto = IPPROTO_UDP, 278 .me = THIS_MODULE, 279 }, 280 { 281 .name = "udp", 282 .family = NFPROTO_IPV6, 283 .checkentry = udp_mt_check, 284 .match = udp_mt, 285 .matchsize = sizeof(struct xt_udp), 286 .proto = IPPROTO_UDP, 287 .me = THIS_MODULE, 288 }, 289 { 290 .name = "udplite", 291 .family = NFPROTO_IPV4, 292 .checkentry = udp_mt_check, 293 .match = udp_mt, 294 .matchsize = sizeof(struct xt_udp), 295 .proto = IPPROTO_UDPLITE, 296 .me = THIS_MODULE, 297 }, 298 { 299 .name = "udplite", 300 .family = NFPROTO_IPV6, 301 .checkentry = udp_mt_check, 302 .match = udp_mt, 303 .matchsize = sizeof(struct xt_udp), 304 .proto = IPPROTO_UDPLITE, 305 .me = THIS_MODULE, 306 }, 307 { 308 .name = "icmp", 309 .match = icmp_match, 310 .matchsize = sizeof(struct ipt_icmp), 311 .checkentry = icmp_checkentry, 312 .proto = IPPROTO_ICMP, 313 .family = NFPROTO_IPV4, 314 .me = THIS_MODULE, 315 }, 316 { 317 .name = "icmp6", 318 .match = icmp6_match, 319 .matchsize = sizeof(struct ip6t_icmp), 320 .checkentry = icmp6_checkentry, 321 .proto = IPPROTO_ICMPV6, 322 .family = NFPROTO_IPV6, 323 .me = THIS_MODULE, 324 }, 325 }; 326 327 static int __init tcpudp_mt_init(void) 328 { 329 return xt_register_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg)); 330 } 331 332 static void __exit tcpudp_mt_exit(void) 333 { 334 xt_unregister_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg)); 335 } 336 337 module_init(tcpudp_mt_init); 338 module_exit(tcpudp_mt_exit); 339