Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 34426
b: refs/heads/master
c: 4cf411d
h: refs/heads/master
v: v3
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Sep 22, 2006
1 parent 3d1a419 commit 43d33c6
Show file tree
Hide file tree
Showing 15 changed files with 139 additions and 118 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 84fa7933a33f806bbbaae6775e87459b1ec584c0
refs/heads/master: 4cf411de49c65140b3c259748629b561c0d3340f
6 changes: 6 additions & 0 deletions trunk/include/linux/netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,12 @@ extern void nf_invalidate_cache(int pf);
Returns true or false. */
extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);

extern u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval,
u_int32_t csum);
extern u_int16_t nf_proto_csum_update(struct sk_buff *skb,
u_int32_t oldval, u_int32_t newval,
u_int16_t csum, int pseudohdr);

struct nf_afinfo {
unsigned short family;
unsigned int (*checksum)(struct sk_buff *skb, unsigned int hook,
Expand Down
4 changes: 0 additions & 4 deletions trunk/include/linux/netfilter_ipv4/ip_nat.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,6 @@ extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack,
extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
const struct ip_conntrack *ignored_conntrack);

/* Calculate relative checksum. */
extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
u_int32_t newval,
u_int16_t oldcheck);
#else /* !__KERNEL__: iptables wants this to compile. */
#define ip_nat_multi_range ip_nat_multi_range_compat
#endif /*__KERNEL__*/
Expand Down
8 changes: 4 additions & 4 deletions trunk/include/linux/netfilter_ipv4/ip_nat_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ extern unsigned int ip_nat_packet(struct ip_conntrack *ct,
unsigned int hooknum,
struct sk_buff **pskb);

extern int ip_nat_icmp_reply_translation(struct sk_buff **pskb,
struct ip_conntrack *ct,
enum ip_nat_manip_type manip,
enum ip_conntrack_dir dir);
extern int ip_nat_icmp_reply_translation(struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pskb);
#endif /* _IP_NAT_CORE_H */
52 changes: 20 additions & 32 deletions trunk/net/ipv4/netfilter/ip_nat_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,6 @@ static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
write_unlock_bh(&ip_nat_lock);
}

/* We do checksum mangling, so if they were wrong before they're still
* wrong. Also works for incomplete packets (eg. ICMP dest
* unreachables.) */
u_int16_t
ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
{
u_int32_t diffs[] = { oldvalinv, newval };
return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
oldcheck^0xFFFF));
}
EXPORT_SYMBOL(ip_nat_cheat_check);

/* Is this tuple already taken? (not by us) */
int
ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
Expand Down Expand Up @@ -378,12 +366,12 @@ manip_pkt(u_int16_t proto,
iph = (void *)(*pskb)->data + iphdroff;

if (maniptype == IP_NAT_MANIP_SRC) {
iph->check = ip_nat_cheat_check(~iph->saddr, target->src.ip,
iph->check);
iph->check = nf_csum_update(~iph->saddr, target->src.ip,
iph->check);
iph->saddr = target->src.ip;
} else {
iph->check = ip_nat_cheat_check(~iph->daddr, target->dst.ip,
iph->check);
iph->check = nf_csum_update(~iph->daddr, target->dst.ip,
iph->check);
iph->daddr = target->dst.ip;
}
return 1;
Expand Down Expand Up @@ -423,18 +411,20 @@ unsigned int ip_nat_packet(struct ip_conntrack *ct,
EXPORT_SYMBOL_GPL(ip_nat_packet);

/* Dir is direction ICMP is coming from (opposite to packet it contains) */
int ip_nat_icmp_reply_translation(struct sk_buff **pskb,
struct ip_conntrack *ct,
enum ip_nat_manip_type manip,
enum ip_conntrack_dir dir)
int ip_nat_icmp_reply_translation(struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pskb)
{
struct {
struct icmphdr icmp;
struct iphdr ip;
} *inside;
struct ip_conntrack_tuple inner, target;
int hdrlen = (*pskb)->nh.iph->ihl * 4;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned long statusbit;
enum ip_nat_manip_type manip = HOOK2MANIP(hooknum);

if (!skb_make_writable(pskb, hdrlen + sizeof(*inside)))
return 0;
Expand All @@ -443,12 +433,8 @@ int ip_nat_icmp_reply_translation(struct sk_buff **pskb,

/* We're actually going to mangle it beyond trivial checksum
adjustment, so make sure the current checksum is correct. */
if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) {
hdrlen = (*pskb)->nh.iph->ihl * 4;
if ((u16)csum_fold(skb_checksum(*pskb, hdrlen,
(*pskb)->len - hdrlen, 0)))
return 0;
}
if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0))
return 0;

/* Must be RELATED */
IP_NF_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED ||
Expand Down Expand Up @@ -487,12 +473,14 @@ int ip_nat_icmp_reply_translation(struct sk_buff **pskb,
!manip))
return 0;

