From: Prasanna S Panchamukhi This patch provides network packet tracing feature using kernel space probes mechanism, which is efficient for dynamic tracing. Network packet traceing allows you to see the network packets while moving up and down the stack. To trace the network packets based on source and target ports, insert the module with source and target ports: insmod netpktlog.ko netpktlog=@62333,254 To trace the network packets based on only source port, insert module with source port: insmod netpktlog.ko netpktlog=@62333, To trace network packets based on target port, insert module with target port: insmod netpktlog.ko netpktlog=@,254 Signed-off-by: Andrew Morton --- 25-akpm/drivers/net/Kconfig | 12 25-akpm/drivers/net/Makefile | 3 25-akpm/drivers/net/netpktlog.c | 672 +++++++++++++++++++++++++ 25-akpm/include/linux/netfilter_ipv4/ipt_LOG.h | 2 25-akpm/kernel/kallsyms.c | 1 25-akpm/net/ipv4/netfilter/ipt_LOG.c | 3 6 files changed, 692 insertions(+), 1 deletion(-) diff -puN drivers/net/Kconfig~network-packet-tracer-module-using-kprobes-interface drivers/net/Kconfig --- 25/drivers/net/Kconfig~network-packet-tracer-module-using-kprobes-interface 2004-08-25 19:18:54.813917680 -0700 +++ 25-akpm/drivers/net/Kconfig 2004-08-25 19:18:54.825915856 -0700 @@ -2655,3 +2655,15 @@ config NETCONSOLE If you want to log kernel messages over the network, enable this. See Documentation/networking/netconsole.txt for details. +config NETPKTLOG + tristate "Network packet Tracer using kernel probes(EXPERIMENTAL)" + depends on KPROBES && IP_NF_TARGET_LOG + ---help--- + Network packet tracing is achived using kernel probes allowing you + to see the network packets while moving up and down the stack. This + module uses kprobes mechanism which is highly efficient for dynamic + tracing. + + See driver/net/netpktlog.c for details. + To compile this driver as a module, choose M.If unsure, say N. + diff -puN drivers/net/Makefile~network-packet-tracer-module-using-kprobes-interface drivers/net/Makefile --- 25/drivers/net/Makefile~network-packet-tracer-module-using-kprobes-interface 2004-08-25 19:18:54.814917528 -0700 +++ 25-akpm/drivers/net/Makefile 2004-08-25 19:18:54.826915704 -0700 @@ -196,3 +196,6 @@ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_NETCONSOLE) += netconsole.o +ifeq ($(CONFIG_NETPKTLOG),y) + obj-m += netpktlog.o +endif diff -puN /dev/null drivers/net/netpktlog.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/net/netpktlog.c 2004-08-25 19:18:54.829915248 -0700 @@ -0,0 +1,672 @@ +/* + * Network Packet Tracer using Kernel Probes (KProbes) + * net/driver/netpktlog.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2004 + * + * 2004-Aug Created by Prasanna S Panchamukhi + * for network packet tracing using kernel probes interface. + * Suggested by Andi Kleen. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned short source_port, target_port; +module_param(source_port, ushort, S_IRUSR | S_IWUSR); +module_param(target_port, ushort, S_IRUSR | S_IWUSR); + +void dump_packet_hdr(const struct ipt_log_info *info, struct sk_buff *skb) +{ + struct iphdr iph; + + if (memcpy(&iph, skb->nh.iph, sizeof(iph)) < 0) { + printk("TRUNCATED"); + return; + } + + /* Important fields: + * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ + /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ + printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ", + NIPQUAD(iph.saddr), NIPQUAD(iph.daddr)); + + /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ + printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", + ntohs(iph.tot_len), iph.tos & IPTOS_TOS_MASK, + iph.tos & IPTOS_PREC_MASK, iph.ttl, ntohs(iph.id)); + + /* Max length: 6 "CE DF MF " */ + if (ntohs(iph.frag_off) & IP_CE) + printk("CE "); + if (ntohs(iph.frag_off) & IP_DF) + printk("DF "); + if (ntohs(iph.frag_off) & IP_MF) + printk("MF "); + + /* Max length: 11 "FRAG:65535 " */ + if (ntohs(iph.frag_off) & IP_OFFSET) + printk("FRAG:%u ", ntohs(iph.frag_off) & IP_OFFSET); + + if ((info->logflags & IPT_LOG_IPOPT) + && iph.ihl * 4 > sizeof(struct iphdr)) { + unsigned char opt[4 * 15 - sizeof(struct iphdr)]; + unsigned int i, optsize; + + optsize = iph.ihl * 4 - sizeof(struct iphdr); + if (memcpy(opt, skb->nh.iph + sizeof(iph), optsize) < 0) { + printk("TRUNCATED"); + return; + } + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ + printk("OPT ("); + for (i = 0; i < optsize; i++) + printk("%02X", opt[i]); + printk(") "); + } + + switch (iph.protocol) { + case IPPROTO_TCP:{ + struct tcphdr tcph; + + /* Max length: 10 "PROTO=TCP " */ + printk("PROTO=TCP "); + + if (ntohs(iph.frag_off) & IP_OFFSET) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + if (memcpy(&tcph, skb->h.th, sizeof(tcph)) + < 0) { + printk("INCOMPLETE [%u bytes] ", iph.ihl * 4); + break; + } + + /* Max length: 20 "SPT=65535 DPT=65535 " */ + printk("SPT=%u DPT=%u ", + ntohs(tcph.source), ntohs(tcph.dest)); + /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ + if (info->logflags & IPT_LOG_TCPSEQ) + printk("SEQ=%u ACK=%u ", + ntohl(tcph.seq), ntohl(tcph.ack_seq)); + /* Max length: 13 "WINDOW=65535 " */ + printk("WINDOW=%u ", ntohs(tcph.window)); + /* Max length: 9 "RES=0x3F " */ + printk("RES=0x%02x ", + (u8) (ntohl + (tcp_flag_word(&tcph) & TCP_RESERVED_BITS) + >> 22)); + /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ + if (tcph.cwr) + printk("CWR "); + if (tcph.ece) + printk("ECE "); + if (tcph.urg) + printk("URG "); + if (tcph.ack) + printk("ACK "); + if (tcph.psh) + printk("PSH "); + if (tcph.rst) + printk("RST "); + if (tcph.syn) + printk("SYN "); + if (tcph.fin) + printk("FIN "); + /* Max length: 11 "URGP=65535 " */ + printk("URGP=%u ", ntohs(tcph.urg_ptr)); + + if ((info->logflags & IPT_LOG_TCPOPT) + && tcph.doff * 4 > sizeof(struct tcphdr)) { + unsigned char opt[4 * 15 - + sizeof(struct tcphdr)]; + unsigned int i, optsize; + + optsize = tcph.doff * 4 - sizeof(struct tcphdr); + if (memcpy(opt, skb->h.th + sizeof(tcph), + optsize) < 0) { + printk("TRUNCATED"); + return; + } + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ + printk("OPT ("); + for (i = 0; i < optsize; i++) + printk("%02X", opt[i]); + printk(") "); + } + break; + } + case IPPROTO_UDP:{ + struct udphdr udph; + + /* Max length: 10 "PROTO=UDP " */ + printk("PROTO=UDP "); + + if (ntohs(iph.frag_off) & IP_OFFSET) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + if (memcpy(&udph, skb->h.uh, sizeof(udph)) + < 0) { + printk("INCOMPLETE [%u bytes] ", iph.ihl * 4); + break; + } + + /* Max length: 20 "SPT=65535 DPT=65535 " */ + printk("SPT=%u DPT=%u LEN=%u ", + ntohs(udph.source), ntohs(udph.dest), + ntohs(udph.len)); + break; + } + case IPPROTO_ICMP:{ + struct icmphdr icmph; + /* Max length: 11 "PROTO=ICMP " */ + printk("PROTO=ICMP "); + + if (ntohs(iph.frag_off) & IP_OFFSET) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + if (memcpy(&icmph, skb->h.icmph, sizeof(icmph)) + < 0) { + printk("INCOMPLETE [bytes] "); + break; + } + + /* Max length: 18 "TYPE=255 CODE=255 " */ + printk("TYPE=%u CODE=%u ", icmph.type, icmph.code); + + switch (icmph.type) { + case ICMP_ECHOREPLY: + case ICMP_ECHO: + /* Max length: 19 "ID=65535 SEQ=65535 " */ + printk("ID=%u SEQ=%u ", + ntohs(icmph.un.echo.id), + ntohs(icmph.un.echo.sequence)); + break; + + case ICMP_PARAMETERPROB: + /* Max length: 14 "PARAMETER=255 " */ + printk("PARAMETER=%u ", + ntohl(icmph.un.gateway) >> 24); + break; + case ICMP_REDIRECT: + /* Max length: 24 "GATEWAY=255.255.255.255 " */ + printk("GATEWAY=%u.%u.%u.%u ", + NIPQUAD(icmph.un.gateway)); + /* Fall through */ + case ICMP_DEST_UNREACH: + case ICMP_SOURCE_QUENCH: + case ICMP_TIME_EXCEEDED: + /* Max length: 10 "MTU=65535 " */ + if (icmph.type == ICMP_DEST_UNREACH + && icmph.code == ICMP_FRAG_NEEDED) + printk("MTU=%u ", + ntohs(icmph.un.frag.mtu)); + } + break; + } + /* Max Length */ + case IPPROTO_AH:{ + struct ip_auth_hdr ah; + + if (ntohs(iph.frag_off) & IP_OFFSET) + break; + + /* Max length: 9 "PROTO=AH " */ + printk("PROTO=AH "); + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + if (memcpy + (&ah, skb->h.icmph + sizeof(struct icmphdr), + sizeof(ah)) < 0) { + printk("INCOMPLETE [bytes] "); + break; + } + + /* Length: 15 "SPI=0xF1234567 " */ + printk("SPI=0x%x ", ntohl(ah.spi)); + break; + } + case IPPROTO_ESP:{ + struct ip_esp_hdr esph; + + /* Max length: 10 "PROTO=ESP " */ + printk("PROTO=ESP "); + + if (ntohs(iph.frag_off) & IP_OFFSET) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + if (memcpy + (&esph, skb->h.icmph + sizeof(struct icmphdr), + sizeof(esph)) + < 0) { + printk("INCOMPLETE [bytes] "); + break; + } + + /* Length: 15 "SPI=0xF1234567 " */ + printk("SPI=0x%x ", ntohl(esph.spi)); + break; + } + /* Max length: 10 "PROTO 255 " */ + default: + printk("PROTO=%u ", iph.protocol); + } + + /* Proto Max log string length */ + /* IP: 40+46+6+11+127 = 230 */ + /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ + /* UDP: 10+max(25,20) = 35 */ + /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ + /* ESP: 10+max(25)+15 = 50 */ + /* AH: 9+max(25)+15 = 49 */ + /* unknown: 10 */ + + /* (ICMP allows recursion one level deep) */ + /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ + /* maxlen = 230+ 91 + 230 + 252 = 803 */ +} + +/* + * nettrace_port: This is a generic routine that can be used to dump the + * network packet for a given source and destination port numbers. + * Network packet filtering is done based on source/target port or + * both source and target ports. + */ + +static inline int nettrace_port(unsigned short source, unsigned short dest) +{ + if (((!source_port) && (!target_port)) + || ((!source_port) && (dest == target_port)) + || ((!target_port) && (source == source_port)) + || ((source == source_port) && (dest == target_port))) + return 0; + + return 1; +} + +static void get_ports_skb(struct sk_buff *skb, unsigned short *source, + unsigned short *dest) +{ + struct iphdr *iph; + struct tcphdr *tcph; + struct udphdr *udph; + iph = (struct iphdr *)skb->data; + + switch (iph->protocol) { + case IPPROTO_TCP: + tcph = (struct tcphdr *)((unsigned long)iph + iph->ihl * 4); + *source = ntohs(tcph->source); + *dest = ntohs(tcph->dest); + break; + case IPPROTO_UDP: + udph = (struct udphdr *)((unsigned long)iph + iph->ihl * 4); + *source = ntohs(udph->source); + *dest = ntohs(udph->dest); + break; + } +} + +static void get_ports_net(struct sk_buff *skb, unsigned short *source, + unsigned short *dest) +{ + struct iphdr *iph; + struct tcphdr *tcph; + struct udphdr *udph; + + iph = (struct iphdr *)skb->nh.iph; + switch (iph->protocol) { + case IPPROTO_TCP: + tcph = (struct tcphdr *)skb->h.th; + *source = ntohs(tcph->source); + *dest = ntohs(tcph->dest); + break; + case IPPROTO_UDP: + udph = (struct udphdr *)skb->h.uh; + *source = ntohs(udph->source); + *dest = ntohs(udph->dest); + break; + } +} + +/* + * Compile the kernel with options CONFIG_KPROBES, CONFIG_NETPKTLOG, + * CONFIG_NETFILTER, CONFIG_IP_NF_IPTABLES and CONFIG_IP_NF_TARGET_LOG enabled. + * You need to specify the parameters to the netpktlog module. + * To trace the network packets based on source and target ports, insert the + * module with source and target ports. + * Example insmod netpktlog.ko source_port=35707 target_port=22 + * To trace the network packets based on only source port, insert module + * with source port. Example insmod netpktlog.ko source_port=35707 + * To trace network packets based on target port, insert module with + * target port. Example insmod netpktlog.ko target_port=22 + */ +static void jnetif_rx(struct sk_buff *skb) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + if ((skb->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)skb->data)) { + get_ports_skb(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("netif_rx: "); + dump_packet((struct ipt_log_info *)&info, skb, 0); + printk("\n"); + } + } + jprobe_return(); +} + +static void j__kfree_skb(struct sk_buff *skb) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + if ((skb->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)skb->nh.iph)) { + get_ports_net(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("__kfree_skb: "); + dump_packet_hdr((struct ipt_log_info *)&info, skb); + printk("\n"); + } + } + jprobe_return(); +} + +static int jnetif_receive_skb(struct sk_buff *skb) +{ + struct iphdr *iph; + unsigned short source, dest; + struct ipt_log_info info; + info.logflags = IPT_LOG_IPOPT; + + if ((skb->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)skb->data)) { + get_ports_skb(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("netif_receive_skb: "); + dump_packet((struct ipt_log_info *)&info, skb, 0); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +static int jip_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + if ((skb->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)skb->data)) { + get_ports_skb(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("ip_rcv: "); + dump_packet((struct ipt_log_info *)&info, skb, 0); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +static int jip_local_deliver(struct sk_buff *skb) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + if ((skb->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)skb->data)) { + get_ports_skb(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("ip_local_deliver: "); + dump_packet((struct ipt_log_info *)&info, skb, 0); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +static int jip_output(struct sk_buff **pskb) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + iph = (struct iphdr *)(*pskb)->nh.iph; + if (iph) { + get_ports_net(*pskb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("ip_output: "); + dump_packet_hdr((struct ipt_log_info *)&info, (*pskb)); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +static int jtcp_v4_rcv(struct sk_buff *skb) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + if ((skb->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)skb->nh.iph)) { + get_ports_net(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("tcp_v4_rcv: "); + dump_packet_hdr((struct ipt_log_info *)&info, skb); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +static int jtcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + if ((skb->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)skb->nh.iph)) { + get_ports_net(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("tcp_v4_do_rcv: "); + dump_packet_hdr((struct ipt_log_info *)&info, skb); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb, + struct tcphdr *th, unsigned len) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + if ((skb->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)skb->nh.iph)) { + get_ports_net(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("tcp_rcv_established: "); + dump_packet_hdr((struct ipt_log_info *)&info, skb); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +static int jskb_copy_datagram_iovec(struct sk_buff *from, int offset, + struct iovec *to, int size) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + if ((from->protocol == htons(ETH_P_IP)) + && (iph = (struct iphdr *)from->nh.iph)) { + get_ports_net(from, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("skb_copy_datagram_iovec: "); + dump_packet_hdr((struct ipt_log_info *)&info, from); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +static void jtcp_send_dupack(struct sock *sk, struct sk_buff *skb) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + iph = (struct iphdr *)skb->nh.iph; + if (iph) { + get_ports_net(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("tcp_send_dupack: "); + dump_packet_hdr((struct ipt_log_info *)&info, skb); + printk("\n"); + } + } + jprobe_return(); +} + +static int jip_forward(struct sk_buff *skb) +{ + struct iphdr *iph; + struct ipt_log_info info; + unsigned short source, dest; + info.logflags = IPT_LOG_IPOPT; + + iph = (struct iphdr *)skb->nh.iph; + if (iph) { + get_ports_net(skb, &source, &dest); + if (!nettrace_port(source, dest)) { + printk("ip_forward: "); + dump_packet_hdr((struct ipt_log_info *)&info, skb); + printk("\n"); + } + } + jprobe_return(); + return 0; +} + +struct nettrace_obj { + const char *funcname; + struct jprobe jp; +}; + +#define NTOBJ(func) \ + { .funcname = #func, .jp = { .entry = (kprobe_opcode_t*)j##func }} +static struct nettrace_obj nettrace_objs[] = { + NTOBJ(netif_rx), + NTOBJ(__kfree_skb), + NTOBJ(netif_receive_skb), + NTOBJ(ip_rcv), + NTOBJ(ip_local_deliver), + NTOBJ(ip_output), + NTOBJ(ip_forward), + NTOBJ(tcp_v4_rcv), + NTOBJ(tcp_v4_do_rcv), + NTOBJ(tcp_rcv_established), + NTOBJ(skb_copy_datagram_iovec), + NTOBJ(tcp_send_dupack) +}; + +#define MAX_NETTRACE_ROUTINE (sizeof(nettrace_objs)/sizeof(nettrace_objs[0])) + +static int init_netpktlog(void) +{ + int i; + struct nettrace_obj *nt; + + /* first time invokation to initialize probe handler */ + /* now we are all set to register the probe */ + for (i = 0, nt = nettrace_objs; i < MAX_NETTRACE_ROUTINE; i++, nt++) { + nt = &nettrace_objs[i]; + nt->jp.kp.addr = (kprobe_opcode_t *) + kallsyms_lookup_name(nt->funcname); + if (nt->jp.kp.addr) { + printk("plant jprobe at %s (%p), handler addr %p\n", + nt->funcname, nt->jp.kp.addr, nt->jp.entry); + register_jprobe(&nt->jp); + } else { + printk("couldn't find %s to plant jprobe\n", + nt->funcname); + } + } + + printk("Network packets tracing is enabled...\n"); + return 0; +} + +static void cleanup_netpktlog(void) +{ + int i; + for (i = 0; i < MAX_NETTRACE_ROUTINE; i++) { + if (nettrace_objs[i].jp.kp.addr) + unregister_jprobe(&nettrace_objs[i].jp); + } + printk("Network packets tracing is disabled...\n"); +} + +module_init(init_netpktlog); +module_exit(cleanup_netpktlog); +MODULE_LICENSE("GPL"); diff -puN include/linux/netfilter_ipv4/ipt_LOG.h~network-packet-tracer-module-using-kprobes-interface include/linux/netfilter_ipv4/ipt_LOG.h --- 25/include/linux/netfilter_ipv4/ipt_LOG.h~network-packet-tracer-module-using-kprobes-interface 2004-08-25 19:18:54.816917224 -0700 +++ 25-akpm/include/linux/netfilter_ipv4/ipt_LOG.h 2004-08-25 19:18:54.830915096 -0700 @@ -11,5 +11,7 @@ struct ipt_log_info { unsigned char logflags; char prefix[30]; }; +void dump_packet(const struct ipt_log_info *info, const struct sk_buff *skb, + unsigned int iphoff); #endif /*_IPT_LOG_H*/ diff -puN kernel/kallsyms.c~network-packet-tracer-module-using-kprobes-interface kernel/kallsyms.c --- 25/kernel/kallsyms.c~network-packet-tracer-module-using-kprobes-interface 2004-08-25 19:18:54.817917072 -0700 +++ 25-akpm/kernel/kallsyms.c 2004-08-25 19:18:54.830915096 -0700 @@ -310,3 +310,4 @@ int __init kallsyms_init(void) __initcall(kallsyms_init); EXPORT_SYMBOL(__print_symbol); +EXPORT_SYMBOL(kallsyms_lookup_name); diff -puN net/ipv4/netfilter/ipt_LOG.c~network-packet-tracer-module-using-kprobes-interface net/ipv4/netfilter/ipt_LOG.c --- 25/net/ipv4/netfilter/ipt_LOG.c~network-packet-tracer-module-using-kprobes-interface 2004-08-25 19:18:54.819916768 -0700 +++ 25-akpm/net/ipv4/netfilter/ipt_LOG.c 2004-08-25 19:18:54.831914944 -0700 @@ -41,7 +41,7 @@ MODULE_PARM_DESC(nflog, "register as int static spinlock_t log_lock = SPIN_LOCK_UNLOCKED; /* One level of recursion won't kill us */ -static void dump_packet(const struct ipt_log_info *info, +void dump_packet(const struct ipt_log_info *info, const struct sk_buff *skb, unsigned int iphoff) { @@ -473,5 +473,6 @@ static void __exit fini(void) ipt_unregister_target(&ipt_log_reg); } +EXPORT_SYMBOL_GPL(dump_packet); module_init(init); module_exit(fini); _