1
This commit is contained in:
@@ -358,4 +358,7 @@ msg.o: /home/duck/project/linux_kernel/msg.c \
|
||||
include/uapi/linux/udp.h include/linux/inet.h include/linux/cdev.h \
|
||||
/home/duck/project/linux_kernel/some_struct.h \
|
||||
/home/duck/project/linux_kernel/global.h \
|
||||
/home/duck/project/linux_kernel/msg.h
|
||||
/home/duck/project/linux_kernel/msg.h \
|
||||
/home/duck/project/linux_kernel/ip_hashmap.h \
|
||||
/home/duck/project/linux_kernel/network.h \
|
||||
/home/duck/project/linux_kernel/client_msg.h
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CONFIG_MODULE_SIG=n
|
||||
obj-m += safe_duck.o
|
||||
safe_duck-objs := main.o msg.o global.o some_struct.o
|
||||
safe_duck-objs := main.o msg.o global.o some_struct.o ip_hashmap.o network.o client_msg.o
|
||||
PWD := $(shell pwd)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
0x8d232039 push_msg /home/duck/project/linux_kernel/safe_duck EXPORT_SYMBOL
|
||||
0x4b7cb975 get_msg /home/duck/project/linux_kernel/safe_duck EXPORT_SYMBOL
|
||||
0xe98895fa push_msg /home/duck/project/linux_kernel/safe_duck EXPORT_SYMBOL
|
||||
0xb1b3bd13 get_msg /home/duck/project/linux_kernel/safe_duck EXPORT_SYMBOL
|
||||
0xb3ceb32b get_msg_list_length /home/duck/project/linux_kernel/safe_duck EXPORT_SYMBOL
|
||||
0x38a1fb31 cleanup_msg /home/duck/project/linux_kernel/safe_duck EXPORT_SYMBOL
|
||||
0x50632040 init_msg /home/duck/project/linux_kernel/safe_duck EXPORT_SYMBOL
|
||||
|
||||
14
linux_kernel/client_msg.c
Normal file
14
linux_kernel/client_msg.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "client_msg.h"
|
||||
|
||||
void dispath_client_msg(struct client_msg_t* msg) {
|
||||
switch (msg->type) {
|
||||
case SD_MSG_TYPE_CLIENT_BLOCK_IP:
|
||||
const size_t target_ip_address = msg->u.ip_address.src_ip;
|
||||
const size_t block_time = msg->u.ip_address.block_time;
|
||||
block_ip_address(target_ip_address, block_time);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "Unknown msg type: %d\n", msg->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
3
linux_kernel/client_msg.h
Normal file
3
linux_kernel/client_msg.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
#include "head.h"
|
||||
extern void dispath_client_msg(struct client_msg_t* msg);
|
||||
@@ -20,9 +20,15 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/hash.h>
|
||||
#include "some_struct.h"
|
||||
#include "global.h"
|
||||
#include "msg.h"
|
||||
#include "ip_hashmap.h"
|
||||
#include "network.h"
|
||||
#include "client_msg.h"
|
||||
#define DEVICE_NAME "safe_duck"
|
||||
#define DEVICE_CNT 1
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
173
linux_kernel/ip_hashmap.c
Normal file
173
linux_kernel/ip_hashmap.c
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "ip_hashmap.h"
|
||||
static struct ip_hash_table g_ip_hashtable;
|
||||
|
||||
void thread_demon_ip_hashmap(void *ctx) {
|
||||
struct hlist_head *head;
|
||||
struct hlist_node *node, *tmp;
|
||||
struct ip_hashmap_node_t *data;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
msleep_interruptible(30000); // 每 30 秒执行一次清理操作
|
||||
const s64 current_time_sec = ktime_get_real_seconds();
|
||||
|
||||
spin_lock(&g_ip_hashtable.lock);
|
||||
|
||||
for (int i = 0; i < g_ip_hashtable.bucket_num; ++i) {
|
||||
head = &g_ip_hashtable.heads[i];
|
||||
hlist_for_each_safe(node, tmp, head) {
|
||||
data = container_of(node, struct ip_hashmap_node_t, node);
|
||||
if (data) {
|
||||
s64 time_diff =
|
||||
(s64)((s64)data->info.ip_meta_info.remove_time -
|
||||
(s64)data->info.ip_meta_info.last_attack_time);
|
||||
if ((data->info.ip_meta_info.is_attack == false) ||
|
||||
(time_diff <= 0)) {
|
||||
hlist_del(&data->node);
|
||||
kfree(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&g_ip_hashtable.lock);
|
||||
}
|
||||
|
||||
printk(KERN_INFO "cleanup_iphashmap thread stopped\n");
|
||||
}
|
||||
// 初始化哈希表对象
|
||||
bool init_ip_hashmap(void) {
|
||||
struct ip_hash_table *table = &g_ip_hashtable;
|
||||
table->bucket_num = BUCKET_NUM;
|
||||
table->heads = kzalloc(BUCKET_NUM * sizeof(struct hlist_head), GFP_KERNEL);
|
||||
if (table->heads) {
|
||||
for (int i = 0; i < BUCKET_NUM; ++i) {
|
||||
INIT_HLIST_HEAD(&table->heads[i]);
|
||||
}
|
||||
}
|
||||
spin_lock_init(&table->lock); // 初始化锁
|
||||
|
||||
// 新建线程,执行清理操作
|
||||
table->cleanup_thread = kthread_run((void *)thread_demon_ip_hashmap, NULL,
|
||||
"thread_demon_ip_hashmap");
|
||||
if (IS_ERR(table->cleanup_thread)) {
|
||||
printk(KERN_ERR "Failed to create cleanup thread\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查是否需要动态调整桶的数量
|
||||
void check_resize_table(struct ip_hash_table *table) {
|
||||
unsigned int bucket_num = table->bucket_num;
|
||||
int count = 0;
|
||||
for (int i = 0; i < bucket_num; ++i) {
|
||||
struct hlist_head *head = &table->heads[i];
|
||||
if (!hlist_empty(head)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((count * 100 / bucket_num) > 70) {
|
||||
table->bucket_num = 2 * bucket_num;
|
||||
struct hlist_head *new_heads =
|
||||
kzalloc(table->bucket_num * sizeof(struct hlist_head), GFP_KERNEL);
|
||||
if (new_heads) {
|
||||
for (int i = 0; i < table->bucket_num / 2; ++i) {
|
||||
struct hlist_node *node, *tmp;
|
||||
hlist_for_each_safe(node, tmp, &table->heads[i]) {
|
||||
struct ip_hashmap_node_t *data =
|
||||
container_of(node, struct ip_hashmap_node_t, node);
|
||||
hlist_del(&data->node);
|
||||
int idx =
|
||||
hash_32(data->info.ip_address_key, table->bucket_num);
|
||||
hlist_add_head(&data->node, &new_heads[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(table->heads);
|
||||
table->heads = new_heads;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取并插入哈希表节点
|
||||
void put_ipdata_by_hashmap(size_t ip_address_key,
|
||||
struct ip_hashmap_info *info) {
|
||||
struct ip_hash_table *table = &g_ip_hashtable;
|
||||
int idx = hash_32(ip_address_key, table->bucket_num);
|
||||
// 新建哈希表节点
|
||||
struct ip_hashmap_node_t *data =
|
||||
kmalloc(sizeof(struct ip_hashmap_node_t), GFP_KERNEL);
|
||||
if (data) {
|
||||
memcpy(&data->info, info, sizeof(struct ip_hashmap_info));
|
||||
spin_lock(&table->lock);
|
||||
hlist_add_head(&data->node, &table->heads[idx]);
|
||||
check_resize_table(table);
|
||||
spin_unlock(&table->lock);
|
||||
}
|
||||
}
|
||||
|
||||
// 通过关键字获取哈希表节点
|
||||
struct ip_hashmap_node_t *get_ipdata_by_hashmap(size_t ip_address_key) {
|
||||
struct ip_hash_table *table = &g_ip_hashtable;
|
||||
spin_lock(&table->lock);
|
||||
|
||||
int idx = hash_32(ip_address_key, table->bucket_num);
|
||||
struct hlist_head *head = &table->heads[idx];
|
||||
struct hlist_node *node = head->first;
|
||||
while (node) {
|
||||
struct ip_hashmap_node_t *data =
|
||||
container_of(node, struct ip_hashmap_node_t, node);
|
||||
if (ip_address_key == data->info.ip_address_key) {
|
||||
spin_unlock(&table->lock);
|
||||
return data;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
spin_unlock(&table->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 从哈希表中删除节点
|
||||
void del_ipdata_by_hashmap(size_t ip_address_key) {
|
||||
struct ip_hash_table *table = &g_ip_hashtable;
|
||||
spin_lock(&table->lock);
|
||||
|
||||
int idx = hash_32(ip_address_key, table->bucket_num);
|
||||
struct hlist_head *head = &table->heads[idx];
|
||||
struct hlist_node *node = head->first;
|
||||
while (node) {
|
||||
struct ip_hashmap_node_t *data =
|
||||
container_of(node, struct ip_hashmap_node_t, node);
|
||||
if (ip_address_key == data->info.ip_address_key) {
|
||||
hlist_del(&data->node);
|
||||
kfree(data);
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
// 检查是否需要调整桶的数量
|
||||
check_resize_table(table);
|
||||
spin_unlock(&table->lock);
|
||||
}
|
||||
void cleanup_iphashmap(void) {
|
||||
kthread_stop(g_ip_hashtable.cleanup_thread); // 停止清理线程
|
||||
if (g_ip_hashtable.heads) {
|
||||
spin_lock(&g_ip_hashtable.lock);
|
||||
struct hlist_head *head, *tmp;
|
||||
struct hlist_node *node;
|
||||
struct ip_hashmap_node_t *data;
|
||||
// 释放哈希表节点动态分配的内存
|
||||
for (int i = 0; i < g_ip_hashtable.bucket_num; ++i) {
|
||||
head = &g_ip_hashtable.heads[i];
|
||||
hlist_for_each_entry_safe(data, node, head, node) {
|
||||
hlist_del(&data->node);
|
||||
kfree(data);
|
||||
}
|
||||
}
|
||||
kfree(g_ip_hashtable.heads);
|
||||
spin_unlock(&g_ip_hashtable.lock);
|
||||
}
|
||||
|
||||
printk(KERN_INFO "clean up iphashmap\n");
|
||||
}
|
||||
41
linux_kernel/ip_hashmap.h
Normal file
41
linux_kernel/ip_hashmap.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "head.h"
|
||||
#define BUCKET_NUM 1000 // 初始桶的数量
|
||||
struct ip_hash_table {
|
||||
struct hlist_head *heads; // 存放桶的指针数组
|
||||
unsigned int bucket_num; // 当前桶的数量
|
||||
spinlock_t lock; // 锁,确保同步和互斥访问哈希表
|
||||
struct task_struct *cleanup_thread; // 执行清理操作的线程
|
||||
};
|
||||
// 定义哈希表节点
|
||||
struct syn_scan_info_t {
|
||||
size_t last_seen;
|
||||
size_t num_syn_packets;
|
||||
};
|
||||
|
||||
struct crack_ip_info_t {
|
||||
size_t last_seen;
|
||||
size_t num_connect;
|
||||
};
|
||||
struct ip_meta_info_t {
|
||||
bool is_attack;
|
||||
size_t last_attack_time;
|
||||
size_t remove_time;
|
||||
};
|
||||
struct ip_hashmap_info {
|
||||
size_t ip_address_key;
|
||||
struct syn_scan_info_t syn_scan_info;
|
||||
struct crack_ip_info_t crack_ip_info;
|
||||
struct ip_meta_info_t ip_meta_info;
|
||||
};
|
||||
struct ip_hashmap_node_t {
|
||||
struct hlist_node node; // 哈希表链表节点
|
||||
struct ip_hashmap_info info;
|
||||
};
|
||||
extern bool init_ip_hashmap(void);
|
||||
extern void check_resize_table(struct ip_hash_table *table);
|
||||
extern void put_ipdata_by_hashmap(size_t ip_address_key,
|
||||
struct ip_hashmap_info *info);
|
||||
extern struct ip_hashmap_node_t *get_ipdata_by_hashmap(size_t ip_address_key);
|
||||
extern void del_ipdata_by_hashmap(size_t ip_address_key);
|
||||
extern void cleanup_iphashmap(void);
|
||||
@@ -1,36 +1,5 @@
|
||||
#include "head.h"
|
||||
|
||||
struct safe_duck_dev {
|
||||
wait_queue_head_t read_wait;
|
||||
};
|
||||
|
||||
unsigned int network_callback(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb, const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *)) {
|
||||
do {
|
||||
if (skb == NULL) {
|
||||
break;
|
||||
}
|
||||
struct iphdr *ip_header = ip_hdr(skb);
|
||||
|
||||
if (ip_header == NULL) {
|
||||
break;
|
||||
}
|
||||
// push ip address to list
|
||||
struct kernel_msg_t *msg =
|
||||
kmalloc(sizeof(struct kernel_msg_t), GFP_KERNEL);
|
||||
if (msg == NULL) {
|
||||
printk(KERN_ERR "Failed to allocate memory for new msg\n");
|
||||
break;
|
||||
}
|
||||
msg->type = SD_MSG_TYPE_NEW_IP_CONNECT;
|
||||
msg->u.poll_req.src_ip = ip_header->saddr;
|
||||
push_msg(msg);
|
||||
} while (false);
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
unsigned int driver_poll_callback(struct file *filep,
|
||||
struct poll_table_struct *wait) {
|
||||
unsigned int mask = 0;
|
||||
@@ -61,6 +30,32 @@ ssize_t safe_duck_read(struct file *file, char __user *buf, size_t count,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t safe_duck_write(struct file *filp, const char __user *buf, size_t count,
|
||||
loff_t *f_pos) {
|
||||
if (count > sizeof(struct client_msg_t)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
struct client_msg_t *message =
|
||||
kmalloc(sizeof(struct client_msg_t), GFP_KERNEL);
|
||||
do {
|
||||
if (message == NULL) {
|
||||
printk(KERN_ERR "Failed to allocate memory for new msg\n");
|
||||
break;
|
||||
}
|
||||
if (copy_from_user(message, buf, sizeof(struct client_msg_t))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
if (message->check_sum != MSG_CHECK_SUM) {
|
||||
printk(KERN_ERR "Invalid checksum\n");
|
||||
break;
|
||||
}
|
||||
dispath_client_msg(message);
|
||||
} while (false);
|
||||
if (message != NULL) {
|
||||
kfree(message);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
int safe_duck_open(struct inode *inode, struct file *filep) { return 0; }
|
||||
bool build_dev(void) {
|
||||
int rc = alloc_chrdev_region(&g_driver_dev_build.devid, 0, DEVICE_CNT,
|
||||
@@ -71,6 +66,8 @@ bool build_dev(void) {
|
||||
printk("newchrled chr_dev region err\n");
|
||||
return false;
|
||||
}
|
||||
g_driver_dev_build.init_chrdev_region = true;
|
||||
|
||||
printk(KERN_WARNING "major:%d, minor:%d\n", g_driver_dev_build.major,
|
||||
g_driver_dev_build.minor);
|
||||
cdev_init(&g_driver_dev_build.cdev, &g_fops);
|
||||
@@ -80,16 +77,40 @@ bool build_dev(void) {
|
||||
if (IS_ERR(g_driver_dev_build.class)) {
|
||||
return false;
|
||||
}
|
||||
g_driver_dev_build.init_cdev_add = true;
|
||||
g_driver_dev_build.device =
|
||||
device_create(g_driver_dev_build.class, NULL, g_driver_dev_build.devid,
|
||||
NULL, DEVICE_NAME);
|
||||
return IS_ERR(g_driver_dev_build.device) == false;
|
||||
const bool build_dev_success = IS_ERR(g_driver_dev_build.device) == false;
|
||||
if (build_dev_success) {
|
||||
g_driver_dev_build.init_device_create = true;
|
||||
}
|
||||
return build_dev_success;
|
||||
}
|
||||
void destory_dev(void) {
|
||||
cdev_del(&g_driver_dev_build.cdev);
|
||||
unregister_chrdev_region(g_driver_dev_build.devid, DEVICE_NAME);
|
||||
device_destroy(g_driver_dev_build.class, g_driver_dev_build.devid);
|
||||
class_destroy(g_driver_dev_build.class);
|
||||
if (g_driver_dev_build.init_cdev_add) {
|
||||
cdev_del(&g_driver_dev_build.cdev);
|
||||
}
|
||||
if (g_driver_dev_build.init_chrdev_region) {
|
||||
unregister_chrdev_region(g_driver_dev_build.devid, DEVICE_NAME);
|
||||
}
|
||||
if (g_driver_dev_build.init_device_create) {
|
||||
device_destroy(g_driver_dev_build.class, g_driver_dev_build.devid);
|
||||
}
|
||||
if (g_driver_dev_build.init_cdev_add) {
|
||||
class_destroy(g_driver_dev_build.class);
|
||||
}
|
||||
}
|
||||
int cleanup(void) {
|
||||
if (g_driver_dev_build.init_netfilter) {
|
||||
nf_unregister_net_hook(&init_net, &g_network_hook_ops);
|
||||
}
|
||||
if (g_driver_dev_build.init_hashmap) {
|
||||
cleanup_iphashmap();
|
||||
}
|
||||
destory_dev();
|
||||
cleanup_msg();
|
||||
return -1;
|
||||
}
|
||||
static int __init driver_entry(void) {
|
||||
printk(KERN_WARNING "[DebugMessage] safe duck init\n");
|
||||
@@ -99,21 +120,25 @@ static int __init driver_entry(void) {
|
||||
printk(KERN_ERR "Failed to build device\n");
|
||||
return -1;
|
||||
}
|
||||
if (init_ip_hashmap() == false) {
|
||||
printk(KERN_ERR "Failed to init ip hashmap\n");
|
||||
return cleanup();
|
||||
}
|
||||
g_driver_dev_build.init_hashmap = true;
|
||||
init_msg();
|
||||
int rc = nf_register_net_hook(&init_net, &g_network_hook_ops);
|
||||
if (rc < 0) {
|
||||
printk(KERN_ERR "Failed to register network hook: %d\n", rc);
|
||||
return rc;
|
||||
return cleanup();
|
||||
}
|
||||
g_driver_dev_build.init_netfilter = true;
|
||||
printk(KERN_WARNING "[DebugMessage] safe duck init success \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit driver_exit(void) {
|
||||
printk(KERN_INFO "[DebugMessage] safe duck exit\n");
|
||||
nf_unregister_net_hook(&init_net, &g_network_hook_ops);
|
||||
cleanup_msg();
|
||||
destory_dev();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
module_init(driver_entry);
|
||||
|
||||
@@ -5,6 +5,7 @@ size_t g_msg_length;
|
||||
void push_msg(struct kernel_msg_t *msg) {
|
||||
if (get_msg_list_length() > 0x1000) {
|
||||
printk(KERN_ERR "Too many messages in the list\n");
|
||||
kfree(msg);
|
||||
return;
|
||||
}
|
||||
struct msg_list *new_msg = kmalloc(sizeof(struct msg_list), GFP_KERNEL);
|
||||
@@ -22,6 +23,36 @@ void push_msg(struct kernel_msg_t *msg) {
|
||||
wake_up_interruptible(&g_r3_wait_queue);
|
||||
}
|
||||
}
|
||||
void push_msg_new_ip_connect(size_t ip_address) {
|
||||
struct kernel_msg_t *msg = kmalloc(sizeof(struct kernel_msg_t), GFP_KERNEL);
|
||||
if (msg == NULL) {
|
||||
printk(KERN_ERR "Failed to allocate memory for new msg\n");
|
||||
return;
|
||||
}
|
||||
msg->type = SD_MSG_TYPE_NEW_IP_CONNECT;
|
||||
msg->u.ip_action.src_ip = ip_address;
|
||||
push_msg(msg);
|
||||
}
|
||||
void push_msg_syn_attack(size_t ip_address) {
|
||||
struct kernel_msg_t *msg = kmalloc(sizeof(struct kernel_msg_t), GFP_KERNEL);
|
||||
if (msg == NULL) {
|
||||
printk(KERN_ERR "Failed to allocate memory for new msg\n");
|
||||
return;
|
||||
}
|
||||
msg->type = SD_MSG_TYPE_SYN_ATTACK;
|
||||
msg->u.ip_action.src_ip = ip_address;
|
||||
push_msg(msg);
|
||||
}
|
||||
void push_msg_ssh_bf_attack(size_t ip_address) {
|
||||
struct kernel_msg_t *msg = kmalloc(sizeof(struct kernel_msg_t), GFP_KERNEL);
|
||||
if (msg == NULL) {
|
||||
printk(KERN_ERR "Failed to allocate memory for new msg\n");
|
||||
return;
|
||||
}
|
||||
msg->type = SD_MSG_TYPE_SSH_BF_ATTACK;
|
||||
msg->u.ip_action.src_ip = ip_address;
|
||||
push_msg(msg);
|
||||
}
|
||||
struct kernel_msg_t *get_msg(void) {
|
||||
struct kernel_msg_t *msg = NULL;
|
||||
struct msg_list *tmp = NULL;
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
typedef enum _msg_type {
|
||||
SD_MSG_TYPE_ERROR = -1,
|
||||
SD_MSG_TYPE_NEW_IP_CONNECT = 0,
|
||||
SD_MSG_TYPE_SYN_ATTACK = 1,
|
||||
SD_MSG_TYPE_CLIENT_BLOCK_IP = 2,
|
||||
SD_MSG_TYPE_SSH_BF_ATTACK = 3,
|
||||
};
|
||||
|
||||
typedef struct kernel_msg_t {
|
||||
@@ -11,8 +14,18 @@ typedef struct kernel_msg_t {
|
||||
int type;
|
||||
union {
|
||||
struct {
|
||||
unsigned int src_ip;
|
||||
} poll_req;
|
||||
unsigned long src_ip;
|
||||
} ip_action;
|
||||
} u;
|
||||
};
|
||||
typedef struct client_msg_t {
|
||||
unsigned long check_sum;
|
||||
int type;
|
||||
union {
|
||||
struct {
|
||||
unsigned long src_ip;
|
||||
unsigned long block_time;
|
||||
} ip_address;
|
||||
} u;
|
||||
};
|
||||
typedef struct msg_list {
|
||||
@@ -25,3 +38,6 @@ extern struct kernel_msg_t *get_msg(void);
|
||||
extern size_t get_msg_list_length(void);
|
||||
extern void cleanup_msg(void);
|
||||
extern void init_msg(void);
|
||||
extern void push_msg_syn_attack(size_t ip_address);
|
||||
extern void push_msg_new_ip_connect(size_t ip_address);
|
||||
extern void push_msg_ssh_bf_attack(size_t ip_address);
|
||||
|
||||
161
linux_kernel/network.c
Normal file
161
linux_kernel/network.c
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "network.h"
|
||||
|
||||
void block_ip_address(size_t ip_address, size_t time_sec) {
|
||||
struct ip_hashmap_node_t *data = get_ipdata_by_hashmap(ip_address);
|
||||
const s64 current_time_sec = ktime_get_real_seconds();
|
||||
|
||||
if (data == NULL) {
|
||||
struct ip_hashmap_info info;
|
||||
info.ip_address_key = ip_address;
|
||||
info.ip_meta_info.last_attack_time = current_time_sec;
|
||||
info.ip_meta_info.remove_time = current_time_sec + time_sec;
|
||||
info.ip_meta_info.is_attack = true;
|
||||
put_ipdata_by_hashmap(ip_address, &info);
|
||||
return;
|
||||
}
|
||||
data->info.ip_meta_info.last_attack_time = current_time_sec;
|
||||
data->info.ip_meta_info.remove_time = current_time_sec + time_sec;
|
||||
data->info.ip_meta_info.is_attack = true;
|
||||
}
|
||||
bool check_is_blacklist_ip(size_t ip_address) {
|
||||
struct ip_hashmap_node_t *data = get_ipdata_by_hashmap(ip_address);
|
||||
if (data == NULL) {
|
||||
printk(KERN_ERR "Failed to get ip data from hashmap\n");
|
||||
return false;
|
||||
}
|
||||
return data->info.ip_meta_info.is_attack;
|
||||
}
|
||||
bool check_syn_attack(struct iphdr *ip_header, struct sk_buff *skb) {
|
||||
bool is_block = false;
|
||||
do {
|
||||
if (ip_header->protocol != IPPROTO_TCP) {
|
||||
break;
|
||||
}
|
||||
struct tcphdr *tcp_header = tcp_hdr(skb);
|
||||
if (tcp_header == NULL) {
|
||||
break;
|
||||
}
|
||||
if (tcp_header->syn == 0 || tcp_header->ack || tcp_header->rst) {
|
||||
break;
|
||||
}
|
||||
size_t ip_address_key = ip_header->saddr;
|
||||
struct ip_hashmap_node_t *data = get_ipdata_by_hashmap(ip_address_key);
|
||||
const s64 current_time_sec = ktime_get_real_seconds();
|
||||
if (data == NULL) {
|
||||
struct ip_hashmap_info info;
|
||||
info.ip_address_key = ip_address_key;
|
||||
info.syn_scan_info.last_seen = current_time_sec;
|
||||
info.syn_scan_info.num_syn_packets = 1;
|
||||
put_ipdata_by_hashmap(ip_address_key, &info);
|
||||
break;
|
||||
}
|
||||
s64 time_diff = current_time_sec - data->info.syn_scan_info.last_seen;
|
||||
if (time_diff >= SYN_SCAN_TIME) {
|
||||
data->info.syn_scan_info.num_syn_packets = 0;
|
||||
data->info.syn_scan_info.last_seen = current_time_sec;
|
||||
break;
|
||||
}
|
||||
data->info.syn_scan_info.num_syn_packets++;
|
||||
if (data->info.syn_scan_info.num_syn_packets >= SYN_SCAN_THRESHOLD) {
|
||||
// printk(KERN_ERR "SYN attack detected from %pI4 num packet: %d
|
||||
// \n",
|
||||
// &ip_header->saddr,
|
||||
// data->info.syn_scan_info.num_syn_packets);
|
||||
push_msg_syn_attack(ip_address_key);
|
||||
block_ip_address(ip_address_key, IP_ATTCK_BLOCK_TIME);
|
||||
is_block = true;
|
||||
}
|
||||
|
||||
} while (false);
|
||||
return is_block;
|
||||
}
|
||||
|
||||
bool check_ssh_brute_force_attack(struct iphdr *ip_header,
|
||||
struct sk_buff *skb) {
|
||||
bool is_block = false;
|
||||
do {
|
||||
if (ip_header->protocol != IPPROTO_TCP) {
|
||||
break;
|
||||
}
|
||||
struct tcphdr *tcp_header = tcp_hdr(skb);
|
||||
if (tcp_header == NULL) {
|
||||
break;
|
||||
}
|
||||
if ((tcp_header->syn == 1) && (tcp_header->ack == 0)) {
|
||||
break;
|
||||
}
|
||||
// check port
|
||||
if (ntohs(tcp_header->dest) != SSH_PORT) {
|
||||
break;
|
||||
}
|
||||
size_t ip_address_key = ip_header->saddr;
|
||||
struct ip_hashmap_node_t *data = get_ipdata_by_hashmap(ip_address_key);
|
||||
const s64 current_time_sec = ktime_get_real_seconds();
|
||||
if (data == NULL) {
|
||||
struct ip_hashmap_info info;
|
||||
info.ip_address_key = ip_address_key;
|
||||
info.crack_ip_info.last_seen = current_time_sec;
|
||||
info.crack_ip_info.num_connect = 1;
|
||||
put_ipdata_by_hashmap(ip_address_key, &info);
|
||||
break;
|
||||
}
|
||||
s64 time_diff = current_time_sec - data->info.crack_ip_info.last_seen;
|
||||
if (time_diff >= SSH_BRUTE_FORCE_TIME) {
|
||||
data->info.crack_ip_info.num_connect = 0;
|
||||
data->info.crack_ip_info.last_seen = current_time_sec;
|
||||
break;
|
||||
}
|
||||
data->info.crack_ip_info.num_connect++;
|
||||
if (data->info.crack_ip_info.num_connect >= SSH_BRUTE_FORCE_THRESHOLD) {
|
||||
// printk(KERN_ERR "SYN attack detected from %pI4 num packet: %d
|
||||
// \n",
|
||||
// &ip_header->saddr,
|
||||
// data->info.syn_scan_info.num_syn_packets);
|
||||
push_msg_ssh_bf_attack(ip_address_key);
|
||||
block_ip_address(ip_address_key, IP_ATTCK_BLOCK_TIME);
|
||||
is_block = true;
|
||||
}
|
||||
|
||||
} while (false);
|
||||
return is_block;
|
||||
}
|
||||
unsigned int network_callback(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb, const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *)) {
|
||||
bool is_block = false;
|
||||
do {
|
||||
if (skb == NULL) {
|
||||
break;
|
||||
}
|
||||
struct iphdr *ip_header = ip_hdr(skb);
|
||||
|
||||
if (ip_header == NULL) {
|
||||
break;
|
||||
}
|
||||
if (check_is_blacklist_ip(ip_header->saddr)) {
|
||||
is_block = true;
|
||||
printk(KERN_ERR "Block ip address: %pI4\n", &ip_header->saddr);
|
||||
break;
|
||||
}
|
||||
if (check_syn_attack(ip_header, skb)) {
|
||||
is_block = true;
|
||||
break;
|
||||
}
|
||||
if (check_ssh_brute_force_attack(ip_header, skb)) {
|
||||
is_block = true;
|
||||
break;
|
||||
}
|
||||
struct tcphdr *tcp_header = tcp_hdr(skb);
|
||||
if (tcp_header == NULL) {
|
||||
break;
|
||||
}
|
||||
if ((tcp_header->syn == 1) && (tcp_header->ack == 0)) {
|
||||
// push ip address to list
|
||||
push_msg_new_ip_connect(ip_header->saddr);
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
return is_block ? NF_DROP : NF_ACCEPT;
|
||||
}
|
||||
15
linux_kernel/network.h
Normal file
15
linux_kernel/network.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "head.h"
|
||||
#define IP_ATTCK_BLOCK_TIME 600
|
||||
#define SYN_SCAN_THRESHOLD 500
|
||||
#define SYN_SCAN_TIME 10
|
||||
#define SSH_BRUTE_FORCE_THRESHOLD 10
|
||||
#define SSH_BRUTE_FORCE_TIME 5
|
||||
#define SSH_PORT 22
|
||||
extern unsigned int network_callback(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *));
|
||||
extern void block_ip_address(size_t ip_address, size_t time_sec);
|
||||
extern bool check_is_blacklist_ip(size_t ip_address);
|
||||
@@ -14,4 +14,5 @@ struct file_operations g_fops = {
|
||||
.open = safe_duck_open,
|
||||
.release = safe_duck_release,
|
||||
.read = safe_duck_read,
|
||||
.write = safe_duck_write,
|
||||
};
|
||||
|
||||
@@ -11,6 +11,8 @@ extern int safe_duck_open(struct inode *inode, struct file *filep);
|
||||
extern int safe_duck_release(struct inode *inode, struct file *file);
|
||||
extern ssize_t safe_duck_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *pos);
|
||||
extern ssize_t safe_duck_write(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *f_pos);
|
||||
struct _driver_dev_build {
|
||||
int major;
|
||||
int minor;
|
||||
@@ -18,6 +20,11 @@ struct _driver_dev_build {
|
||||
dev_t devid; // device num
|
||||
struct class *class; // class
|
||||
struct device *device; // device
|
||||
bool init_chrdev_region;
|
||||
bool init_cdev_add;
|
||||
bool init_device_create;
|
||||
bool init_netfilter;
|
||||
bool init_hashmap;
|
||||
};
|
||||
extern struct nf_hook_ops g_network_hook_ops;
|
||||
extern struct file_operations g_fops;
|
||||
|
||||
Reference in New Issue
Block a user