Hi all,
I write an NKE ip filter, it works fine normally. But when I set an ipfw rule to limit the net speed. The system will always panic when I visit website.
The rule I added is:
ipfw pipe 1 config bw 512Kbit/s
ipfw add 400 pipe 1 ip from any to any
The panic log said "m_free: freeing an already freed mbuf".
I collect the panic dump and the stack shows like this:
#0 0x001b0b60 in Debugger (message=0x80010033 <Address 0x80010033 out of bounds>)
#1 0x0012b4c6 in panic (str=0x1 <Address 0x1 out of bounds>) at /SourceCache/xnu/xnu-1228.15.4/osfmk/kern/debug.c:275
#2 0x003a5b39 in m_free (m=0x1d248c00) at /SourceCache/xnu/xnu-1228.15.4/bsd/kern/uipc_mbuf.c:2741
#3 0x003a8051 in m_pullup (n=0x1d248c00, len=20) at /SourceCache/xnu/xnu-1228.15.4/bsd/kern/uipc_mbuf.c:4196
#4 0x00234a1e in divert_packet (m=0x1d24a500, incoming=0, port=8668, rule=10) at /SourceCache/xnu/xnu-1228.15.4/bsd/netinet/ip_divert.c:218
#5 0x00244cce in ip_output_list (m0=0x1d24a500, packetchain=0, opt=0x0, ro=<value temporarily unavailable, due to optimizations>, flags=256, imo=0x0, ipoa=0x3c823d0c) at /SourceCache/xnu/xnu-1228.15.4/bsd/netinet/ip_output.c:1160
#6 0x0024bcd3 in tcp_ip_output (so=0x5e0b000, tp=<value temporarily unavailable, due to optimizations>, pkt=0x1d24a500, cnt=0, opt=0x0, flags=256) at /SourceCache/xnu/xnu-1228.15.4/bsd/netinet/tcp_output.c:1701
#7 0x0024d4c2 in tcp_output (tp=0x5e0b270) at /SourceCache/xnu/xnu-1228.15.4/bsd/netinet/tcp_output.c:1523
#8 0x003aafb0 in soconnectlock (so=0x5e0b000, nam=0x3c823ed8, dolock=0) at /SourceCache/xnu/xnu-1228.15.4/bsd/kern/uipc_socket.c:1245
#9 0x003b2733 in connect_nocancel (p=0x3e59794, uap=0x58930c0, retval=0x5893104) at /SourceCache/xnu/xnu-1228.15.4/bsd/kern/uipc_syscalls.c:645
#10 0x003e3a7f in unix_syscall (state=0x4ca3680) at /SourceCache/xnu/xnu-1228.15.4/bsd/dev/i386/systemcalls.c:184
#11 0x001a1c0a in lo_unix_scall () at pmap.h:176
Cannot access memory at address 0xb02cb97c
Here is my code, I will redirect all TCP traffic to Port 80:
errno_t ip_output(void *cookie, mbuf_t *data, ipf_pktopts_t options)
{
...
//if the traffic is from browser to remote http server, change the destination ip and port to
127.0.0.1:6668 if(type == CONNTRACK_TYPE_REDIRECT)
{
org_port = p_tcp_header->th_dport;
/* change header here */
// change dest ip to 127.0.0.1
modifyDstAddress(p_ip_header, NULL);
p_tcp_header->th_dport = htons(localProxy_port);
mbuf_outbound_finalize( *data, PF_INET, 0 );
mbuf_copyback(*data, 0, payloadOffset+sizeof(struct tcphdr), p_ip_header, M_WAITOK);
if(ipf_inject_output(*data, IP_V(p_ip_header) == IPVERSION?ipfilter_ref:ipfilter_ref6, options) != 0) {
/* restore ip/tcp header and bypass */
modifyDstAddress(p_ip_header, &dst_ip);
p_tcp_header->th_dport = org_port;
mbuf_copyback(*data, 0, payloadOffset+sizeof(struct tcphdr), p_ip_header, M_NOWAIT);
return 0;
}
return EJUSTREURN;
}
//if the traffic is from local proxy (
127.0.0.1:6668) to browser, modify the source ip and port from
127.0.0.1:6668 to remote http server's ip and port, and modify the destination ip to 127.0.0.1
else if(type == CONNTRACK_TYPE_REDIRECT_REVERSE)
{
LOG(LOG_DEBUG, "ip_output, type is REDIRECT_REVERSE, reverse packet\n");
modifySrcAddress(p_ip_header, &ip);
p_tcp_header->th_sport = port;
mbuf_outbound_finalize( *data, PF_INET, 0 );
mbuf_copyback(*data, 0, payloadOffset+sizeof(struct tcphdr), p_ip_header, M_WAITOK);
return 0;
}
}
Is there any sample code or detail guideline about ip filter development? I don't know if my code fit the standard. In fact, my kext will always panic with any ipfw rule before I adding mbuf_outbound_finalize(). After I calling this function, I find that most rules will not cause OS panic, but the ones I listed still do.
I don't know if it is because my code is not fit the standard or there is other cause.
Could any one help me? Thanks!
Best Regards,
jan