- گروه شماره ۲۵
- معین آعلی - ۴۰۱۱۰۵۵۶۱
- ثمین اکبری - ۴۰۱۱۰۵۵۹۴
کد درایور:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int __init hello_init(void) {
printk(KERN_INFO "Hello\n");
return 0;
}
static void __exit hello_exit(void) {
printk(KERN_INFO "Goodbye\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Moeein Aali");
MODULE_DESCRIPTION("Hello World Linux kernel module");ابتدا دستور Make
را اجرا میکنیم و سپس:
نتیجهی اجرا:
توضیحات:
#include <linux/module.h>: کتابخانه اصلی برای نوشتن ماژول کرنل.
#include <linux/kernel.h>: شامل توابعی مثل printk.
#include <linux/init.h>: برای ماکروهای __init و __exit.
hello_init: هنگام بارگذاری ماژول توسط دستور insmod اجرا شده و پیام "Hello" چاپ میکند.
hello_exit: هنگام حذف ماژول با rmmod اجرا شده و پیام "Goodbye" چاپ میکند.
printk: مشابه printf در فضای کرنل، با سطح اهمیت (KERN_INFO).
module_init و module_exit: معرفی توابع ورودی و خروجی ماژول.
متادیتا مثل MODULE_LICENSE، MODULE_AUTHOR و MODULE_DESCRIPTION: اطلاعات ماژول.
نیازمندی اجرایی:
sudo apt-get install build-essential linux-headers-$(uname -r)
البته این را در آزمایشهای قبل نصب کردهایم و نیازی به اجرای آن نبود...
کد درایور:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/time.h>
#include <linux/string.h>
#define LOG_FILE "/var/log/netmon.log"
static struct nf_hook_ops nfho_in;
static struct nf_hook_ops nfho_out;
static struct file *log_file = NULL;
static loff_t log_pos = 0;
static char* get_protocol_name(unsigned int protocol) {
switch(protocol) {
case IPPROTO_TCP: return "TCP";
case IPPROTO_UDP: return "UDP";
case IPPROTO_ICMP: return "ICMP";
default: return "OTHER";
}
}
static void log_packet(const struct sk_buff *skb, const char *direction) {
struct iphdr *ip_header;
struct tcphdr *tcp_header;
struct udphdr *udp_header;
char log_entry[256];
struct timespec64 ts;
int len = 0;
if (!skb || !log_file) return;
ip_header = ip_hdr(skb);
if (!ip_header) return;
ktime_get_real_ts64(&ts);
len = snprintf(log_entry, sizeof(log_entry),
"[%lld.%09ld] %s %pI4:%d -> %pI4:%d %s len=%d\n",
(long long)ts.tv_sec, ts.tv_nsec,
direction,
&ip_header->saddr, ntohs(ip_header->saddr),
&ip_header->daddr, ntohs(ip_header->daddr),
get_protocol_name(ip_header->protocol),
ntohs(ip_header->tot_len));
if (len > 0) {
kernel_write(log_file, log_entry, len, &log_pos);
}
}
static unsigned int hook_func_in(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) {
log_packet(skb, "IN");
return NF_ACCEPT;
}
static unsigned int hook_func_out(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) {
log_packet(skb, "OUT");
return NF_ACCEPT;
}
static int __init netmon_init(void) {
log_file = filp_open(LOG_FILE, O_WRONLY|O_CREAT|O_APPEND, 0644);
if (IS_ERR(log_file)) {
printk(KERN_ERR "Failed to open log file\n");
return PTR_ERR(log_file);
}
nfho_in.hook = hook_func_in;
nfho_in.hooknum = NF_INET_PRE_ROUTING;
nfho_in.pf = PF_INET;
nfho_in.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &nfho_in);
nfho_out.hook = hook_func_out;
nfho_out.hooknum = NF_INET_POST_ROUTING;
nfho_out.pf = PF_INET;
nfho_out.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &nfho_out);
printk(KERN_INFO "Network monitor loaded\n");
return 0;
}
static void __exit netmon_exit(void) {
nf_unregister_net_hook(&init_net, &nfho_in);
nf_unregister_net_hook(&init_net, &nfho_out);
if (log_file && !IS_ERR(log_file)) {
filp_close(log_file, NULL);
}
printk(KERN_INFO "Network monitor unloaded\n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Moeein");
MODULE_DESCRIPTION("Network monitoring");
module_init(netmon_init);
module_exit(netmon_exit);شیوه عملکرد این درایور به این صورت است که در تابع init، ماژول ابتدا فایل لاگ خود را با پرچمهای O_WRONLY، O_CREATE و O_APPEND باز میکند تا امکان نوشتن در انتهای فایل و در صورت لزوم ایجاد آن فراهم شود. سپس با بهرهگیری از تابع nf_register_net_hook، یک قلاب روی namespace شبکه قرار میدهیم. در اینجا init_net همان namespace اصلی است که تمامی ترافیک از آن عبور میکند. بنابراین میتوانیم ترافیک ورودی و خروجی را به تابع log_packet هدایت کنیم. در پایان، این تابع دادههای مهمی مانند زمان ارسال بسته، آدرسهای مبدأ و مقصد، نوع پروتکل و طول پیام را با استفاده از snprintf قالببندی کرده و در فایل موردنظر ذخیره میکند.
نتیجه اجرا:


