Hello all. I am developing interface filter NKE, which should swallow TCP and UDP packet from one interface, change ethernet header, source or destinaiton address and reinject packet to another interface. Currently, I am able to move packets from en0 to en1 on dual-network card Mac Pro, en1 is attached to another mac with Internet sharing, so I can tcpdump on the "bridge0" to see packets flaw.
I do have problems with using KPI function mbuf_inet_cksum for TCP packets. Assuming I do have an mbuf_t with Ethernet header, i was able to compute checksum for IP header using the following code:
u_int16_t ip_sum = 0; u_int16_t tsum = 0; struct tcphdr* tcp; struct udphdr* udp;
unsigned char *ptr = (unsigned char*)mbuf_data(data); ptr += ETHER_HDR_LEN;
struct ip *ip = (struct ip*)ptr; if (ip->ip_v != 4) return;
ip->ip_sum = 0; mbuf_inet_cksum(data, 0, ETHER_HDR_LEN, ip->ip_hl << 2, &ip_sum); ip->ip_sum = ip_sum;
This gives me valid IP header checksum. But when i try to use this function for TCP part:
tcp = (struct tcphdr*)(ptr + (ip->ip_hl << 2)); tcp->th_sum = 0; uint32_t offset = (ETHER_HDR_LEN + (ip->ip_hl << 2)); uint32_t len = ntohs(ip->ip_len) - (ip->ip_hl << 2);
mbuf_inet_cksum(data, IPPROTO_TCP, offset, len, &tsum);
tcp->th_sum = tsum;
the resulting checksum is invalid. I was used to calculate checksum "manually", by using 3rd party function and mbuf_copydate packet into flat buffer, but I would prefer to avoid unnecessary copy. Checking the sources of 10.8.3 kernel I had found the following: mbuf_inet_cksum actually calls inet_cksum, passing all but last parameters to it. Inside the latter, some code which is suppose have bug:
/* include pseudo header checksum? */ if (nxt != 0) { struct ip *iph;
if (m->m_len < sizeof (struct ip)) panic("inet_cksum: bad mbuf chain");
iph = mtod(m, struct ip *); sum = in_pseudo(iph->ip_src.s_addr, iph->ip_dst.s_addr, htonl(len + nxt)); }
in_pseudo call seems to misuse the last 32-bit value, shouldn't it be sometime like htonl(len + (nxt<<16)) ? -- Sincerely, Rustam Muginov
|