前置知识:
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个地方可以拦截
图很清楚的说明了在对应的位置能干什么
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_F