Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0abee526 authored by Changli Gao's avatar Changli Gao Committed by Patrick McHardy
Browse files

netfilter: nf_nat: add nf_nat_csum()



Add a static function nf_nat_csum() to replace the duplicate code in
nf_nat_mangle_udp_packet() and __nf_nat_mangle_tcp_packet().

Signed-off-by: default avatarChangli Gao <xiaosuo@gmail.com>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent 068e8a30
Loading
Loading
Loading
Loading
+31 −45
Original line number Diff line number Diff line
@@ -153,6 +153,35 @@ void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
}
EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);

static void nf_nat_csum(struct sk_buff *skb, struct iphdr *iph, void *data,
			int datalen, __sum16 *check, int oldlen)
{
	struct rtable *rt = skb_rtable(skb);

	if (skb->ip_summed != CHECKSUM_PARTIAL) {
		if (!(rt->rt_flags & RTCF_LOCAL) &&
		    skb->dev->features & NETIF_F_V4_CSUM) {
			skb->ip_summed = CHECKSUM_PARTIAL;
			skb->csum_start = skb_headroom(skb) +
					  skb_network_offset(skb) +
					  iph->ihl * 4;
			skb->csum_offset = (void *)check - data;
			*check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
						    datalen, iph->protocol, 0);
		} else {
			*check = 0;
			*check = csum_tcpudp_magic(iph->saddr, iph->daddr,
						   datalen, iph->protocol,
						   csum_partial(data, datalen,
								0));
			if (iph->protocol == IPPROTO_UDP && !*check)
				*check = CSUM_MANGLED_0;
		}
	} else
		inet_proto_csum_replace2(check, skb,
					 htons(oldlen), htons(datalen), 1);
}

/* Generic function for mangling variable-length address changes inside
 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
 * command in FTP).
@@ -169,7 +198,6 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
			       const char *rep_buffer,
			       unsigned int rep_len, bool adjust)
{
	struct rtable *rt = skb_rtable(skb);
	struct iphdr *iph;
	struct tcphdr *tcph;
	int oldlen, datalen;
@@ -192,26 +220,7 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
			match_offset, match_len, rep_buffer, rep_len);

	datalen = skb->len - iph->ihl*4;
	if (skb->ip_summed != CHECKSUM_PARTIAL) {
		if (!(rt->rt_flags & RTCF_LOCAL) &&
		    skb->dev->features & NETIF_F_V4_CSUM) {
			skb->ip_summed = CHECKSUM_PARTIAL;
			skb->csum_start = skb_headroom(skb) +
					  skb_network_offset(skb) +
					  iph->ihl * 4;
			skb->csum_offset = offsetof(struct tcphdr, check);
			tcph->check = ~tcp_v4_check(datalen,
						    iph->saddr, iph->daddr, 0);
		} else {
			tcph->check = 0;
			tcph->check = tcp_v4_check(datalen,
						   iph->saddr, iph->daddr,
						   csum_partial(tcph,
								datalen, 0));
		}
	} else
		inet_proto_csum_replace2(&tcph->check, skb,
					 htons(oldlen), htons(datalen), 1);
	nf_nat_csum(skb, iph, tcph, datalen, &tcph->check, oldlen);

	if (adjust && rep_len != match_len)
		nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
@@ -240,7 +249,6 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
			 const char *rep_buffer,
			 unsigned int rep_len)
{
	struct rtable *rt = skb_rtable(skb);
	struct iphdr *iph;
	struct udphdr *udph;
	int datalen, oldlen;
@@ -274,29 +282,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
	if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
		return 1;

	if (skb->ip_summed != CHECKSUM_PARTIAL) {
		if (!(rt->rt_flags & RTCF_LOCAL) &&
		    skb->dev->features & NETIF_F_V4_CSUM) {
			skb->ip_summed = CHECKSUM_PARTIAL;
			skb->csum_start = skb_headroom(skb) +
					  skb_network_offset(skb) +
					  iph->ihl * 4;
			skb->csum_offset = offsetof(struct udphdr, check);
			udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
							 datalen, IPPROTO_UDP,
							 0);
		} else {
			udph->check = 0;
			udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
							datalen, IPPROTO_UDP,
							csum_partial(udph,
								     datalen, 0));
			if (!udph->check)
				udph->check = CSUM_MANGLED_0;
		}
	} else
		inet_proto_csum_replace2(&udph->check, skb,
					 htons(oldlen), htons(datalen), 1);
	nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen);

	return 1;
}