cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xt_TCPOPTSTRIP.c (3857B)


      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
     19static 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
     28static unsigned int
     29tcpoptstrip_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
     88static unsigned int
     89tcpoptstrip_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)
     95static unsigned int
     96tcpoptstrip_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
    112static 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
    135static int __init tcpoptstrip_tg_init(void)
    136{
    137	return xt_register_targets(tcpoptstrip_tg_reg,
    138				   ARRAY_SIZE(tcpoptstrip_tg_reg));
    139}
    140
    141static void __exit tcpoptstrip_tg_exit(void)
    142{
    143	xt_unregister_targets(tcpoptstrip_tg_reg,
    144			      ARRAY_SIZE(tcpoptstrip_tg_reg));
    145}
    146
    147module_init(tcpoptstrip_tg_init);
    148module_exit(tcpoptstrip_tg_exit);
    149MODULE_AUTHOR("Sven Schnelle <svens@bitebene.org>, Jan Engelhardt <jengelh@medozas.de>");
    150MODULE_DESCRIPTION("Xtables: TCP option stripping");
    151MODULE_LICENSE("GPL");
    152MODULE_ALIAS("ipt_TCPOPTSTRIP");
    153MODULE_ALIAS("ip6t_TCPOPTSTRIP");