root/net/netfilter/xt_tcpudp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. port_match
  2. tcp_find_option
  3. tcp_mt
  4. tcp_mt_check
  5. udp_mt
  6. udp_mt_check
  7. tcpudp_mt_init
  8. tcpudp_mt_exit

   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 <net/ipv6.h>
   8 #include <net/tcp.h>
   9 #include <net/udp.h>
  10 #include <linux/netfilter/x_tables.h>
  11 #include <linux/netfilter/xt_tcpudp.h>
  12 #include <linux/netfilter_ipv4/ip_tables.h>
  13 #include <linux/netfilter_ipv6/ip6_tables.h>
  14 
  15 MODULE_DESCRIPTION("Xtables: TCP, UDP and UDP-Lite match");
  16 MODULE_LICENSE("GPL");
  17 MODULE_ALIAS("xt_tcp");
  18 MODULE_ALIAS("xt_udp");
  19 MODULE_ALIAS("ipt_udp");
  20 MODULE_ALIAS("ipt_tcp");
  21 MODULE_ALIAS("ip6t_udp");
  22 MODULE_ALIAS("ip6t_tcp");
  23 
  24 /* Returns 1 if the port is matched by the range, 0 otherwise */
  25 static inline bool
  26 port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert)
  27 {
  28         return (port >= min && port <= max) ^ invert;
  29 }
  30 
  31 static bool
  32 tcp_find_option(u_int8_t option,
  33                 const struct sk_buff *skb,
  34                 unsigned int protoff,
  35                 unsigned int optlen,
  36                 bool invert,
  37                 bool *hotdrop)
  38 {
  39         /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
  40         const u_int8_t *op;
  41         u_int8_t _opt[60 - sizeof(struct tcphdr)];
  42         unsigned int i;
  43 
  44         pr_debug("finding option\n");
  45 
  46         if (!optlen)
  47                 return invert;
  48 
  49         /* If we don't have the whole header, drop packet. */
  50         op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr),
  51                                 optlen, _opt);
  52         if (op == NULL) {
  53                 *hotdrop = true;
  54                 return false;
  55         }
  56 
  57         for (i = 0; i < optlen; ) {
  58                 if (op[i] == option) return !invert;
  59                 if (op[i] < 2) i++;
  60                 else i += op[i+1]?:1;
  61         }
  62 
  63         return invert;
  64 }
  65 
  66 static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par)
  67 {
  68         const struct tcphdr *th;
  69         struct tcphdr _tcph;
  70         const struct xt_tcp *tcpinfo = par->matchinfo;
  71 
  72         if (par->fragoff != 0) {
  73                 /* To quote Alan:
  74 
  75                    Don't allow a fragment of TCP 8 bytes in. Nobody normal
  76                    causes this. Its a cracker trying to break in by doing a
  77                    flag overwrite to pass the direction checks.
  78                 */
  79                 if (par->fragoff == 1) {
  80                         pr_debug("Dropping evil TCP offset=1 frag.\n");
  81                         par->hotdrop = true;
  82                 }
  83                 /* Must not be a fragment. */
  84                 return false;
  85         }
  86 
  87         th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
  88         if (th == NULL) {
  89                 /* We've been asked to examine this packet, and we
  90                    can't.  Hence, no choice but to drop. */
  91                 pr_debug("Dropping evil TCP offset=0 tinygram.\n");
  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                 pr_debug("Dropping evil UDP tinygram.\n");
 144                 par->hotdrop = true;
 145                 return false;
 146         }
 147 
 148         return port_match(udpinfo->spts[0], udpinfo->spts[1],
 149                           ntohs(uh->source),
 150                           !!(udpinfo->invflags & XT_UDP_INV_SRCPT))
 151                 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
 152                               ntohs(uh->dest),
 153                               !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
 154 }
 155 
 156 static int udp_mt_check(const struct xt_mtchk_param *par)
 157 {
 158         const struct xt_udp *udpinfo = par->matchinfo;
 159 
 160         /* Must specify no unknown invflags */
 161         return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0;
 162 }
 163 
 164 static struct xt_match tcpudp_mt_reg[] __read_mostly = {
 165         {
 166                 .name           = "tcp",
 167                 .family         = NFPROTO_IPV4,
 168                 .checkentry     = tcp_mt_check,
 169                 .match          = tcp_mt,
 170                 .matchsize      = sizeof(struct xt_tcp),
 171                 .proto          = IPPROTO_TCP,
 172                 .me             = THIS_MODULE,
 173         },
 174         {
 175                 .name           = "tcp",
 176                 .family         = NFPROTO_IPV6,
 177                 .checkentry     = tcp_mt_check,
 178                 .match          = tcp_mt,
 179                 .matchsize      = sizeof(struct xt_tcp),
 180                 .proto          = IPPROTO_TCP,
 181                 .me             = THIS_MODULE,
 182         },
 183         {
 184                 .name           = "udp",
 185                 .family         = NFPROTO_IPV4,
 186                 .checkentry     = udp_mt_check,
 187                 .match          = udp_mt,
 188                 .matchsize      = sizeof(struct xt_udp),
 189                 .proto          = IPPROTO_UDP,
 190                 .me             = THIS_MODULE,
 191         },
 192         {
 193                 .name           = "udp",
 194                 .family         = NFPROTO_IPV6,
 195                 .checkentry     = udp_mt_check,
 196                 .match          = udp_mt,
 197                 .matchsize      = sizeof(struct xt_udp),
 198                 .proto          = IPPROTO_UDP,
 199                 .me             = THIS_MODULE,
 200         },
 201         {
 202                 .name           = "udplite",
 203                 .family         = NFPROTO_IPV4,
 204                 .checkentry     = udp_mt_check,
 205                 .match          = udp_mt,
 206                 .matchsize      = sizeof(struct xt_udp),
 207                 .proto          = IPPROTO_UDPLITE,
 208                 .me             = THIS_MODULE,
 209         },
 210         {
 211                 .name           = "udplite",
 212                 .family         = NFPROTO_IPV6,
 213                 .checkentry     = udp_mt_check,
 214                 .match          = udp_mt,
 215                 .matchsize      = sizeof(struct xt_udp),
 216                 .proto          = IPPROTO_UDPLITE,
 217                 .me             = THIS_MODULE,
 218         },
 219 };
 220 
 221 static int __init tcpudp_mt_init(void)
 222 {
 223         return xt_register_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg));
 224 }
 225 
 226 static void __exit tcpudp_mt_exit(void)
 227 {
 228         xt_unregister_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg));
 229 }
 230 
 231 module_init(tcpudp_mt_init);
 232 module_exit(tcpudp_mt_exit);

/* [<][>][^][v][top][bottom][index][help] */