我是 Android 内核空间编程的初学者。在我的模块中,内核和用户空间模块通过 netlink 套接字成功通信,并且 netfilter 钩子也可以工作。但是当我通过 netlink 套接字向用户空间模块发送 netfilter 消息时,它有一个大错误!Netlink 通过 socket 传输消息,但是 netfilter 再次钩住传输,所以它有一个循环,永远不会结束!我该如何解决这个问题,或者如何忽略 netlink 套接字并连接另一个网络套接字?内核版本是android-goldfish 3.4。(我的英文不好,希望清楚明白。谢谢!)
内核模块:
#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!");
}
用户空间程序:
#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;
}