基于netfilter的简单网络防火墙demo

一、环境

操作系统:Ubuntu18.04LTS

二、代码

1、netfilter.c

//
// Created by hs on 2020/6/3.
//

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static unsigned int nf_hook_in(void *priv, struct sk_buff *skb, const struct nf_hook_state *state);
static unsigned int nf_hook_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *state);
static int nf_sockopt_set(struct sock *sk, int optval, void __user *user, unsigned int len);
static int nf_sockopt_get(struct sock *sk, int optval, void __user *user, int *len);
static int nf_register_hook(struct nf_hook_ops *reg);
static void nf_unregister_hook(struct nf_hook_ops *reg);

#define SOE_BANDIP 0X6001
#define SOE_BANDPORT 0X6002
#define SOE_BANDPING 0X6003

#define NF_SUCCESS 0
#define NF_FAILURE 1

struct nf_bandport
{
    unsigned short protocol;

    unsigned short port;
};

struct band_status
{
    unsigned int band_ip;

    struct nf_bandport band_port;

    unsigned char band_ping;
};

#define IS_BANDPORT_TCP(status) (status.band_port.protocol == IPPROTO_TCP && status.band_port.port != 0)
#define IS_BANDPORT_UDP(status) (status.band_port.protocol == IPPROTO_UDP && status.band_port.port != 0)
#define IS_BANDPING(status) (status.band_ping)
#define IS_BANDIP(status) (status.band_ip)


struct band_status b_status;
static struct nf_hook_ops nfin = {.hook = nf_hook_in, .hooknum = NF_INET_LOCAL_IN, .pf = PF_INET, .priority = NF_IP_PRI_FILTER};
static struct nf_hook_ops nfout = {.hook = nf_hook_out, .hooknum = NF_INET_LOCAL_OUT, .pf = PF_INET, .priority = NF_IP_PRI_FILTER};
static struct nf_sockopt_ops nfsockopt = {.pf = PF_INET, .set_optmin = SOE_BANDIP, .set_optmax = SOE_BANDIP+3,
        .set = nf_sockopt_set, .get_optmin = SOE_BANDIP, .get_optmax = SOE_BANDIP+3, .get = nf_sockopt_get};


static int nf_sockopt_set(struct sock *sk, int optval, void __user *user, unsigned int len)
{
    int ret = 0;
    struct band_status status;

    if(!capable(CAP_NET_ADMIN))
    {
        ret = -EPERM;
        goto ERROR;
    }

    ret = copy_from_user(&status, user, len);
    if(ret != 0)
    {
        ret = -EINVAL;
        goto ERROR;
    }

    switch (optval)
    {
        case SOE_BANDIP:
            b_status.band_ip = status.band_ip;
            break;
        case SOE_BANDPORT:
            if(IS_BANDPORT_TCP(status) || IS_BANDPORT_UDP(status))
                b_status.band_port = status.band_port;
            else
            {
                b_status.band_port.protocol = 0;
                b_status.band_port.port = 0;
            }
            break;
        case SOE_BANDPING:
            b_status.band_ping = IS_BANDPING(status) ? 1 : 0;
            break;
        default:
            ret = -EINVAL;
            break;
    }

    ERROR:
    return ret;
}

static int nf_sockopt_get(struct sock *sk, int optval, void __user *user, int *len)
{
    int ret = 0;

    if(!capable(CAP_NET_ADMIN))
    {
        ret = -EPERM;
        goto ERROR;
    }

    switch (optval)
    {
        case SOE_BANDIP:
        case SOE_BANDPORT:
        case SOE_BANDPING:
            ret = copy_to_user(user, &b_status, sizeof(b_status));
            if(ret != 0)
            {
                ret = -EINVAL;
                goto ERROR;
            }
            *len = sizeof(b_status);
            break;
        default:
            break;
    }

    ERROR:
    return ret;
}

static unsigned int nf_hook_out(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
    struct iphdr *iph = ip_hdr(skb);

    switch (iph->protocol)
    {
        case IPPROTO_ICMP:
            if(IS_BANDPING(b_status))
            {
                printk(KERN_ALERT "drop one icmp packet\n");
                return NF_DROP;
            }
            break;
        default:
            break;
    }

    return NF_ACCEPT;
}

