Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0003 #include <linux/types.h>
0004 #include <linux/module.h>
0005 #include <net/ip.h>
0006 #include <linux/ipv6.h>
0007 #include <net/ipv6.h>
0008 #include <net/tcp.h>
0009 #include <net/udp.h>
0010 #include <linux/netfilter/x_tables.h>
0011 #include <linux/netfilter/xt_tcpudp.h>
0012 #include <linux/netfilter_ipv4/ip_tables.h>
0013 #include <linux/netfilter_ipv6/ip6_tables.h>
0014 
0015 MODULE_DESCRIPTION("Xtables: TCP, UDP and UDP-Lite match");
0016 MODULE_LICENSE("GPL");
0017 MODULE_ALIAS("xt_tcp");
0018 MODULE_ALIAS("xt_udp");
0019 MODULE_ALIAS("ipt_udp");
0020 MODULE_ALIAS("ipt_tcp");
0021 MODULE_ALIAS("ip6t_udp");
0022 MODULE_ALIAS("ip6t_tcp");
0023 
0024 /* Returns 1 if the port is matched by the range, 0 otherwise */
0025 static inline bool
0026 port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert)
0027 {
0028     return (port >= min && port <= max) ^ invert;
0029 }
0030 
0031 static bool
0032 tcp_find_option(u_int8_t option,
0033         const struct sk_buff *skb,
0034         unsigned int protoff,
0035         unsigned int optlen,
0036         bool invert,
0037         bool *hotdrop)
0038 {
0039     /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
0040     const u_int8_t *op;
0041     u_int8_t _opt[60 - sizeof(struct tcphdr)];
0042     unsigned int i;
0043 
0044     pr_debug("finding option\n");
0045 
0046     if (!optlen)
0047         return invert;
0048 
0049     /* If we don't have the whole header, drop packet. */
0050     op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr),
0051                 optlen, _opt);
0052     if (op == NULL) {
0053         *hotdrop = true;
0054         return false;
0055     }
0056 
0057     for (i = 0; i < optlen; ) {
0058         if (op[i] == option) return !invert;
0059         if (op[i] < 2) i++;
0060         else i += op[i+1]?:1;
0061     }
0062 
0063     return invert;
0064 }
0065 
0066 static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par)
0067 {
0068     const struct tcphdr *th;
0069     struct tcphdr _tcph;
0070     const struct xt_tcp *tcpinfo = par->matchinfo;
0071 
0072     if (par->fragoff != 0) {
0073         /* To quote Alan:
0074 
0075            Don't allow a fragment of TCP 8 bytes in. Nobody normal
0076            causes this. Its a cracker trying to break in by doing a
0077            flag overwrite to pass the direction checks.
0078         */
0079         if (par->fragoff == 1) {
0080             pr_debug("Dropping evil TCP offset=1 frag.\n");
0081             par->hotdrop = true;
0082         }
0083         /* Must not be a fragment. */
0084         return false;
0085     }
0086 
0087     th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
0088     if (th == NULL) {
0089         /* We've been asked to examine this packet, and we
0090            can't.  Hence, no choice but to drop. */
0091         pr_debug("Dropping evil TCP offset=0 tinygram.\n");
0092         par->hotdrop = true;
0093         return false;
0094     }
0095 
0096     if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
0097             ntohs(th->source),
0098             !!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
0099         return false;
0100     if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
0101             ntohs(th->dest),
0102             !!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
0103         return false;
0104     if (!NF_INVF(tcpinfo, XT_TCP_INV_FLAGS,
0105              (((unsigned char *)th)[13] & tcpinfo->flg_mask) == tcpinfo->flg_cmp))
0106         return false;
0107     if (tcpinfo->option) {
0108         if (th->doff * 4 < sizeof(_tcph)) {
0109             par->hotdrop = true;
0110             return false;
0111         }
0112         if (!tcp_find_option(tcpinfo->option, skb, par->thoff,
0113                      th->doff*4 - sizeof(_tcph),
0114                      tcpinfo->invflags & XT_TCP_INV_OPTION,
0115                      &par->hotdrop))
0116             return false;
0117     }
0118     return true;
0119 }
0120 
0121 static int tcp_mt_check(const struct xt_mtchk_param *par)
0122 {
0123     const struct xt_tcp *tcpinfo = par->matchinfo;
0124 
0125     /* Must specify no unknown invflags */
0126     return (tcpinfo->invflags & ~XT_TCP_INV_MASK) ? -EINVAL : 0;
0127 }
0128 
0129 static bool udp_mt(const struct sk_buff *skb, struct xt_action_param *par)
0130 {
0131     const struct udphdr *uh;
0132     struct udphdr _udph;
0133     const struct xt_udp *udpinfo = par->matchinfo;
0134 
0135     /* Must not be a fragment. */
0136     if (par->fragoff != 0)
0137         return false;
0138 
0139     uh = skb_header_pointer(skb, par->thoff, sizeof(_udph), &_udph);
0140     if (uh == NULL) {
0141         /* We've been asked to examine this packet, and we
0142            can't.  Hence, no choice but to drop. */
0143         pr_debug("Dropping evil UDP tinygram.\n");
0144         par->hotdrop = true;
0145         return false;
0146     }
0147 
0148     return port_match(udpinfo->spts[0], udpinfo->spts[1],
0149               ntohs(uh->source),
0150               !!(udpinfo->invflags & XT_UDP_INV_SRCPT))
0151         && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
0152                   ntohs(uh->dest),
0153                   !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
0154 }
0155 
0156 static int udp_mt_check(const struct xt_mtchk_param *par)
0157 {
0158     const struct xt_udp *udpinfo = par->matchinfo;
0159 
0160     /* Must specify no unknown invflags */
0161     return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0;
0162 }
0163 
0164 static struct xt_match tcpudp_mt_reg[] __read_mostly = {
0165     {
0166         .name       = "tcp",
0167         .family     = NFPROTO_IPV4,
0168         .checkentry = tcp_mt_check,
0169         .match      = tcp_mt,
0170         .matchsize  = sizeof(struct xt_tcp),
0171         .proto      = IPPROTO_TCP,
0172         .me     = THIS_MODULE,
0173     },
0174     {
0175         .name       = "tcp",
0176         .family     = NFPROTO_IPV6,
0177         .checkentry = tcp_mt_check,
0178         .match      = tcp_mt,
0179         .matchsize  = sizeof(struct xt_tcp),
0180         .proto      = IPPROTO_TCP,
0181         .me     = THIS_MODULE,
0182     },
0183     {
0184         .name       = "udp",
0185         .family     = NFPROTO_IPV4,
0186         .checkentry = udp_mt_check,
0187         .match      = udp_mt,
0188         .matchsize  = sizeof(struct xt_udp),
0189         .proto      = IPPROTO_UDP,
0190         .me     = THIS_MODULE,
0191     },
0192     {
0193         .name       = "udp",
0194         .family     = NFPROTO_IPV6,
0195         .checkentry = udp_mt_check,
0196         .match      = udp_mt,
0197         .matchsize  = sizeof(struct xt_udp),
0198         .proto      = IPPROTO_UDP,
0199         .me     = THIS_MODULE,
0200     },
0201     {
0202         .name       = "udplite",
0203         .family     = NFPROTO_IPV4,
0204         .checkentry = udp_mt_check,
0205         .match      = udp_mt,
0206         .matchsize  = sizeof(struct xt_udp),
0207         .proto      = IPPROTO_UDPLITE,
0208         .me     = THIS_MODULE,
0209     },
0210     {
0211         .name       = "udplite",
0212         .family     = NFPROTO_IPV6,
0213         .checkentry = udp_mt_check,
0214         .match      = udp_mt,
0215         .matchsize  = sizeof(struct xt_udp),
0216         .proto      = IPPROTO_UDPLITE,
0217         .me     = THIS_MODULE,
0218     },
0219 };
0220 
0221 static int __init tcpudp_mt_init(void)
0222 {
0223     return xt_register_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg));
0224 }
0225 
0226 static void __exit tcpudp_mt_exit(void)
0227 {
0228     xt_unregister_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg));
0229 }
0230 
0231 module_init(tcpudp_mt_init);
0232 module_exit(tcpudp_mt_exit);