OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipv4/] [netfilter/] [ipt_TCPMSS.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * This is a module which is used for setting the MSS option in TCP packets.
3
 *
4
 * Copyright (c) 2000 Marc Boucher
5
 */
6
#include <linux/module.h>
7
#include <linux/skbuff.h>
8
 
9
#include <linux/ip.h>
10
#include <net/tcp.h>
11
 
12
#include <linux/netfilter_ipv4/ip_tables.h>
13
#include <linux/netfilter_ipv4/ipt_TCPMSS.h>
14
 
15
#if 0
16
#define DEBUGP printk
17
#else
18
#define DEBUGP(format, args...)
19
#endif
20
 
21
static u_int16_t
22
cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
23
{
24
        u_int32_t diffs[] = { oldvalinv, newval };
25
        return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
26
                                      oldcheck^0xFFFF));
27
}
28
 
29
static inline unsigned int
30
optlen(const u_int8_t *opt, unsigned int offset)
31
{
32
        /* Beware zero-length options: make finite progress */
33
        if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) return 1;
34
        else return opt[offset+1];
35
}
36
 
37
static unsigned int
38
ipt_tcpmss_target(struct sk_buff **pskb,
39
                  unsigned int hooknum,
40
                  const struct net_device *in,
41
                  const struct net_device *out,
42
                  const void *targinfo,
43
                  void *userinfo)
44
{
45
        const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
46
        struct tcphdr *tcph;
47
        struct iphdr *iph;
48
        u_int16_t tcplen, newtotlen, oldval, newmss;
49
        unsigned int i;
50
        u_int8_t *opt;
51
 
52
        /* raw socket (tcpdump) may have clone of incoming skb: don't
53
           disturb it --RR */
54
        if (skb_cloned(*pskb) && !(*pskb)->sk) {
55
                struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
56
                if (!nskb)
57
                        return NF_DROP;
58
                kfree_skb(*pskb);
59
                *pskb = nskb;
60
        }
61
 
62
        iph = (*pskb)->nh.iph;
63
        tcplen = (*pskb)->len - iph->ihl*4;
64
 
65
        tcph = (void *)iph + iph->ihl*4;
66
 
67
        /* Since it passed flags test in tcp match, we know it is is
68
           not a fragment, and has data >= tcp header length.  SYN
69
           packets should not contain data: if they did, then we risk
70
           running over MTU, sending Frag Needed and breaking things
71
           badly. --RR */
72
        if (tcplen != tcph->doff*4) {
73
                if (net_ratelimit())
74
                        printk(KERN_ERR
75
                               "ipt_tcpmss_target: bad length (%d bytes)\n",
76
                               (*pskb)->len);
77
                return NF_DROP;
78
        }
79
 
80
        if(tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
81
                if(!(*pskb)->dst) {
82
                        if (net_ratelimit())
83
                                printk(KERN_ERR
84
                                        "ipt_tcpmss_target: no dst?! can't determine path-MTU\n");
85
                        return NF_DROP; /* or IPT_CONTINUE ?? */
86
                }
87
 
88
                if((*pskb)->dst->pmtu <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
89
                        if (net_ratelimit())
90
                                printk(KERN_ERR
91
                                        "ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", (*pskb)->dst->pmtu);
92
                        return NF_DROP; /* or IPT_CONTINUE ?? */
93
                }
94
 
95
                newmss = (*pskb)->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr);
96
        } else
97
                newmss = tcpmssinfo->mss;
98
 
99
        opt = (u_int8_t *)tcph;
100
        for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)){
101
                if ((opt[i] == TCPOPT_MSS) &&
102
                    ((tcph->doff*4 - i) >= TCPOLEN_MSS) &&
103
                    (opt[i+1] == TCPOLEN_MSS)) {
104
                        u_int16_t oldmss;
105
 
106
                        oldmss = (opt[i+2] << 8) | opt[i+3];
107
 
108
                        if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
109
                                (oldmss <= newmss))
110
                                        return IPT_CONTINUE;
111
 
112
                        opt[i+2] = (newmss & 0xff00) >> 8;
113
                        opt[i+3] = (newmss & 0x00ff);
114
 
115
                        tcph->check = cheat_check(htons(oldmss)^0xFFFF,
116
                                                  htons(newmss),
117
                                                  tcph->check);
118
 
119
                        DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
120
                               "->%u.%u.%u.%u:%hu changed TCP MSS option"
121
                               " (from %u to %u)\n",
122
                               NIPQUAD((*pskb)->nh.iph->saddr),
123
                               ntohs(tcph->source),
124
                               NIPQUAD((*pskb)->nh.iph->daddr),
125
                               ntohs(tcph->dest),
126
                               oldmss, newmss);
