Netfilter for kernel
От: Molchalnik  
Дата: 29.09.14 12:55
Оценка:
Пытаюсь освоить программирование под ядро 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;
}
Отредактировано 29.09.2014 12:57 Molchalnik . Предыдущая версия .
netfilter kernel linux
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.