OpenWrt kernel module development - ip address filtering through linux netfilter framework

ip_filter

Function introduction

Register the hook function to the netfilter framework through the kernel module, analyze the ip header information, extract the source ip and destination ip, and filter after matching to the specified ip address.

network layer

The network layer introduces the IP protocol and formulates a set of new addresses, so that we can distinguish whether the two hosts belong to the same network. This set of addresses is the network address, that is, the so-called IP address. IP protocol divides the 32-bit address into two parts. The front part represents the network address and the back part represents the address of the host in the LAN. If two IP addresses are in the same subnet, the network address must be the same. In order to judge the network address in the IP address, the IP protocol also introduces the subnet mask. The IP address and subnet mask can get the network address through bitwise sum operation.

Generally speaking, the network layer uses the ip address as the unique identifier for data forwarding, and the ip address can uniquely identify a host. Therefore, if we filter the ip address of the LAN, we can limit the Internet access of a device, and if we filter the ip address of the public network, we can limit the access of all devices to specific resources.

netfilter register hook function

Here we set hooknum to NF_INET_FORWARD

static struct nf_hook_ops ip_filter_ops[] __read_mostly = {
    {
        .hook = ip_filter_hook,
        .pf = PF_INET,
        .hooknum = NF_INET_FORWARD,
        .priority = NF_IP_PRI_FIRST + 1,
    },
};

static int __init ip_filter_init(void)
{
    printk("ip filter...init\n");
    nf_register_net_hooks(&init_net, ip_filter_ops, ARRAY_SIZE(ip_filter_ops));
    return 0;
}

Analysis of ip filter hook function

Source code

static u_int32_t ip_filter_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
    struct nf_conn *ct = (struct nf_conn *)skb->_nfct;
    struct udphdr *udph = NULL;
    struct iphdr *iph = NULL;
    int i;
    char *black_ip_list[] = {
        "192.168.66.167",
        "8.8.8.8",
        "114.114.114.114",
        NULL
    };

    if (ct == NULL || !nf_ct_is_confirmed(ct))
    {
        return NF_ACCEPT;
    }

    iph = ip_hdr(skb);
    if (!iph)
        return NF_ACCEPT;
    char src_ip[32] = {0};
    char dst_ip[32] = {0};
    sprintf(src_ip, "%pI4", &iph->saddr);
    sprintf(dst_ip, "%pI4", &iph->daddr);
    printk("src_ip = %s, dst_ip = %s\n", src_ip, dst_ip);
    for (i = 0; black_ip_list[i] != NULL; i++)
    {
        if (0 == strcmp(src_ip, black_ip_list[i]) ||
            0 == strcmp(dst_ip, black_ip_list[i]))
        {
            printk("drop ippacket %pI4--->%pI4\n", &iph->saddr, &iph->daddr);
            return NF_DROP;
        }
    }

    return NF_ACCEPT;
}

analysis
The source ip and destination ip of the ip header are extracted from the source code, and the configured filter ip list is queried. If the matching is successful, NF will be returned_ Drop handles packet loss.

Compile run

Refer to the previous section

test result

root@OpenWrt:/fros# 
root@OpenWrt:/fros# insmod ip_filter.ko 
root@OpenWrt:/fros# <4>[52786.030458] ip filter...init
<4>[52797.584631] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52797.589199] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52798.585038] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52798.588543] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52799.585729] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52799.588981] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52800.586586] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52800.590504] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52816.371851] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52816.376783] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52817.373089] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52817.378449] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52818.373501] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52818.379103] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52819.374765] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52819.376784] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52820.376567] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52820.380384] drop ippacket 192.168.66.167--->39.156.69.79

Introduction to the author

Author of OpenWrt application filtering plug-in (application filtering is used to control app networking, and can filter hundreds of apps such as games, videos and chat)
Engaged in embedded Linux development for nearly 10 years, mainly responsible for the research and development of router Netcom products, proficient in OpenWrt system, including luci, message mechanism, kernel module, etc. Good at modules: router Internet behavior management, intelligent flow control, Internet authentication, firewall, virtual server, multi wan load balancing, etc

Open source work address:
https://github.com/destan19/OpenAppFilter

Source code and documentation

Focus on WeChat official account for more technical documents, firmware, source code, etc.
Wechat code scanning concerns:

Keywords: Linux openwrt

Added by webdata on Mon, 17 Jan 2022 12:12:57 +0200