2

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;
}
Vergil
  • 21
  • 4

0 Answers0