1 Please find below a patch to modify some existing and add some new
2 convenience functions to the newnat core conntrack and nat functions.
6 - make ip_nat_resize_packet more generic (TCP and UDP)
7 - optimize away the memmove in ip_nat_mangle_tcp_packet when the
8 replacement string is the same size as the match string
9 - add ip_nat_mangle_udp_packet
11 The latter change/function is an implementation of
12 ip_nat_mangle_udp_packet which takes an array of modifications to be
13 made to a packet. A similar TCP version could/should be made.
15 These changes are a prerequisite for the patch I will be submitting
16 subsequently which is a NAT/conntrack helper pair for the Amanda
17 backup protocol. I will attempt to do that one patch-o-matic compliant.
19 If there is anything unacceptable in either patch submissions, I will
20 be most willing to make corrections.
26 diff -uNr linux-2.4.18-6mdk-pom-clean/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.4.18-6mdkuml-48um-pom/include/linux/netfilter_ipv4/ip_nat_helper.h
27 --- linux-2.4.18-6mdk-pom-clean/include/linux/netfilter_ipv4/ip_nat_helper.h 2002-08-01 14:21:44.000000000 -0400
28 +++ linux-2.4.18-6mdkuml-48um-pom/include/linux/netfilter_ipv4/ip_nat_helper.h 2002-08-15 12:47:38.000000000 -0400
30 struct ip_nat_info *info);
33 +struct ip_nat_mangle_rep {
34 + unsigned int match_offset;
35 + unsigned int match_len;
37 + unsigned int rep_len;
40 extern struct list_head helpers;
42 extern int ip_nat_helper_register(struct ip_nat_helper *me);
44 unsigned int match_len,
46 unsigned int rep_len);
47 +extern int ip_nat_mangle_udp_packet(struct sk_buff **skb,
48 + struct ip_conntrack *ct,
49 + enum ip_conntrack_info ctinfo,
50 + unsigned int match_offset,
51 + unsigned int match_len,
53 + unsigned int rep_len);
54 extern int ip_nat_seq_adjust(struct sk_buff *skb,
55 struct ip_conntrack *ct,
56 enum ip_conntrack_info ctinfo);
57 diff -uNr linux-2.4.18-6mdk-pom-clean/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.18-6mdkuml-48um-pom/net/ipv4/netfilter/ip_nat_helper.c
58 --- linux-2.4.18-6mdk-pom-clean/net/ipv4/netfilter/ip_nat_helper.c 2002-07-25 08:56:27.000000000 -0400
59 +++ linux-2.4.18-6mdkuml-48um-pom/net/ipv4/netfilter/ip_nat_helper.c 2002-08-16 03:11:33.000000000 -0400
61 * - add support for SACK adjustment
62 * 14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
63 * - merge SACK support into newnat API
64 + * 16 Aug 2002 Brian J. Murrell <netfilter@interlinx.bc.ca>:
65 + * - make ip_nat_resize_packet more generic (TCP and UDP)
66 + * - add ip_nat_mangle_udp_packet
68 #include <linux/version.h>
69 #include <linux/config.h>
76 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
77 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
82 - struct tcphdr *tcph;
85 struct ip_nat_seq *this_way, *other_way;
87 DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n",
88 (*skb)->len, new_size);
90 - iph = (*skb)->nh.iph;
91 - tcph = (void *)iph + iph->ihl*4;
92 - data = (void *)tcph + tcph->doff*4;
94 dir = CTINFO2DIR(ctinfo);
96 this_way = &ct->nat.info.seq[dir];
100 iph = (*skb)->nh.iph;
101 - tcph = (void *)iph + iph->ihl*4;
102 - data = (void *)tcph + tcph->doff*4;
104 - DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
105 - DUMP_OFFSET(this_way);
106 + if (iph->protocol == IPPROTO_TCP) {
107 + struct tcphdr *tcph = (void *)iph + iph->ihl*4;
108 + void *data = (void *)tcph + tcph->doff*4;
110 + DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
111 + DUMP_OFFSET(this_way);
113 + LOCK_BH(&ip_nat_seqofs_lock);
115 + /* SYN adjust. If it's uninitialized, of this is after last
116 + * correction, record it: we don't handle more than one
117 + * adjustment in the window, but do deal with common case of a
119 + if (this_way->offset_before == this_way->offset_after
120 + || before(this_way->correction_pos, ntohl(tcph->seq))) {
121 + this_way->correction_pos = ntohl(tcph->seq);
122 + this_way->offset_before = this_way->offset_after;
123 + this_way->offset_after = (int32_t)
124 + this_way->offset_before + new_size -
128 - LOCK_BH(&ip_nat_seqofs_lock);
129 + UNLOCK_BH(&ip_nat_seqofs_lock);
131 - /* SYN adjust. If it's uninitialized, of this is after last
132 - * correction, record it: we don't handle more than one
133 - * adjustment in the window, but do deal with common case of a
135 - if (this_way->offset_before == this_way->offset_after
136 - || before(this_way->correction_pos, ntohl(tcph->seq))) {
137 - this_way->correction_pos = ntohl(tcph->seq);
138 - this_way->offset_before = this_way->offset_after;
139 - this_way->offset_after = (int32_t)
140 - this_way->offset_before + new_size - (*skb)->len;
141 + DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
142 + DUMP_OFFSET(this_way);
145 - UNLOCK_BH(&ip_nat_seqofs_lock);
147 - DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
148 - DUMP_OFFSET(this_way);
154 /* Generic function for mangling variable-length address changes inside
155 - * NATed connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command in FTP).
156 + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
159 * Takes care about all the nasty sequence number changes, checksumming,
160 * skb enlargement, ...
161 @@ -174,10 +177,11 @@
162 tcph = (void *)iph + iph->ihl*4;
163 data = (void *)tcph + tcph->doff*4;
165 - /* move post-replacement */
166 - memmove(data + match_offset + rep_len,
167 - data + match_offset + match_len,
168 - (*skb)->tail - (data + match_offset + match_len));
169 + if (rep_len != match_len)
170 + /* move post-replacement */
171 + memmove(data + match_offset + rep_len,
172 + data + match_offset + match_len,
173 + (*skb)->tail - (data + match_offset + match_len));
175 /* insert data from buffer */
176 memcpy(data + match_offset, rep_buffer, rep_len);
177 @@ -207,6 +211,109 @@
182 +/* Generic function for mangling variable-length address changes inside
183 + * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
184 + * command in the Amanda protocol)
186 + * Takes care about all the nasty sequence number changes, checksumming,
187 + * skb enlargement, ...
189 + * XXX - This function could be merged with ip_nat_mangle_tcp_packet which
190 + * should be fairly easy to do.
193 +ip_nat_mangle_udp_packet(struct sk_buff **skb,
194 + struct ip_conntrack *ct,
195 + enum ip_conntrack_info ctinfo,
196 + unsigned int match_offset,
197 + unsigned int match_len,
199 + unsigned int rep_len)
201 + struct iphdr *iph = (*skb)->nh.iph;
202 + struct udphdr *udph = (void *)iph + iph->ihl * 4;
203 + unsigned char *data;
204 + u_int32_t udplen, newlen, newudplen;
206 + udplen = (*skb)->len - iph->ihl*4;
207 + newudplen = udplen - match_len + rep_len;
208 + newlen = iph->ihl*4 + newudplen;
210 + if (newlen > 65535) {
211 + if (net_ratelimit())
212 + printk("ip_nat_mangle_udp_packet: nat'ed packet "
213 + "exceeds maximum packet size\n");
217 + if ((*skb)->len != newlen) {
218 + if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
219 + printk("resize_packet failed!!\n");
224 + /* Alexey says: if a hook changes _data_ ... it can break
225 + original packet sitting in tcp queue and this is fatal */
226 + if (skb_cloned(*skb)) {
227 + struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
229 + if (net_ratelimit())
230 + printk("Out of memory cloning TCP packet\n");
233 + /* Rest of kernel will get very unhappy if we pass it
234 + a suddenly-orphaned skbuff */
236 + skb_set_owner_w(nskb, (*skb)->sk);
241 + /* skb may be copied !! */
242 + iph = (*skb)->nh.iph;
243 + udph = (void *)iph + iph->ihl*4;
244 + data = (void *)udph + sizeof(struct udphdr);
246 + if (rep_len != match_len)
247 + /* move post-replacement */
248 + memmove(data + match_offset + rep_len,
249 + data + match_offset + match_len,
250 + (*skb)->tail - (data + match_offset + match_len));
252 + /* insert data from buffer */
253 + memcpy(data + match_offset, rep_buffer, rep_len);
255 + /* update skb info */
256 + if (newlen > (*skb)->len) {
257 + DEBUGP("ip_nat_mangle_udp_packet: Extending packet by "
258 + "%u to %u bytes\n", newlen - (*skb)->len, newlen);
259 + skb_put(*skb, newlen - (*skb)->len);
261 + DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from "
262 + "%u to %u bytes\n", (*skb)->len, newlen);
263 + skb_trim(*skb, newlen);
266 + /* update the length of the UDP and IP packets to the new values*/
267 + udph->len = htons((*skb)->len - iph->ihl*4);
268 + iph->tot_len = htons(newlen);
270 + /* fix checksum information */
271 + (*skb)->csum = csum_partial((char *)udph + sizeof(struct udphdr),
272 + newudplen - sizeof(struct udphdr), 0);
275 + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, newudplen,
277 + csum_partial((char *)udph,
278 + sizeof(struct udphdr),
280 + ip_send_check(iph);
285 /* Adjust one found SACK option including checksum correction */
287 diff -uNr linux-2.4.18-6mdk-pom-clean/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.18-6mdkuml-48um-pom/net/ipv4/netfilter/ip_nat_standalone.c
288 --- linux-2.4.18-6mdk-pom-clean/net/ipv4/netfilter/ip_nat_standalone.c 2002-08-16 03:56:03.000000000 -0400
289 +++ linux-2.4.18-6mdkuml-48um-pom/net/ipv4/netfilter/ip_nat_standalone.c 2002-08-16 03:55:29.000000000 -0400
291 EXPORT_SYMBOL(ip_nat_helper_unregister);
292 EXPORT_SYMBOL(ip_nat_cheat_check);
293 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
294 +EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
295 EXPORT_SYMBOL(ip_nat_used_tuple);
296 MODULE_LICENSE("GPL");