root/net/netfilter/xt_TCPOPTSTRIP.c

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

DEFINITIONS

This source file includes following definitions.
  1. optlen
  2. tcpoptstrip_mangle_packet
  3. tcpoptstrip_tg4
  4. tcpoptstrip_tg6
  5. tcpoptstrip_tg_init
  6. tcpoptstrip_tg_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * A module for stripping a specific TCP option from TCP packets.
   4  *
   5  * Copyright (C) 2007 Sven Schnelle <svens@bitebene.org>
   6  * Copyright © CC Computer Consultants GmbH, 2007
   7  */
   8 
   9 #include <linux/module.h>
  10 #include <linux/skbuff.h>
  11 #include <linux/ip.h>
  12 #include <linux/ipv6.h>
  13 #include <linux/tcp.h>
  14 #include <net/ipv6.h>
  15 #include <net/tcp.h>
  16 #include <linux/netfilter/x_tables.h>
  17 #include <linux/netfilter/xt_TCPOPTSTRIP.h>
  18 
  19 static inline unsigned int optlen(const u_int8_t *opt, unsigned int offset)
  20 {
  21         /* Beware zero-length options: make finite progress */
  22         if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
  23                 return 1;
  24         else
  25                 return opt[offset+1];
  26 }
  27 
  28 static unsigned int
  29 tcpoptstrip_mangle_packet(struct sk_buff *skb,
  30                           const struct xt_action_param *par,
  31                           unsigned int tcphoff)
  32 {
  33         const struct xt_tcpoptstrip_target_info *info = par->targinfo;
  34         struct tcphdr *tcph, _th;
  35         unsigned int optl, i, j;
  36         u_int16_t n, o;
  37         u_int8_t *opt;
  38         int tcp_hdrlen;
  39 
  40         /* This is a fragment, no TCP header is available */
  41         if (par->fragoff != 0)
  42                 return XT_CONTINUE;
  43 
  44         tcph = skb_header_pointer(skb, tcphoff, sizeof(_th), &_th);
  45         if (!tcph)
  46                 return NF_DROP;
  47 
  48         tcp_hdrlen = tcph->doff * 4;
  49         if (tcp_hdrlen < sizeof(struct tcphdr))
  50                 return NF_DROP;
  51 
  52         if (skb_ensure_writable(skb, tcphoff + tcp_hdrlen))
  53                 return NF_DROP;
  54 
  55         /* must reload tcph, might have been moved */
  56         tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
  57         opt  = (u8 *)tcph;
  58 
  59         /*
  60          * Walk through all TCP options - if we find some option to remove,
  61          * set all octets to %TCPOPT_NOP and adjust checksum.
  62          */
  63         for (i = sizeof(struct tcphdr); i < tcp_hdrlen - 1; i += optl) {
  64                 optl = optlen(opt, i);
  65 
  66                 if (i + optl > tcp_hdrlen)
  67                         break;
  68 
  69                 if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i]))
  70                         continue;
  71 
  72                 for (j = 0; j < optl; ++j) {
  73                         o = opt[i+j];
  74                         n = TCPOPT_NOP;
  75                         if ((i + j) % 2 == 0) {
  76                                 o <<= 8;
  77                                 n <<= 8;
  78                         }
  79                         inet_proto_csum_replace2(&tcph->check, skb, htons(o),
  80                                                  htons(n), false);
  81                 }
  82                 memset(opt + i, TCPOPT_NOP, optl);
  83         }
  84 
  85         return XT_CONTINUE;
  86 }
  87 
  88 static unsigned int
  89 tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_action_param *par)
  90 {
  91         return tcpoptstrip_mangle_packet(skb, par, ip_hdrlen(skb));
  92 }
  93 
  94 #if IS_ENABLED(CONFIG_IP6_NF_MANGLE)
  95 static unsigned int
  96 tcpoptstrip_tg6(struct sk_buff *skb, const struct xt_action_param *par)
  97 {
  98         struct ipv6hdr *ipv6h = ipv6_hdr(skb);
  99         int tcphoff;
 100         u_int8_t nexthdr;
 101         __be16 frag_off;
 102 
 103         nexthdr = ipv6h->nexthdr;
 104         tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off);
 105         if (tcphoff < 0)
 106                 return NF_DROP;
 107 
 108         return tcpoptstrip_mangle_packet(skb, par, tcphoff);
 109 }
 110 #endif
 111 
 112 static struct xt_target tcpoptstrip_tg_reg[] __read_mostly = {
 113         {
 114                 .name       = "TCPOPTSTRIP",
 115                 .family     = NFPROTO_IPV4,
 116                 .table      = "mangle",
 117                 .proto      = IPPROTO_TCP,
 118                 .target     = tcpoptstrip_tg4,
 119                 .targetsize = sizeof(struct xt_tcpoptstrip_target_info),
 120                 .me         = THIS_MODULE,
 121         },
 122 #if IS_ENABLED(CONFIG_IP6_NF_MANGLE)
 123         {
 124                 .name       = "TCPOPTSTRIP",
 125                 .family     = NFPROTO_IPV6,
 126                 .table      = "mangle",
 127                 .proto      = IPPROTO_TCP,
 128                 .target     = tcpoptstrip_tg6,
 129                 .targetsize = sizeof(struct xt_tcpoptstrip_target_info),
 130                 .me         = THIS_MODULE,
 131         },
 132 #endif
 133 };
 134 
 135 static int __init tcpoptstrip_tg_init(void)
 136 {
 137         return xt_register_targets(tcpoptstrip_tg_reg,
 138                                    ARRAY_SIZE(tcpoptstrip_tg_reg));
 139 }
 140 
 141 static void __exit tcpoptstrip_tg_exit(void)
 142 {
 143         xt_unregister_targets(tcpoptstrip_tg_reg,
 144                               ARRAY_SIZE(tcpoptstrip_tg_reg));
 145 }
 146 
 147 module_init(tcpoptstrip_tg_init);
 148 module_exit(tcpoptstrip_tg_exit);
 149 MODULE_AUTHOR("Sven Schnelle <svens@bitebene.org>, Jan Engelhardt <jengelh@medozas.de>");
 150 MODULE_DESCRIPTION("Xtables: TCP option stripping");
 151 MODULE_LICENSE("GPL");
 152 MODULE_ALIAS("ipt_TCPOPTSTRIP");
 153 MODULE_ALIAS("ip6t_TCPOPTSTRIP");

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