- 注册时间
- 2011-3-6
- 最后登录
- 1970-1-1
该用户从未签到
|
前置知识:
IP包:- struct ip {
- #if BYTE_ORDER == LITTLE_ENDIAN
- unsigned char ip_hl:4, /* header length */
- ip_v:4; /* version */
- #endif
- unsigned char ip_tos; /* type of service */
- short ip_len; /* total length */
- unsigned short ip_id;/* identification */
- short ip_off;
- unsigned char ip_ttl;/* time to live */
- unsigned char ip_p;/* protocol */
- unsigned short ip_sum;
- struct in_addr ip_src,ip_dst;/* source and dest address */
- };
复制代码
IHL(Internet Header Length 报头长度),位于IP报文的第二个字段,4位,表示IP报文头部按32位字长(32位,4字节)计数的长度,也即报文头的长度等于IHL的值乘以4。 (ip_hl)
TCP头- struct tcphdr {
- u_short th_sport; /* source port */
- u_short th_dport; /* destination port */
- tcp_seq th_seq; /* sequence number */
- tcp_seq th_ack; /* acknowledgement number */
- #if BYTE_ORDER == LITTLE_ENDIAN
- u_char th_x2:4, /* (unused) */
- th_off:4; /* data offset */
- #endif
- #if BYTE_ORDER == BIG_ENDIAN
- u_char th_off:4, /* data offset */
- th_x2:4; /* (unused) */
- #endif
- u_char th_flags;
- #define TH_FIN 0x01
- #define TH_SYN 0x02
- #define TH_RST 0x04
- #define TH_PUSH 0x08
- #define TH_ACK 0x10
- #define TH_URG 0x20
- #define TH_FLAGS (TH_FIN|TH_SYN|
- TH_RST|TH_ACK|TH_URG)
- u_short th_win; /* window */
- u_short th_sum; /* checksum */
- u_short th_urp; /* urgent pointer */
- };
复制代码
UDP- struct udphdr
- {
- u_short uh_sport; /* source port */
- u_short uh_dport; /* destination port */
- short uh_ulen; /* udp length */
- u_short uh_sum;
- /* udp checksum */
- };
复制代码
ARP- typedef struct _ETHERNET_FRAME
- {
- BYTE DestinationAddress[6];
- BYTE SourceAddress[6];
- WORD FrameType; // in host-order
- } EHTERNET_FRAME, *PETHERNET_FRAME;
- typedef struct _ARP_HEADER
- {
- WORD HardType; //硬件类型
- WORD ProtocolType; //协议类型
- BYTE HardLength; //硬件地址长度
- BYTE ProtocolLength; //协议地址长度
- WORD Opcode; //操作类型
- BYTE SourceMAC[6];
- BYTE SourceIP[4];
- BYTE DestinationMAC[6];
- BYTE DestinationIP[4];
- } ARP_HEADER, *PARP_HEADER;
- typedef struct _ARP
- {
- EHTERNET_FRAME EthernetFrame;
- ARP_HEADER ArpHeader;
- }ARP, *PARP;
复制代码
其他的可以看或文章最尾部的参考文章
数据包报头百度百科
http://baike.baidu.com/link?url=DuxdZVeorGksQX94G8UP19wx_iy-o504SjAhiQjZuRWSWNaZEVthpt6cm4L_z0FryXPqF4-YPtaN0UBbe_8Yeq
基于linux内核的网络防火墙开发
Linux核心网络堆栈中有一个全局变量 :
struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS],该变量是一个二维数组,其中第一维用于指定协议族,第二维用于指定hook的类型(即5个HOOK点 )。注册一个Netfilter hook实际就是在由协议族和hook类型确定的链表中添加一个新的节点。
在Linux防火墙开发中,有5个地方可以拦截
图很清楚的说明了在对应的位置能干什么
Filter:包过滤
Nat:地址转换
Mangle:修改包数据
规则链:
五个钩子函数(hook functions),也叫五个规则链。
1.PREROUTING (路由前)
2.INPUT (数据包流入口)
3.FORWARD (转发管卡)
4.OUTPUT(数据包出口)
5.POSTROUTING(路由后)
这是NetFilter规定的五个规则链,任何一个数据包,只要经过本机,必将经过这五个链中的其中一个链。
5个HOOK点的定义:- NF_INET_PRE_ROUTING 在完整性校验之后,选路确定之前
- NF_INET_LOCAL_IN 在选路确定之后,且数据包的目的是本地主机
- NF_INET_FORWARD 目的地是其它主机地数据包
- NF_INET_LOCAL_OUT 来自本机进程的数据包在其离开本地主机的过程中
- NF_IP_POST_ROUTING 在数据包离开本地主机“上线”之前
- NF_INET_POST_ROUTING 同上
复制代码
对包的处理结果:- NF_DROP 丢弃该数据包
- NF_ACCEPT 保留该数据包
- NF_STOLEN 忘掉该数据包
- NF_QUEUE 将该数据包插入到用户空间
- NF_REPEAT 再次调用该hook函数
复制代码
优先级:- enum nf_ip_hook_priorities {
- NF_IP_PRI_FIRST = INT_MIN,
- NF_IP_PRI_CONNTRACK_DEFRAG = -400,
- NF_IP_PRI_RAW = -300,
- NF_IP_PRI_SELINUX_FIRST = -225,
- NF_IP_PRI_CONNTRACK = -200,
- NF_IP_PRI_MANGLE = -150,
- NF_IP_PRI_NAT_DST = -100,
- NF_IP_PRI_FILTER = 0,
- NF_IP_PRI_SECURITY = 50,
- NF_IP_PRI_NAT_SRC = 100,
- NF_IP_PRI_SELINUX_LAST = 225,
- NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
- NF_IP_PRI_LAST = INT_MAX,
- };
复制代码 一般写NF_IP_PRI_FIRST啦~或+1 +2...
///////////////////////////////////////////////////开始编写防火墙//////////////////////////////////////////////////////////////////
在注册之前 我们需要填写一个结构
- struct nf_hook_ops {
- struct list_head list;
- /* 此下的值由用户填充 */
- nf_hookfn *hook//回调函数;
- int pf;//协议 IPV4 还是ipV6
- int hooknum;//hook点
- /* Hook以升序的优先级排序 */
- int priority;
- };
复制代码
例子:
- struct nf_hook_ops nfho;
- /* 填充我们的hook数据结构 */
- nfho.hook = hook_func; /* 处理函数 */
- nfho.hooknum = NF_INET_PRE_ROUTING;
- /* 使用IPv4的第一个hook */
- nfho.pf = PF_INET;
- //优先级 /* 让我们的函数首先执行 */
- nfho.priority = NF_IP_PRI_FIRST;
复制代码
过滤函数:- 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 *))
- {
- return NF_DROP; /* 丢弃所有的数据包 */
- }
复制代码-
- //初始化函数调用
- nf_register_hook(&nfho);
- //卸载函数中调用
- nf_unregister_hook(&nfho);
复制代码
完整代码:- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/netfilter.h>
- #include <linux/netfilter_ipv4.h>
- static struct nf_hook_ops nfho;
- static 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 *))
- {
- return NF_ACCEPT;
- }
- static int nf_init(void)
- {
- nfho.hook = hook_func;
- nfho.hooknum = NF_INET_PRE_ROUTING;
- nfho.pf = PF_INET;
- nfho.priority = NF_IP_PRI_FIRST;
- nf_register_hook(&nfho);
- return 0;
- }
- static void nf_cleanup(void)
- {
- nf_unregister_hook(&nfho);
- }
- module_init(nf_init);
- module_exit(nf_cleanup);
- MODULE_AUTHOR("djwow");
- MODULE_LICENSE("GPL");
复制代码
struct sk_buff
sk_buff结构的成员skb->head指向一个已分配的空间的头部,即申请到的整个缓冲区的头,skb->end指向该空间的尾部,这两个成员指针从空间创建之后,就不能被修改。skb->data指向分配空间中数据的头部,skb->tail指向数据的尾部,这两个值随着网络数据在各层之间的传递、修改,会被不断改动。刚开始接触skb_buf的时候会产生一种错误的认识,就是以为协议头都会是放在skb->head和skb->data这两个指针之间,但实际上skb_buf的操作函数都无法直接对这一段内存进行操作,所有的操作函数所做的就仅仅是修改skb->data和skb->tail这两个指针而已,向套接字缓冲区拷贝数据也是由其它函数来完成的,所以不管是从网卡接受的数据还是上层发下来的数据,协议头都是被放在了skb->data到skb->tail之间,通过skb_push前移skb->data加入协议头,通过skb_pull后移skb->data剥离协议头。
sk_buf常用解析
struct sk_buff *sb = skb;
IP地址:- #define NIPQUAD(addr) \
- ((unsigned char *)&addr)[0], \
- ((unsigned char *)&addr)[1], \
- ((unsigned char *)&addr)[2], \
- ((unsigned char *)&addr)[3]
- #define NIPQUAD_FMT "%u.%u.%u.%u"
- __be sip, dip;
- struct iphdr *iph=ip_hdr(sb);
- sip=iph->saddr;
- dip=iph->daddr;
- printk("sip:%u.%u.%u.%u,dip:%u.%u.%u.%u\m",
- NIPQUAD(sip),NIPQUAD(dip));
复制代码
协议:- struct iphdr *iph=ip_hdr(sb);
- iph->protocol==IPPROTO_TCP
复制代码 端口:- struct iphdr *iph=ip_hdr(sb);
- struct tcphdr *tcph = NULL;
- struct udphdr *udph = NULL;
- unsigned short sport = 0;
- unsigned short dport = 0;
- if(iph->protocol==IPPROTO_TCP)
- {
- tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));
- sport=ntohs(tcph->source);
- dport=ntohs(tcph->dest);
- }
- else if(iph->protocal==IPPROTO_UDP)
- {
- udph = (struct udphdr *)((char *)skb->data + (int)(iph->ihl * 4));
- sport=ntohs(udph->source);
- dport=ntohs(udph->dest);
- }
复制代码 tcp的数据:- char *data = NULL;
- struct tcphdr *tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));;
- data = (char *)((int)tcph + (int)(tcph->doff * 4));
复制代码 ihl(Internet Header Length 报头长度),位于IP报文的第二个字段,4位,表示IP报文头部按32位字长(32位,4字节)计数的长度,也即报文头的长度等于IHL的值乘以4。
三个demo
一个是打印ip地址 一个是获取ftp账号密码 最后一个老外写一个获取ftp和修改数据的demo- //打印IP:
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/types.h>
- #include <linux/netdevice.h>
- #include <linux/skbuff.h>
- #include <linux/netfilter_ipv4.h>
- #include <linux/inet.h>
- #include <linux/in.h>
- #include <linux/ip.h>
- #include <linux/tcp.h>
- #include <linux/udp.h>
- #define NIPQUAD(addr) \
- ((unsigned char *)&addr)[0], \
- ((unsigned char *)&addr)[1], \
- ((unsigned char *)&addr)[2], \
- ((unsigned char *)&addr)[3]
- static unsigned int ipprint_func(
- unsigned int hooknum,
- struct sk_buff * skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn) (struct sk_buff *))
- {
- __be32 sip,dip;
- struct tcphdr *tcph = NULL;
- struct udphdr *udph = NULL;
- unsigned short sport = 0;
- unsigned short dport = 0;
- struct iphdr *iph;
- if(skb)
- {
- struct sk_buff *sb = NULL;
- sb = skb;
- iph = ip_hdr(sb);
- sip = iph->saddr;
- dip = iph->daddr;
- if(iph->protocol==IPPROTO_TCP)
- {
- tcph = (struct tcphdr *)((char *)skb->data + (int)(iph->ihl * 4));
- //tcph = tcp_hdr(sb);
- sport=ntohs(tcph->source);
- dport=ntohs(tcph->dest);
- }
- else if(iph->protocol==IPPROTO_UDP)
- {
- udph = (struct udphdr *)((char *)skb->data + (int)(iph->ihl * 4));
- //udph = udp_hdr(sb);
- sport=ntohs(udph->source);
- dport=ntohs(udph->dest);
- }
- printk("Packet for source address: %u.%u.%u.%u:%u destination address: %u.%u.%u.%u:%u\n ", NIPQUAD(sip),sport,NIPQUAD(dip),dport);
- }
- return NF_DROP;
- }
- struct nf_hook_ops ipprint_ops = {
- .list = {NULL,NULL},
- .hook = ipprint_func,
- .pf = PF_INET,
- //.hooknum = NF_INET_PRE_ROUTING,
- .hooknum = NF_INET_LOCAL_IN,
- .priority = NF_IP_PRI_FILTER+2
- };
- static int __init ipprint_init(void) {
- nf_register_hook(&ipprint_ops);
- return 0;
- }
- static void __exit ipprint_exit(void) {
- nf_unregister_hook(&ipprint_ops);
- }
- module_init(ipprint_init);
- module_exit(ipprint_exit);
- MODULE_AUTHOR("djwow");
- MODULE_DESCRIPTION("ipprint");
- MODULE_LICENSE("GPL");
复制代码
获取FTP账号密码: 结合通信的话可以参考我的另一篇文章
《linux防火墙开发实例 获取FTP账号密码》
6319521
Linux内核sk_buff结构分析
7415748
skb_buf结构分析
8797236
sk_buff结构分析
http://www.cnblogs.com/qq78292959/archive/2012/06/06/2538358.html |
|