1338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle/* 2338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * A module for stripping a specific TCP option from TCP packets. 3338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * 4338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * Copyright (C) 2007 Sven Schnelle <svens@bitebene.org> 5338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * Copyright © CC Computer Consultants GmbH, 2007 6338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * 7338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * This program is free software; you can redistribute it and/or modify 8338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * it under the terms of the GNU General Public License version 2 as 9338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * published by the Free Software Foundation. 10338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle */ 11338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 12338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <linux/module.h> 13338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <linux/skbuff.h> 14338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <linux/ip.h> 15338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <linux/ipv6.h> 16338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <linux/tcp.h> 17338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <net/ipv6.h> 18338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <net/tcp.h> 19338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <linux/netfilter/x_tables.h> 20338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#include <linux/netfilter/xt_TCPOPTSTRIP.h> 21338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 22338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellestatic inline unsigned int optlen(const u_int8_t *opt, unsigned int offset) 23338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle{ 24338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle /* Beware zero-length options: make finite progress */ 25338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) 26338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle return 1; 27338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle else 28338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle return opt[offset+1]; 29338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle} 30338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 31338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellestatic unsigned int 32338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelletcpoptstrip_mangle_packet(struct sk_buff *skb, 33bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso const struct xt_action_param *par, 34338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle unsigned int tcphoff, unsigned int minlen) 35338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle{ 36bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso const struct xt_tcpoptstrip_target_info *info = par->targinfo; 37338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle unsigned int optl, i, j; 38338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle struct tcphdr *tcph; 39338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle u_int16_t n, o; 40338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle u_int8_t *opt; 41bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso int len; 42bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso 43bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso /* This is a fragment, no TCP header is available */ 44bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso if (par->fragoff != 0) 45bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso return XT_CONTINUE; 46338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 47338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle if (!skb_make_writable(skb, skb->len)) 48338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle return NF_DROP; 49338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 50bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso len = skb->len - tcphoff; 51ed82c437320c48a4032492f4a55a7e2c934158b6Pablo Neira Ayuso if (len < (int)sizeof(struct tcphdr)) 52bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso return NF_DROP; 53bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso 54338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); 55ed82c437320c48a4032492f4a55a7e2c934158b6Pablo Neira Ayuso if (tcph->doff * 4 > len) 56ed82c437320c48a4032492f4a55a7e2c934158b6Pablo Neira Ayuso return NF_DROP; 57ed82c437320c48a4032492f4a55a7e2c934158b6Pablo Neira Ayuso 58338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle opt = (u_int8_t *)tcph; 59338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 60338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle /* 61338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * Walk through all TCP options - if we find some option to remove, 62338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle * set all octets to %TCPOPT_NOP and adjust checksum. 63338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle */ 64338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle for (i = sizeof(struct tcphdr); i < tcp_hdrlen(skb); i += optl) { 65338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle optl = optlen(opt, i); 66338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 67338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle if (i + optl > tcp_hdrlen(skb)) 68338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle break; 69338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 70338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i])) 71338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle continue; 72338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 73338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle for (j = 0; j < optl; ++j) { 74338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle o = opt[i+j]; 75338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle n = TCPOPT_NOP; 76338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle if ((i + j) % 2 == 0) { 77338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle o <<= 8; 78338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle n <<= 8; 79338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle } 80338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle inet_proto_csum_replace2(&tcph->check, skb, htons(o), 81338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle htons(n), 0); 82338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle } 83338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle memset(opt + i, TCPOPT_NOP, optl); 84338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle } 85338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 86338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle return XT_CONTINUE; 87338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle} 88338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 89338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellestatic unsigned int 904b560b447df83368df44bd3712c0c39b1d79ba04Jan Engelhardttcpoptstrip_tg4(struct sk_buff *skb, const struct xt_action_param *par) 91338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle{ 92bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso return tcpoptstrip_mangle_packet(skb, par, ip_hdrlen(skb), 93338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle sizeof(struct iphdr) + sizeof(struct tcphdr)); 94338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle} 95338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 96c0cd115667bcd23c2a31fe2114beaab3608de68cIgor Maravić#if IS_ENABLED(CONFIG_IP6_NF_MANGLE) 97338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellestatic unsigned int 984b560b447df83368df44bd3712c0c39b1d79ba04Jan Engelhardttcpoptstrip_tg6(struct sk_buff *skb, const struct xt_action_param *par) 99338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle{ 100338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle struct ipv6hdr *ipv6h = ipv6_hdr(skb); 101be8d0d7903af85d396449b34366e7f5b0c9cc58bRoel Kluin int tcphoff; 102338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle u_int8_t nexthdr; 10375f2811c6460ccc59d83c66059943ce9c9f81a18Jesse Gross __be16 frag_off; 104338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 105338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle nexthdr = ipv6h->nexthdr; 10675f2811c6460ccc59d83c66059943ce9c9f81a18Jesse Gross tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off); 107338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle if (tcphoff < 0) 108338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle return NF_DROP; 109338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 110bc6bcb59dd7c184d229f9e86d08aa56059938a4cPablo Neira Ayuso return tcpoptstrip_mangle_packet(skb, par, tcphoff, 111338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle sizeof(*ipv6h) + sizeof(struct tcphdr)); 112338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle} 113338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#endif 114338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 115338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellestatic struct xt_target tcpoptstrip_tg_reg[] __read_mostly = { 116338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle { 117338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .name = "TCPOPTSTRIP", 118ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt .family = NFPROTO_IPV4, 119338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .table = "mangle", 120338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .proto = IPPROTO_TCP, 121338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .target = tcpoptstrip_tg4, 122338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .targetsize = sizeof(struct xt_tcpoptstrip_target_info), 123338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .me = THIS_MODULE, 124338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle }, 125c0cd115667bcd23c2a31fe2114beaab3608de68cIgor Maravić#if IS_ENABLED(CONFIG_IP6_NF_MANGLE) 126338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle { 127338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .name = "TCPOPTSTRIP", 128ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt .family = NFPROTO_IPV6, 129338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .table = "mangle", 130338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .proto = IPPROTO_TCP, 131338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .target = tcpoptstrip_tg6, 132338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .targetsize = sizeof(struct xt_tcpoptstrip_target_info), 133338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle .me = THIS_MODULE, 134338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle }, 135338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle#endif 136338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle}; 137338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 138338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellestatic int __init tcpoptstrip_tg_init(void) 139338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle{ 140338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle return xt_register_targets(tcpoptstrip_tg_reg, 141338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle ARRAY_SIZE(tcpoptstrip_tg_reg)); 142338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle} 143338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 144338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellestatic void __exit tcpoptstrip_tg_exit(void) 145338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle{ 146338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle xt_unregister_targets(tcpoptstrip_tg_reg, 147338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle ARRAY_SIZE(tcpoptstrip_tg_reg)); 148338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle} 149338e8a79262c3709e314fbcc7ca193323e534934Sven Schnelle 150338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellemodule_init(tcpoptstrip_tg_init); 151338e8a79262c3709e314fbcc7ca193323e534934Sven Schnellemodule_exit(tcpoptstrip_tg_exit); 152408ffaa4a11ddd6f730be520479fd5cd890c57d3Jan EngelhardtMODULE_AUTHOR("Sven Schnelle <svens@bitebene.org>, Jan Engelhardt <jengelh@medozas.de>"); 1532ae15b64e6a1608c840c60df38e8e5eef7b2b8c3Jan EngelhardtMODULE_DESCRIPTION("Xtables: TCP option stripping"); 154338e8a79262c3709e314fbcc7ca193323e534934Sven SchnelleMODULE_LICENSE("GPL"); 155338e8a79262c3709e314fbcc7ca193323e534934Sven SchnelleMODULE_ALIAS("ipt_TCPOPTSTRIP"); 156338e8a79262c3709e314fbcc7ca193323e534934Sven SchnelleMODULE_ALIAS("ip6t_TCPOPTSTRIP"); 157