I am a beginner in Android kernel space programming. In my modules, kernel and user space module are successfully communicating via netlink sockets and netfilter hook also works. But when I send netfilter message to user space module via netlink socket, it has a big bug! Netlink transmits message via socket, but the netfilter hook the transmission again, so it has a loop and never ends! How can I solve the problem or how to just ignore the netlink sockets and hook the other network socket? The kernel version is android-goldfish 3.4.(My English is not good, hope it clear to understand. Thanks!)
the kernel module:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/unistd.h>
#include <linux/kthread.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#define MY_GROUP 1
#define MAX_SIZE 1024
struct task_struct *mythread = NULL;
struct sock *nl_sk = NULL;
static void nl_receive_callback (struct sk_buff *skb)
{
nlmsg_free(skb);
}
static void kernel_send_nl_msg(const char *msg)
{
struct nlmsghdr *nlsk_mh;
struct sk_buff *socket_buff;
socket_buff = nlmsg_new(MAX_SIZE, GFP_KERNEL);
nlsk_mh = nlmsg_put(socket_buff, 0, 0, NLMSG_DONE, MAX_SIZE, 0);
NETLINK_CB(socket_buff).pid = 0;
NETLINK_CB(socket_buff).dst_group = MY_GROUP;
strcpy(nlmsg_data(nlsk_mh), msg);
nlmsg_multicast(nl_sk, socket_buff, 0, MY_GROUP, GFP_KERNEL);
return;
}
unsigned int nfhook(
unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
char inetmsg[128] = {0};
__be32 sip, dip;
if (skb)
{
iph = ip_hdr(skb);
sip = iph->saddr;
dip = iph->daddr;
snprintf(inetmsg, 128,
"{'netObject':[{'saddr':'%d.%d.%d.%d:%u', 'daddr':'%d.%d.%d.%d:%u', 'protocol':'%x'}]}\n",
NIPQUAD(sip), NIPQUAD(dip), iph->protocol);
kernel_send_nl_msg(strim(inetmsg));
printk("%s\n", inetmsg);
}
return NF_ACCEPT;
}
struct nf_hook_ops out_nfho = {
.list = {NULL, NULL},
.hook = nfhook,
.hooknum = NF_INET_POST_ROUTING,
.pf = PF_INET,
.priority = NF_IP_PRI_FIRST,
};
int init_module(void)
{
nl_sk = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0, nl_receive_callback, NULL, THIS_MODULE);
if(!nl_sk)
{
printk(KERN_ERR "my_net_link: create netlink socket error.\n");
return 1;
}
mythread = kthread_run(kernel_send_nl_msg, "init", "network-monitor");
printk("Module Ready!");
nf_register_hook(&out_nfho);
return 0;
}
void cleanup_module(void)
{
if(nl_sk != NULL)
{
sock_release(nl_sk->sk_socket);
}
nf_unregister_hook(&out_nfho);
printk("Remove Module!");
}
Userspace program:
#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdio.h>
#include <errno.h>
#include <cutils/log.h>
#define MY_GROUP 1
#define MAX_SIZE 1024
#define LOG_TAG "APP LOG TAG"
int main(int argc, char* argv[])
{
int sock_fd, retval;
struct sockaddr_nl user_sockaddr;
struct nlmsghdr *nl_msghdr;
struct msghdr msghdr;
struct iovec iov;
char kernel_msg[256] = {0};
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
if (sock_fd == -1)
{
sprintf(kernel_msg, "error getting socket: %s", strerror(errno));
LOGV(strerror(kernel_msg));
printf("error getting socket: %s", strerror(errno));
return -1;
}
memset(&user_sockaddr, 0, sizeof(user_sockaddr));
user_sockaddr.nl_family = PF_NETLINK;
user_sockaddr.nl_pid = getpid();
user_sockaddr.nl_groups = MY_GROUP;
retval = bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
if(retval < 0)
{
sprintf(kernel_msg, "bind failed: %s", strerror(errno));
LOGV(strerror(kernel_msg));
printf("bind failed: %s", strerror(errno));
close(sock_fd);
return -1;
}
while (1)
{
nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(MAX_SIZE));
if(!nl_msghdr)
{
LOGV(strerror("malloc nlmsghdr error!\n"));
printf("malloc nlmsghdr error!\n");
close(sock_fd);
return -1;
}
memset(nl_msghdr, 0, NLMSG_SPACE(MAX_SIZE));
iov.iov_base = (void*) nl_msghdr;
iov.iov_len = NLMSG_SPACE(MAX_SIZE);
memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
recvmsg(sock_fd, &msghdr, 0);
LOGV(NLMSG_DATA(nl_msghdr));
printf("%s\n", NLMSG_DATA(nl_msghdr));
}
close(sock_fd);
return 0;
}