Skip to content

Commit

Permalink
fix cksum mismatch
Browse files Browse the repository at this point in the history
  • Loading branch information
张弘引 committed Dec 5, 2015
1 parent 84135b1 commit bc0c26a
Showing 1 changed file with 37 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/nat.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,34 @@ typedef struct {
} \
}

#define FIX_CHECKSUM(iphdr, fcc) { \
short sum = 0; \
int32_t verify = 0; \
verify = (iphdr->ver<<8)+ \
iphdr->tos+ \
htons(iphdr->total_len)+ \
htons(iphdr->id)+ \
htons(iphdr->frag)+ \
(iphdr->ttl<<8)+ \
iphdr->proto+ \
htons(iphdr->checksum)+ \
htons((iphdr->saddr>>16) & 0xffff)+ \
htons(iphdr->saddr & 0xffff)+ \
htons((iphdr->daddr>>16) & 0xffff)+ \
htons(iphdr->daddr & 0xffff); \
verify = (verify>>16) + (verify&0xffff); \
sum = ntohs(verify); \
logf("cksum verify:0x%x, checksum:%x", verify, sum); \
if(sum == -1){ \
fcc = 0; \
} else { \
fcc = sum<-1 ? -sum-1 : -sum; \
if(fcc == 1 || fcc == -1){ \
iphdr->checksum += fcc; \
} \
} \
}

int nat_fix_upstream(nat_ctx_t *ctx, unsigned char *buf, size_t buflen,
const struct sockaddr *addr, socklen_t addrlen) {
uint8_t iphdr_len;
Expand Down Expand Up @@ -169,7 +197,10 @@ int nat_fix_upstream(nat_ctx_t *ctx, unsigned char *buf, size_t buflen,

// add old, sub new
acc = client->input_tun_ip - iphdr->saddr;

short fcc = 0;
ADJUST_CHECKSUM(acc, iphdr->checksum);
FIX_CHECKSUM(iphdr, fcc);

if (0 == (iphdr->frag & htons(0x1fff))) {
// only adjust tcp & udp when frag offset == 0
Expand All @@ -181,13 +212,15 @@ int nat_fix_upstream(nat_ctx_t *ctx, unsigned char *buf, size_t buflen,
}
tcp_hdr_t *tcphdr = ip_payload;
ADJUST_CHECKSUM(acc, tcphdr->checksum);
tcphdr->checksum += fcc;
} else if (iphdr->proto == IPPROTO_UDP) {
if (buflen < iphdr_len + 8) {
errf("nat: udp packet too short");
return -1;
}
udp_hdr_t *udphdr = ip_payload;
ADJUST_CHECKSUM(acc, udphdr->checksum);
udphdr->checksum += fcc;
}
}
return 0;
Expand Down Expand Up @@ -234,7 +267,9 @@ int nat_fix_downstream(nat_ctx_t *ctx, unsigned char *buf, size_t buflen,
// overwrite IP
iphdr->daddr = client->input_tun_ip;

short fcc = 0;
ADJUST_CHECKSUM(acc, iphdr->checksum);
FIX_CHECKSUM(iphdr, fcc);

if (0 == (iphdr->frag & htons(0x1fff))) {
// only adjust tcp & udp when frag offset == 0
Expand All @@ -246,13 +281,15 @@ int nat_fix_downstream(nat_ctx_t *ctx, unsigned char *buf, size_t buflen,
}
tcp_hdr_t *tcphdr = ip_payload;
ADJUST_CHECKSUM(acc, tcphdr->checksum);
tcphdr->checksum += fcc;
} else if (iphdr->proto == IPPROTO_UDP) {
if (buflen < iphdr_len + 8) {
errf("nat: udp packet too short");
return -1;
}
udp_hdr_t *udphdr = ip_payload;
ADJUST_CHECKSUM(acc, udphdr->checksum);
udphdr->checksum += fcc;
}
}
return 0;
Expand Down

0 comments on commit bc0c26a

Please sign in to comment.