static unsigned int nf_hook_in(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
    struct iphdr *iph = ip_hdr(skb);
    struct tcphdr *tcph = NULL;
    struct udphdr *udph = NULL;

    if(IS_BANDIP(b_status))
    {
        if(b_status.band_ip == iph->saddr)
        {
            return NF_DROP;
        }
    }

    switch(iph->protocol)
    {
        case IPPROTO_TCP:
            if(IS_BANDPORT_TCP(b_status))
            {
                tcph = tcp_hdr(skb);
                if(tcph->dest == b_status.band_port.port)
                {
                    return NF_DROP;
                }
            }
            break;
        case IPPROTO_UDP:
            if(IS_BANDPORT_UDP(b_status))
            {
                udph = udp_hdr(skb);
                if(udph->dest == b_status.band_port.port)
                {
                    return NF_DROP;
                }
            }
            break;
        default:
            break;
    }

    return NF_ACCEPT;
}

static int nf_register_hook(struct nf_hook_ops *reg)
{
    struct net *net, *last;
    int ret;

    rtnl_lock();
    for_each_net(net)
    {
        ret = nf_register_net_hook(net, reg);
        if(ret && ret != -ENOENT)
            goto rollback;
    }
    rtnl_unlock();
    return 0;

    rollback:
    last = net;
    for_each_net(net)
    {
        if(net == last)
            break;
        nf_unregister_net_hook(net, reg);
    }
    rtnl_unlock();
    return ret;
}

static void nf_unregister_hook(struct nf_hook_ops *reg)
{
    struct net *net;

    rtnl_lock();
    for_each_net(net)
    {
        nf_unregister_net_hook(net, reg);
    }
    rtnl_unlock();
}

static int __init helloworld_init(void)
{
    int ret = 0;
    ret += nf_register_hook(&nfin);
    ret += nf_register_hook(&nfout);
    ret += nf_register_sockopt(&nfsockopt);

    printk(KERN_ALERT "module init with ret: %d\n", ret);

    return ret ? NF_FAILURE : NF_SUCCESS;
}

static void __exit helloworld_exit(void)
{
    nf_unregister_hook(&nfin);
    nf_unregister_hook(&nfout);
    nf_unregister_sockopt(&nfsockopt);

    printk(KERN_ALERT "module exit");
}

module_init(helloworld_init);
module_exit(helloworld_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("HS");
MODULE_DESCRIPTION("NETFILTER DEMO");
MODULE_VERSION("0.0.1");
MODULE_ALIAS("HELLOWORLD");

2、test.c

//
// Created by hs on 2020/6/4.
//

#include 
#include 
#include 
#include 
#include 

#define SOE_BANDIP 0X6001
#define SOE_BANDPORT 0X6002
#define SOE_BANDPING 0X6003

#define NF_SUCCESS 0
#define NF_FAILURE 1

struct nf_bandport
{
    unsigned short protocol;

    unsigned short port;
};

struct band_status
{
    unsigned int band_ip;

    struct nf_bandport band_port;

    unsigned char band_ping;
};

int main()
{
    struct band_status b_status;
    b_status.band_ping = 1;
    socklen_t len = sizeof(b_status);

    int fd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
    if(fd == -1)
    {
        perror("create socket error\n");
        exit(-1);
    }

    if(setsockopt(fd, IPPROTO_IP, SOE_BANDPING, &b_status, len) == -1)
    {
        perror("set sock opt error\n");
        printf("errno: %d\n", errno);
        exit(-1);
    }

    return 0;
}

3、Makefile

target := netfilter
obj-m := $(target).o
KERNELDIR = /lib/modules/$(shell uname -r)/build

.PHONY: all install uninstall clean

all:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

install:
	insmod $(target).ko

uninstall:
	rmmod $(target).ko

clean:
	rm -rf *.o *.mod .*.cmd *.mod.c *.ko *.order
	rm -rf Module.symvers *.cmd .tmp_versions

test:test.c
	gcc -o $@ $^

你可能感兴趣的:(基于netfilter的简单网络防火墙demo)