Я пытаюсь создать простой модуль ядра, используя ловушку netfilter, которая изменит адрес источника любого пакета и передаст снова, как NAT. Новый адрес источника будет сохранен в массиве s_entries
в программе ниже.
Но я не имею ни малейшего представления о том, какие все связанные параметры я должен изменить как часть этого, и как его отправить. вне. Пожалуйста, найдите следующий код, где я поместил 'TODO' в этой программе. Может ли кто-нибудь помочь мне найти решение для этого? Я видел некоторую нить, связанную NF_HOOK
, чтобы отправить снова. Но может кто-нибудь сказать мне, как использовать NF_HOOK
для отправки пакета с PRE_ROUTING_HOOK
?
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/module.h>
#include <linux/kernel.h> // included for KERN_INFO
#include <linux/init.h> // included for __init and __exit macros
#include <net/ip.h>
#include "defines.h"
#include <linux/inetdevice.h>
#define NIPQUAD(addr) ((unsigned char *)&addr)[0], ((unsigned char *)&addr)[1], ((unsigned char *)&addr)[2], ((unsigned char *)&addr)[3]
static sock_data_t **s_entries = NULL;
static int set_index = 0;
static int get_index = 0;
static sock_data_t *get_new_src_entry(uint ip, ushort port) {
int i;
for(i = 0; i < MAX_NUM_ENTRIES; i++) {
if(s_entries[i] && s_entries[i]->baddr.ipaddr == ip && s_entries[i]->baddr.port == port) {
return s_entries[i];
}
}
return NULL;
}
static sock_data_t *get_matching_dest(uint ip, ushort port) {
int i;
for(i = 0; i < MAX_NUM_ENTRIES; i++) {
if(s_entries[i] && s_entries[i]->xaddr.ipaddr == ip && s_entries[i]->xaddr.port == port) {
return s_entries[i];
}
}
return NULL;
}
static unsigned int ip_simple_nat_hook_v4(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
struct iphdr *iph = ip_hdr(skb);
struct udphdr *udph;
struct tcphdr *tcph;
ushort dst_port = 0;
ushort src_port = 0;
sock_data_t *entry = NULL;
// struct net_device *dev;
if(iph->protocol == IPPROTO_UDP) {
udph = udp_hdr(skb);
dst_port = ntohs(udph->dest);
src_port = ntohs(udph->source);
} else if(iph->protocol == IPPROTO_TCP) {
tcph = tcp_hdr(skb);
dst_port = ntohs(tcph->dest);
src_port = ntohs(tcph->source);
}
if(dst_port != 1250) return NF_ACCEPT;
if(skb->dev)
printk(KERN_INFO "simple_nat: Hook: %u; Interface name:%s\n", state->hook, skb->dev->name);
else
printk(KERN_INFO "simple_nat: No destination in sk_buff[%d]\n", state->hook);
entry = get_new_src_entry(iph->saddr, src_port);
if(entry) {
// TODO: modify iph->saddr with entry entry->baddr.ipaddr and send again.
return NF_ACCEPT;
}
printk(KERN_INFO "%pI4:%d -- %pI4:%d\n", &iph->saddr, src_port, &iph->daddr, dst_port);
return NF_ACCEPT;
}
static struct nf_hook_ops ip_simple_nat_pre_v4 = {
.hook = (nf_hookfn*)ip_simple_nat_hook_v4,
.pf = PF_INET,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST
};
/**
* @brief: Set set index to next empty space
* @return: 0 successful
* -1 loop completed and no space left
*/
static unsigned short set_next_set_index(void) {
int tmp_idx = set_index;
while(1) {
++set_index;
if(set_index == MAX_NUM_ENTRIES)
set_index = 0;
if(set_index == tmp_idx) {
return -1;
}
if(!s_entries[set_index]) {
return 0;
}
}
}
/**
* @brief: Set get index to next non-empty space
* @return: 0 successful
* -1 loop completed and no item found
*/
static unsigned short set_next_get_index(void) {
int tmp_idx = get_index;
while(1) {
++get_index;
if(get_index == MAX_NUM_ENTRIES)
get_index = 0;
if(get_index == tmp_idx) {
return -1;
}
if(s_entries[get_index]) {
return 0;
}
}
}
/**
* @brief: setsockopt controls
*/
static int simple_nat_set_ctl(struct sock *sk, int cmd, void *user, unsigned int len)
{
sock_data_t *data;
switch(cmd) {
case SN_SET_ENTRY:
if(set_next_set_index()) {
printk(KERN_INFO "simple_nat: No free space\n");
return -EFAULT;
}
// If size of data is not as expected; discard it.
if(len != sizeof(sock_data_t)) {
printk(KERN_INFO "simple_nat: Invalid data given\n");
return -EFAULT;
}
// Allocate memory in the array.
s_entries[set_index] = (sock_data_t *)kzalloc(sizeof(sock_data_t), GFP_ATOMIC);
if(!s_entries[set_index]) {
return -ENOMEM;
}
// Copy data to kernel memeory
if(copy_from_user(s_entries[set_index], user, sizeof(sock_data_t))) {
return -EFAULT;
}
data = s_entries[set_index];
printk(KERN_INFO "simple_nat: New entry crated at %d\n", set_index);
break;
case SN_REST_IDX:
get_index = 0;
break;
}
return 0;
}
/**
* @brief: getsockopt controls
*/
static int simple_nat_get_ctl(struct sock *sk, int cmd, void *user, int *len)
{
switch(cmd) {
case SN_GET_ENTRY:
if(set_next_get_index()) {
printk(KERN_INFO "simple_nat: Loop completed\n");
return -EFAULT;
}
if(!s_entries[get_index] || copy_to_user(user, s_entries[get_index], *len)) {
return -EFAULT;
}
break;
}
return 0;
}
static struct nf_sockopt_ops simple_nat_sockopt = {
.pf = PF_INET,
.set_optmin = SN_SO_BASE_CTL,
.set_optmax = SN_SO_MAX_CTL,
.set = simple_nat_set_ctl,
.get_optmin = SN_SO_BASE_CTL,
.get_optmax = SN_SO_MAX_CTL,
.get = simple_nat_get_ctl,
};
static int __init simple_nat_init(void) {
int ret = 0;
printk(KERN_INFO "simple_nat: Module inserted\n");
s_entries = kzalloc(sizeof(sock_data_t *) * MAX_NUM_ENTRIES, GFP_KERNEL);
if(!s_entries) {
printk("simple_nat: Memory allocation failed\n");
return -1;
}
ret = nf_register_net_hook(&init_net, &ip_simple_nat_pre_v4);
if(ret < 0) {
printk(KERN_ERR "simple_nat: Pre-Hook Failed\n");
goto pre_hook_exit;
}
ret = nf_register_sockopt(&simple_nat_sockopt);
if(ret < 0) {
printk(KERN_ERR "simple_nat: setting sockopt failed Failed\n");
goto sock_opt_exit;
}
return 0;
sock_opt_exit:
nf_unregister_net_hook(&init_net, &ip_simple_nat_pre_v4);
pre_hook_exit:
kfree(s_entries);
return -1;
}
static void free_entry(int idx) {
if(s_entries[idx]) {
kfree(s_entries[idx]);
s_entries[idx] = NULL;
}
}
static void free_all_entries(void) {
int idx;
for(idx = 0; idx < MAX_NUM_ENTRIES; idx++) {
free_entry(idx);
}
}
static void __exit simple_nat_exit(void) {
nf_unregister_net_hook(&init_net, &ip_simple_nat_pre_v4);
nf_unregister_sockopt(&simple_nat_sockopt);
free_all_entries();
if(s_entries) {
kfree(s_entries);
}
printk(KERN_INFO "simple_nat: Module exit\n");
}
module_init(simple_nat_init);
module_exit(simple_nat_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shafeeque");
MODULE_DESCRIPTION("A Simple NAT module");
Спасибо, Shafeeque