127
                        goto retmodified;
128
                }
129
        }
130
 
131
        /*
132
         * MSS Option not found ?! add it..
133
         */
134
        if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
135
                struct sk_buff *newskb;
136
 
137
                newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
138
                                         TCPOLEN_MSS, GFP_ATOMIC);
139
                if (!newskb) {
140
                        if (net_ratelimit())
141
                                printk(KERN_ERR "ipt_tcpmss_target:"
142
                                       " unable to allocate larger skb\n");
143
                        return NF_DROP;
144
                }
145
 
146
                kfree_skb(*pskb);
147
                *pskb = newskb;
148
                iph = (*pskb)->nh.iph;
149
                tcph = (void *)iph + iph->ihl*4;
150
        }
151
 
152
        skb_put((*pskb), TCPOLEN_MSS);
153
 
154
        opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
155
        memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
156
 
157
        tcph->check = cheat_check(htons(tcplen) ^ 0xFFFF,
158
                                  htons(tcplen + TCPOLEN_MSS), tcph->check);
159
        tcplen += TCPOLEN_MSS;
160
 
161
        opt[0] = TCPOPT_MSS;
162
        opt[1] = TCPOLEN_MSS;
163
        opt[2] = (newmss & 0xff00) >> 8;
164
        opt[3] = (newmss & 0x00ff);
165
 
166
        tcph->check = cheat_check(~0, *((u_int32_t *)opt), tcph->check);
167
 
168
        oldval = ((u_int16_t *)tcph)[6];
169
        tcph->doff += TCPOLEN_MSS/4;
170
        tcph->check = cheat_check(oldval ^ 0xFFFF,
171
                                  ((u_int16_t *)tcph)[6], tcph->check);
172
 
173
        newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
174
        iph->check = cheat_check(iph->tot_len ^ 0xFFFF,
175
                                 newtotlen, iph->check);
176
        iph->tot_len = newtotlen;
177
 
178
        DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
179
               "->%u.%u.%u.%u:%hu added TCP MSS option (%u)\n",
180
               NIPQUAD((*pskb)->nh.iph->saddr),
181
               ntohs(tcph->source),
182
               NIPQUAD((*pskb)->nh.iph->daddr),
183
               ntohs(tcph->dest),
184
               newmss);
185
 
186
 retmodified:
187
        /* If we had a hardware checksum before, it's now invalid */
188
        (*pskb)->ip_summed = CHECKSUM_NONE;
189
        (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
190
        return IPT_CONTINUE;
191
}
192
 
193
#define TH_SYN 0x02
194
 
195
static inline int find_syn_match(const struct ipt_entry_match *m)
196
{
197
        const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
198
 
199
        if (strcmp(m->u.kernel.match->name, "tcp") == 0
200
            && (tcpinfo->flg_cmp & TH_SYN)
201
            && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
202
                return 1;
203
 
204
        return 0;
205
}
206
 
207
/* Must specify -p tcp --syn/--tcp-flags SYN */
208
static int
209
ipt_tcpmss_checkentry(const char *tablename,
210
                      const struct ipt_entry *e,
211
                      void *targinfo,
212
                      unsigned int targinfosize,
213
                      unsigned int hook_mask)
214
{
215
        const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
216
 
217
        if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) {
218
                DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n",
219
                       targinfosize, IPT_ALIGN(sizeof(struct ipt_tcpmss_info)));
220
                return 0;
221
        }
222
 
223
 
224
        if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
225
                        ((hook_mask & ~((1 << NF_IP_FORWARD)
226
                                | (1 << NF_IP_LOCAL_OUT)
227
                                | (1 << NF_IP_POST_ROUTING))) != 0)) {
228
                printk("TCPMSS: path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
229
                return 0;
230
        }
231
 
232
        if (e->ip.proto == IPPROTO_TCP
233
            && !(e->ip.invflags & IPT_INV_PROTO)
234
            && IPT_MATCH_ITERATE(e, find_syn_match))
235
                return 1;
236
 
237
        printk("TCPMSS: Only works on TCP SYN packets\n");
238
        return 0;
239
}
240
 
241
static struct ipt_target ipt_tcpmss_reg
242
= { { NULL, NULL }, "TCPMSS",
243
    ipt_tcpmss_target, ipt_tcpmss_checkentry, NULL, THIS_MODULE };
244
 
245
static int __init init(void)
246
{
247
        return ipt_register_target(&ipt_tcpmss_reg);
248
}
249
 
250
static void __exit fini(void)
251
{
252
        ipt_unregister_target(&ipt_tcpmss_reg);
253
}
254
 
255
module_init(init);
256
module_exit(fini);
257
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.