at v3.10-rc4 154 lines 4.0 kB view raw
1/* 2 * A module for stripping a specific TCP option from TCP packets. 3 * 4 * Copyright (C) 2007 Sven Schnelle <svens@bitebene.org> 5 * Copyright © CC Computer Consultants GmbH, 2007 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/module.h> 13#include <linux/skbuff.h> 14#include <linux/ip.h> 15#include <linux/ipv6.h> 16#include <linux/tcp.h> 17#include <net/ipv6.h> 18#include <net/tcp.h> 19#include <linux/netfilter/x_tables.h> 20#include <linux/netfilter/xt_TCPOPTSTRIP.h> 21 22static inline unsigned int optlen(const u_int8_t *opt, unsigned int offset) 23{ 24 /* Beware zero-length options: make finite progress */ 25 if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) 26 return 1; 27 else 28 return opt[offset+1]; 29} 30 31static unsigned int 32tcpoptstrip_mangle_packet(struct sk_buff *skb, 33 const struct xt_action_param *par, 34 unsigned int tcphoff, unsigned int minlen) 35{ 36 const struct xt_tcpoptstrip_target_info *info = par->targinfo; 37 unsigned int optl, i, j; 38 struct tcphdr *tcph; 39 u_int16_t n, o; 40 u_int8_t *opt; 41 int len; 42 43 /* This is a fragment, no TCP header is available */ 44 if (par->fragoff != 0) 45 return XT_CONTINUE; 46 47 if (!skb_make_writable(skb, skb->len)) 48 return NF_DROP; 49 50 len = skb->len - tcphoff; 51 if (len < (int)sizeof(struct tcphdr) || 52 tcp_hdr(skb)->doff * 4 > len) 53 return NF_DROP; 54 55 tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); 56 opt = (u_int8_t *)tcph; 57 58 /* 59 * Walk through all TCP options - if we find some option to remove, 60 * set all octets to %TCPOPT_NOP and adjust checksum. 61 */ 62 for (i = sizeof(struct tcphdr); i < tcp_hdrlen(skb); i += optl) { 63 optl = optlen(opt, i); 64 65 if (i + optl > tcp_hdrlen(skb)) 66 break; 67 68 if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i])) 69 continue; 70 71 for (j = 0; j < optl; ++j) { 72 o = opt[i+j]; 73 n = TCPOPT_NOP; 74 if ((i + j) % 2 == 0) { 75 o <<= 8; 76 n <<= 8; 77 } 78 inet_proto_csum_replace2(&tcph->check, skb, htons(o), 79 htons(n), 0); 80 } 81 memset(opt + i, TCPOPT_NOP, optl); 82 } 83 84 return XT_CONTINUE; 85} 86 87static unsigned int 88tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_action_param *par) 89{ 90 return tcpoptstrip_mangle_packet(skb, par, ip_hdrlen(skb), 91 sizeof(struct iphdr) + sizeof(struct tcphdr)); 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 sizeof(*ipv6h) + sizeof(struct tcphdr)); 110} 111#endif 112 113static struct xt_target tcpoptstrip_tg_reg[] __read_mostly = { 114 { 115 .name = "TCPOPTSTRIP", 116 .family = NFPROTO_IPV4, 117 .table = "mangle", 118 .proto = IPPROTO_TCP, 119 .target = tcpoptstrip_tg4, 120 .targetsize = sizeof(struct xt_tcpoptstrip_target_info), 121 .me = THIS_MODULE, 122 }, 123#if IS_ENABLED(CONFIG_IP6_NF_MANGLE) 124 { 125 .name = "TCPOPTSTRIP", 126 .family = NFPROTO_IPV6, 127 .table = "mangle", 128 .proto = IPPROTO_TCP, 129 .target = tcpoptstrip_tg6, 130 .targetsize = sizeof(struct xt_tcpoptstrip_target_info), 131 .me = THIS_MODULE, 132 }, 133#endif 134}; 135 136static int __init tcpoptstrip_tg_init(void) 137{ 138 return xt_register_targets(tcpoptstrip_tg_reg, 139 ARRAY_SIZE(tcpoptstrip_tg_reg)); 140} 141 142static void __exit tcpoptstrip_tg_exit(void) 143{ 144 xt_unregister_targets(tcpoptstrip_tg_reg, 145 ARRAY_SIZE(tcpoptstrip_tg_reg)); 146} 147 148module_init(tcpoptstrip_tg_init); 149module_exit(tcpoptstrip_tg_exit); 150MODULE_AUTHOR("Sven Schnelle <svens@bitebene.org>, Jan Engelhardt <jengelh@medozas.de>"); 151MODULE_DESCRIPTION("Xtables: TCP option stripping"); 152MODULE_LICENSE("GPL"); 153MODULE_ALIAS("ipt_TCPOPTSTRIP"); 154MODULE_ALIAS("ip6t_TCPOPTSTRIP");