kernels/linux-2.4.0/net/ipv4/netfilter/ip_nat_ftp.c
/* This is interesting.  We simply use the port given us by the client
   or server.  In practice it's extremely unlikely to clash; if it
   does, the rule won't be able to get a unique tuple and will drop
   the packets. */
This is interesting.  We simply use the port given us by the client
or server.  In practice it's extremely unlikely to clash; if it
does, the rule won't be able to get a unique tuple and will drop
the packets.
This is interesting . We simply use the port given us by the client or server . In practice it ' s extremely unlikely to clash ; if it does the rule won ' t be able to get a unique tuple and will drop the packets .
static int
mangle_packet(struct sk_buff **pskb,
	      u_int32_t newip,
	      u_int16_t port,
	      unsigned int matchoff,
	      unsigned int matchlen,
	      struct ip_nat_ftp_info *this_way,
	      struct ip_nat_ftp_info *other_way)
{
	struct iphdr *iph = (*pskb)->nh.iph;
	struct tcphdr *tcph;
	unsigned char *data;
	unsigned int tcplen, newlen, newtcplen;
	char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
	MUST_BE_LOCKED(&ip_ftp_lock);
	sprintf(buffer, "%u,%u,%u,%u,%u,%u",
		NIPQUAD(newip), port>>8, port&0xFF);
	tcplen = (*pskb)->len - iph->ihl * 4;
	newtcplen = tcplen - matchlen + strlen(buffer);
	newlen = iph->ihl*4 + newtcplen;
	if (newlen > 65535) {
		if (net_ratelimit())
			printk("nat_ftp cheat: %u.%u.%u.%u->%u.%u.%u.%u %u\n",
			       NIPQUAD((*pskb)->nh.iph->saddr),
			       NIPQUAD((*pskb)->nh.iph->daddr),
			       (*pskb)->nh.iph->protocol);
		return 0;
	}
	if (newlen > (*pskb)->len + skb_tailroom(*pskb)) {
		struct sk_buff *newskb;
		newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
					 newlen - (*pskb)->len,
					 GFP_ATOMIC);
		if (!newskb) {
			DEBUGP("ftp: oom\n");
			return 0;
		} else {
			kfree_skb(*pskb);
			*pskb = newskb;
			iph = (*pskb)->nh.iph;
		}
	}
	tcph = (void *)iph + iph->ihl*4;
	data = (void *)tcph + tcph->doff*4;
	DEBUGP("Mapping `%.*s' [%u %u %u] to new `%s' [%u]\n",
		 (int)matchlen, data+matchoff,
		 data[matchoff], data[matchoff+1],
		 matchlen, buffer, strlen(buffer));
	if (this_way->syn_offset_before == this_way->syn_offset_after
	    || before(this_way->syn_correction_pos, ntohl(tcph->seq))) {
		this_way->syn_correction_pos = ntohl(tcph->seq);
		this_way->syn_offset_before = this_way->syn_offset_after;
		this_way->syn_offset_after = (int32_t)
			this_way->syn_offset_before + newlen - (*pskb)->len;
	}
	memmove(data + matchoff + strlen(buffer),
		data + matchoff + matchlen,
		(*pskb)->tail - (data + matchoff + matchlen));
	memcpy(data + matchoff, buffer, strlen(buffer));
	if (newlen > (*pskb)->len) {
		DEBUGP("ip_nat_ftp: Extending packet by %u to %u bytes\n",
		       newlen - (*pskb)->len, newlen);
		skb_put(*pskb, newlen - (*pskb)->len);
	} else {
		DEBUGP("ip_nat_ftp: Shrinking packet from %u to %u bytes\n",
		       (*pskb)->len, newlen);
		skb_trim(*pskb, newlen);
	}
	iph->tot_len = htons(newlen);
	(*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
				     newtcplen - tcph->doff*4, 0);
	tcph->check = 0;
	tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr,
				   csum_partial((char *)tcph, tcph->doff*4,
						(*pskb)->csum));
	ip_send_check(iph);
	return 1;
}
static int mangle_packet ( struct sk_buff * * pskb , u_int32_t newip , u_int16_t port , unsigned int matchoff , unsigned int matchlen , struct ip_nat_ftp_info * this_way , struct ip_nat_ftp_info * other_way ) { struct iphdr * iph = ( * pskb ) -> nh . iph ; struct tcphdr * tcph ; unsigned char * data ; unsigned int tcplen , newlen , newtcplen ; char buffer [ sizeof ( " " ) ] ; MUST_BE_LOCKED ( & ip_ftp_lock ) ; sprintf ( buffer , " " , NIPQUAD ( newip ) , port >> 8 , port & 0xFF ) ; tcplen = ( * pskb ) -> len - iph -> ihl * 4 ; newtcplen = tcplen - matchlen + strlen ( buffer ) ; newlen = iph -> ihl * 4 + newtcplen ; if ( newlen > 65535 ) { if ( net_ratelimit ( ) ) printk ( " \n " , NIPQUAD ( ( * pskb ) -> nh . iph -> saddr ) , NIPQUAD ( ( * pskb ) -> nh . iph -> daddr ) , ( * pskb ) -> nh . iph -> protocol ) ; return 0 ; } if ( newlen > ( * pskb ) -> len + skb_tailroom ( * pskb ) ) { struct sk_buff * newskb ; newskb = skb_copy_expand ( * pskb , skb_headroom ( * pskb ) , newlen - ( * pskb ) -> len , GFP_ATOMIC ) ; if ( ! newskb ) { DEBUGP ( " \n " ) ; return 0 ; } else { kfree_skb ( * pskb ) ; * pskb = newskb ; iph = ( * pskb ) -> nh . iph ; } } tcph = ( void * ) iph + iph -> ihl * 4 ; data = ( void * ) tcph + tcph -> doff * 4 ; DEBUGP ( " \n " , ( int ) matchlen , data + matchoff , data [ matchoff ] , data [ matchoff + 1 ] , matchlen , buffer , strlen ( buffer ) ) ; if ( this_way -> syn_offset_before == this_way -> syn_offset_after || before ( this_way -> syn_correction_pos , ntohl ( tcph -> seq ) ) ) { this_way -> syn_correction_pos = ntohl ( tcph -> seq ) ; this_way -> syn_offset_before = this_way -> syn_offset_after ; this_way -> syn_offset_after = ( int32_t ) this_way -> syn_offset_before + newlen - ( * pskb ) -> len ; } memmove ( data + matchoff + strlen ( buffer ) , data + matchoff + matchlen , ( * pskb ) -> tail - ( data + matchoff + matchlen ) ) ; memcpy ( data + matchoff , buffer , strlen ( buffer ) ) ; if ( newlen > ( * pskb ) -> len ) { DEBUGP ( " \n " , newlen - ( * pskb ) -> len , newlen ) ; skb_put ( * pskb , newlen - ( * pskb ) -> len ) ; } else { DEBUGP ( " \n " , ( * pskb ) -> len , newlen ) ; skb_trim ( * pskb , newlen ) ; } iph -> tot_len = htons ( newlen ) ; ( * pskb ) -> csum = csum_partial ( ( char * ) tcph + tcph -> doff * 4 , newtcplen - tcph -> doff * 4 , 0 ) ; tcph -> check = 0 ; tcph -> check = tcp_v4_check ( tcph , newtcplen , iph -> saddr , iph -> daddr , csum_partial ( ( char * ) tcph , tcph -> doff * 4 , ( * pskb ) -> csum ) ) ; ip_send_check ( iph ) ; return 1 ; }
This is interesting.
This is interesting .
/* So there I am, in the middle of my `netfilter-is-wonderful'
	   talk in Sydney, and someone asks `What happens if you try
	   to enlarge a 64k packet here?'.  I think I said something
	   eloquent like `fuck'. */ /* SYN adjust.  If it's uninitialized, or this is after last
           correction, record it: we don't handle more than one
           adjustment in the window, but do deal with common case of a
           retransmit. */ /* Move post-replacement */ /* Resize packet. */ /* Fix checksums */