1

我是 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;
}
4

0 回答 0