Пытаюсь освоить программирование под ядро linux. Поэтому вопросы, вероятно, будут ламерскими.
есть простой код, он виснет.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
//#include <linux/semaphore.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include <net/genetlink.h>
//# include <linux/semaphore.h>
#include <linux/proc_fs.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/netfilter_ipv4.h>
# define Max(a,b) ( ( (a) > (b) ) ? (a) : (b) )
# define Min(a,b) ( ( (a) < (b) ) ? (a) : (b) )
# define DiagnosticPrint printk
# define PrintError printk
typedef unsigned int IPType; //MUST be 32 bit
typedef unsigned int PortType; //MUST be 32 bit
typedef size_t Size;
# define KERNEL_ASSERT_SERVICE(condition, message, file, line) {if (!(condition)) {PrintError(KERN_EMERG " * * * ASSERTION_ERROR * * * ---> %s ( in file %s at %d ) ", message, file, line); } }
# define KERNEL_ASSERT(condition, message) { KERNEL_ASSERT_SERVICE(condition, message, __FILE__, __LINE__) }
enum ProtocolType {
kUDP_Protocol = 17,
kTCP_Protocol = 6
};
extern int InPacketWork(void *rules, IPType src_ip, IPType dest_ip, PortType src_port, PortType dest_port, unsigned protocol, int accept_value, int drop_value);
void RegisterHook_C(void);
void UnregisterHook_C(void);
static int __init cppmod_init(void)
{
DiagnosticPrint(KERN_INFO "cpp module installed\n");
DiagnosticPrint(KERN_EMERG "size of rwlock_t = %lu", sizeof(rwlock_t) );
RegisterHook_C();
return 0;
}
static void __exit cppmod_exit(void)
{
DiagnosticPrint(KERN_INFO "cpp module removed\n");
UnregisterHook_C();
}
module_init(cppmod_init);
module_exit(cppmod_exit);
MODULE_LICENSE("GPL");
struct nf_hook_ops gHookDescriptor;
#define KERNEL_API_C_DIFF_IN_BYTES(pointer1, pointer2) ( (char *)(pointer2) - (char *)(pointer1) )
#define KERNEL_API_C_MAX_POINTER(pointer1, pointer2) ( Max( (char *)(pointer2) , (char *)(pointer1) ) )
unsigned int InPacketHook(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *)) {
struct iphdr *ip_header = 0;
struct udphdr *udp_header = 0;
struct tcphdr *tcp_header = 0;
unsigned int src_ip = 0;
unsigned int dest_ip = 0;
unsigned int src_port = 0;
unsigned int dest_port = 0;
unsigned int protocol;
int re = NF_ACCEPT;
if ( hooknum != NF_INET_LOCAL_IN) return NF_ACCEPT;
do {
if (!skb) {
KERNEL_ASSERT(0,"InPacketHook: null socket buffer");
break;
}
if (ip_hdrlen(skb) < sizeof(struct iphdr)) {
DiagnosticPrint(KERN_EMERG "short message incoming len = %u", ip_hdrlen(skb));
KERNEL_ASSERT(0,"InPacketHook: too short");
break;
}
#if 0
if ( hooknum == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))) {
// root is playing with raw sockets.
return NF_ACCEPT;
}
#endif
if (skb->protocol != htons(ETH_P_IP) ) {
KERNEL_ASSERT(0,"InPacketHook: error skb protocol");
break;
}
if (skb->pkt_type != PACKET_HOST ) {
//KERNEL_ASSERT(0,"InPacketHook: error skb type");
break;
}
//ip_header = (struct iphdr *)skb_network_header(skb); //мой вариант
ip_header = ip_hdr(skb); //как в iptables
if (!ip_header) {
KERNEL_ASSERT(0,"InPacketHook: null ip_header");
break;
}
if(! (ip_header->version == 4 && ip_header->protocol == IPPROTO_TCP) ) {
//DiagnosticPrint(KERN_EMERG "NON Tcp, exit");
return NF_ACCEPT;
//break;
}
src_ip = (unsigned int)ip_header->saddr;
dest_ip = (unsigned int)ip_header->daddr;
protocol = ip_header->protocol;
if (protocol == kUDP_Protocol) {
if ( ip_hdrlen(skb) < sizeof(struct iphdr) + sizeof(*udp_header) ) {
DiagnosticPrint(KERN_EMERG "short message incoming len = %u", ip_hdrlen(skb));
KERNEL_ASSERT(0,"InPacketHook: udp message too short");
break;
}
udp_header = (struct udphdr *)(skb_transport_header(skb) + ip_hdrlen(skb));
//udp_header = (struct udphdr *)(skb_transport_header(skb));
if (!udp_header) {
KERNEL_ASSERT(0,"InPacketHook: null udp_header");
break;
}
{
void * max_pointer = KERNEL_API_C_MAX_POINTER(&udp_header->source, &udp_header->dest);
Size delta = KERNEL_API_C_DIFF_IN_BYTES(skb->head, max_pointer) + sizeof(udp_header->dest);
if (delta > skb->len) {
DiagnosticPrint(KERN_EMERG "UDP incoming %3.u.%3.u.%3.u.%3.u delta = %lu, len = %u", src_ip&255, (src_ip>>8)&255, (src_ip>>16)&255, (src_ip>>24)&255 , delta, skb->len);
KERNEL_ASSERT(0,"InPacketHook: udp message too short");
break;
}
}
src_port = (unsigned int)ntohs(udp_header->source);
dest_port = (unsigned int)ntohs(udp_header->dest);
//DiagnosticPrint(KERN_EMERG "source_port = %u, dest_port = %u", src_port, dest_port);
} else {
if (protocol == kTCP_Protocol) {
if( ip_header->version != 4) {
DiagnosticPrint(KERN_EMERG "NON Tcp 4, exit");
break;
}
/* //вешается на этой проверке
if ( ip_hdrlen(skb) < sizeof(struct iphdr) + sizeof(*tcp_header) ) {
DiagnosticPrint(KERN_EMERG "short message incoming len = %u", ip_hdrlen(skb));
KERNEL_ASSERT(0,"InPacketHook: tcp message too short");
break;
}
*/
tcp_header = (struct tcphdr *)(skb_transport_header(skb) + ip_hdrlen(skb));
//tcp_header = (struct tcphdr *)(skb_transport_header(skb));
if (!tcp_header) {
KERNEL_ASSERT(0,"InPacketHook: null tcp_header");
break;
}
src_port = (unsigned int)ntohs(tcp_header->source);
dest_port = (unsigned int)ntohs(tcp_header->dest);
//DiagnosticPrint(KERN_EMERG "source_port = %u, dest_port = %u", src_port, dest_port);
} else {
KERNEL_ASSERT(0,"InPacketHook: UNKNOWN PROTOCOL");
break;
}
}
re = InPacketWork((void*)0, src_ip, dest_ip, src_port, dest_port, protocol, NF_ACCEPT, NF_DROP);//*/
} while (0);
return re;
}
void RegisterHook_C(void) {
DiagnosticPrint(KERN_INFO "Hook\n");
gHookDescriptor.hook = InPacketHook;
gHookDescriptor.hooknum = NF_INET_LOCAL_IN;
gHookDescriptor.pf = PF_INET;
gHookDescriptor.priority = NF_IP_PRI_FIRST;
nf_register_hook(&gHookDescriptor);
}
void UnregisterHook_C(void) {
nf_unregister_hook(&gHookDescriptor);
DiagnosticPrint(KERN_INFO "Unhook\n");
}
////////////////////////////////////////////////////////////////////
Size g_debug_in_packet_counter = 0;
rwlock_t g_memory_lock;
int InPacketWork(void *rules, IPType src_ip, IPType dest_ip, PortType src_port, PortType dest_port, unsigned protocol, int accept_value, int drop_value) {
DiagnosticPrint(KERN_EMERG "InPacket debug counter = %lu", g_debug_in_packet_counter);
write_lock(&g_memory_lock);
++g_debug_in_packet_counter;
write_unlock(&g_memory_lock);
return NF_ACCEPT;
}