/* Reloading "inside" here since manip_pkt inner. */
inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
inside->icmp.checksum = 0;
inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
(*pskb)->len - hdrlen,
0));
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
/* Reloading "inside" here since manip_pkt inner. */
inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
inside->icmp.checksum = 0;
inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
(*pskb)->len - hdrlen,
0));
}

/* Change outer to look the reply to an incoming packet
* (proto 0 means don't invert per-proto part). */
Expand Down
59 changes: 41 additions & 18 deletions trunk/net/ipv4/netfilter/ip_nat_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
{
struct iphdr *iph;
struct tcphdr *tcph;
int datalen;
int oldlen, datalen;

if (!skb_make_writable(pskb, (*pskb)->len))
return 0;
Expand All @@ -180,13 +180,22 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
iph = (*pskb)->nh.iph;
tcph = (void *)iph + iph->ihl*4;

oldlen = (*pskb)->len - iph->ihl*4;
mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
match_offset, match_len, rep_buffer, rep_len);

datalen = (*pskb)->len - iph->ihl*4;
tcph->check = 0;
tcph->check = tcp_v4_check(tcph, datalen, iph->saddr, iph->daddr,
csum_partial((char *)tcph, datalen, 0));
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
tcph->check = 0;
tcph->check = tcp_v4_check(tcph, datalen,
iph->saddr, iph->daddr,
csum_partial((char *)tcph,
datalen, 0));
} else
tcph->check = nf_proto_csum_update(*pskb,
htons(oldlen) ^ 0xFFFF,
htons(datalen),
tcph->check, 1);

if (rep_len != match_len) {
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
Expand Down Expand Up @@ -221,6 +230,7 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb,
{
struct iphdr *iph;
struct udphdr *udph;
int datalen, oldlen;

/* UDP helpers might accidentally mangle the wrong packet */
iph = (*pskb)->nh.iph;
Expand All @@ -238,22 +248,32 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb,

iph = (*pskb)->nh.iph;
udph = (void *)iph + iph->ihl*4;

oldlen = (*pskb)->len - iph->ihl*4;
mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph),
match_offset, match_len, rep_buffer, rep_len);

/* update the length of the UDP packet */
udph->len = htons((*pskb)->len - iph->ihl*4);
datalen = (*pskb)->len - iph->ihl*4;
udph->len = htons(datalen);

/* fix udp checksum if udp checksum was previously calculated */
if (udph->check) {
int datalen = (*pskb)->len - iph->ihl * 4;
if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL)
return 1;

if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
udph->check = 0;
udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, IPPROTO_UDP,
csum_partial((char *)udph,
datalen, 0));
}

if (!udph->check)
udph->check = -1;
} else
udph->check = nf_proto_csum_update(*pskb,
htons(oldlen) ^ 0xFFFF,
htons(datalen),
udph->check, 1);
return 1;
}
EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
Expand Down Expand Up @@ -293,11 +313,14 @@ sack_adjust(struct sk_buff *skb,
ntohl(sack->start_seq), new_start_seq,
ntohl(sack->end_seq), new_end_seq);

tcph->check =
ip_nat_cheat_check(~sack->start_seq, new_start_seq,
ip_nat_cheat_check(~sack->end_seq,
new_end_seq,
tcph->check));
tcph->check = nf_proto_csum_update(skb,
~sack->start_seq,
new_start_seq,
tcph->check, 0);
tcph->check = nf_proto_csum_update(skb,
~sack->end_seq,
new_end_seq,
tcph->check, 0);
sack->start_seq = new_start_seq;
sack->end_seq = new_end_seq;
sackoff += sizeof(*sack);
Expand Down Expand Up @@ -381,10 +404,10 @@ ip_nat_seq_adjust(struct sk_buff **pskb,
newack = ntohl(tcph->ack_seq) - other_way->offset_before;
newack = htonl(newack);

tcph->check = ip_nat_cheat_check(~tcph->seq, newseq,
ip_nat_cheat_check(~tcph->ack_seq,
newack,
tcph->check));
tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq,
tcph->check, 0);
tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack,
tcph->check, 0);

DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n",
ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
Expand Down
5 changes: 3 additions & 2 deletions trunk/net/ipv4/netfilter/ip_nat_proto_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ gre_manip_pkt(struct sk_buff **pskb,
if (greh->csum) {
/* FIXME: Never tested this code... */
*(gre_csum(greh)) =
ip_nat_cheat_check(~*(gre_key(greh)),
nf_proto_csum_update(*pskb,
~*(gre_key(greh)),
tuple->dst.u.gre.key,
*(gre_csum(greh)));
*(gre_csum(greh)), 0);
}
*(gre_key(greh)) = tuple->dst.u.gre.key;
break;
Expand Down
8 changes: 4 additions & 4 deletions trunk/net/ipv4/netfilter/ip_nat_proto_icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ icmp_manip_pkt(struct sk_buff **pskb,
return 0;

hdr = (struct icmphdr *)((*pskb)->data + hdroff);

hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ 0xFFFF,
tuple->src.u.icmp.id,
hdr->checksum);
hdr->checksum = nf_proto_csum_update(*pskb,
hdr->un.echo.id ^ 0xFFFF,
tuple->src.u.icmp.id,
hdr->checksum, 0);
hdr->un.echo.id = tuple->src.u.icmp.id;
return 1;
}
Expand Down
7 changes: 3 additions & 4 deletions trunk/net/ipv4/netfilter/ip_nat_proto_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,9 @@ tcp_manip_pkt(struct sk_buff **pskb,
if (hdrsize < sizeof(*hdr))
return 1;

hdr->check = ip_nat_cheat_check(~oldip, newip,
ip_nat_cheat_check(oldport ^ 0xFFFF,
newport,
hdr->check));
hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1);
hdr->check = nf_proto_csum_update(*pskb, oldport ^ 0xFFFF, newport,
hdr->check, 0);
return 1;
}

Expand Down
15 changes: 10 additions & 5 deletions trunk/net/ipv4/netfilter/ip_nat_proto_udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,16 @@ udp_manip_pkt(struct sk_buff **pskb,
newport = tuple->dst.u.udp.port;
portptr = &hdr->dest;
}
if (hdr->check) /* 0 is a special case meaning no checksum */
hdr->check = ip_nat_cheat_check(~oldip, newip,
ip_nat_cheat_check(*portptr ^ 0xFFFF,
newport,
hdr->check));

if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip,
hdr->check, 1);
hdr->check = nf_proto_csum_update(*pskb,
*portptr ^ 0xFFFF, newport,
hdr->check, 0);
if (!hdr->check)
hdr->check = -1;
}
*portptr = newport;
return 1;
}
Expand Down
10 changes: 2 additions & 8 deletions trunk/net/ipv4/netfilter/ip_nat_standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,6 @@ ip_nat_fn(unsigned int hooknum,
IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
& htons(IP_MF|IP_OFFSET)));

/* If we had a hardware checksum before, it's now invalid */
if ((*pskb)->ip_summed == CHECKSUM_PARTIAL ||
(*pskb)->ip_summed == CHECKSUM_COMPLETE)
if (skb_checksum_help(*pskb))
return NF_DROP;

ct = ip_conntrack_get(*pskb, &ctinfo);
/* Can't track? It's not due to stress, or conntrack would
have dropped it. Hence it's the user's responsibilty to
Expand Down Expand Up @@ -146,8 +140,8 @@ ip_nat_fn(unsigned int hooknum,
case IP_CT_RELATED:
case IP_CT_RELATED+IP_CT_IS_REPLY:
if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
if (!ip_nat_icmp_reply_translation(pskb, ct, maniptype,
CTINFO2DIR(ctinfo)))
if (!ip_nat_icmp_reply_translation(ct, ctinfo,
hooknum, pskb))
return NF_DROP;
else
return NF_ACCEPT;
Expand Down
19 changes: 6 additions & 13 deletions trunk/net/ipv4/netfilter/ipt_ECN.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static inline int
set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
{
struct tcphdr _tcph, *tcph;
u_int16_t diffs[2];
u_int16_t oldval;

/* Not enought header? */
tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
Expand All @@ -70,23 +70,16 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
return 0;
tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4;

if (((*pskb)->ip_summed == CHECKSUM_PARTIAL ||
(*pskb)->ip_summed == CHECKSUM_COMPLETE) &&
skb_checksum_help(*pskb))
return 0;

diffs[0] = ((u_int16_t *)tcph)[6];
oldval = ((u_int16_t *)tcph)[6];
if (einfo->operation & IPT_ECN_OP_SET_ECE)
tcph->ece = einfo->proto.tcp.ece;
if (einfo->operation & IPT_ECN_OP_SET_CWR)
tcph->cwr = einfo->proto.tcp.cwr;
diffs[1] = ((u_int16_t *)tcph)[6];
diffs[0] = diffs[0] ^ 0xFFFF;

if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY)
tcph->check = csum_fold(csum_partial((char *)diffs,
sizeof(diffs),
tcph->check^0xFFFF));
tcph->check = nf_proto_csum_update((*pskb),
oldval ^ 0xFFFF,
((u_int16_t *)tcph)[6],
tcph->check, 0);
return 1;
}

Expand Down
1 change: 1 addition & 0 deletions trunk/net/ipv4/netfilter/ipt_REJECT.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
tcph->urg_ptr = 0;

/* Adjust TCP checksum */
nskb->ip_summed = CHECKSUM_NONE;
tcph->check = 0;
tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
nskb->nh.iph->saddr,
Expand Down
Loading

0 comments on commit 43d33c6

Please sign in to comment.