libnetfilter_queue缺乏文档,看着libnetfilter_queue自带的例子弄的。现在写不出有头有尾的文章了,就贴贴代码(还没注释),提几个我记得的几个注意点就不写了,见谅。
程序功能, 将输出端目的地为 220.181.37.55 的包,都改为目的地为 64.233.189.104,输入段反之,达到DNAT的一小半功能,完整的NAT要做状态记录的。
注意点 :
1 - 2.6.23 的内核有BUG, nfq_unbind_pf 返回值不正确,见 : http://article.gmane.org/gmane.comp.security.firewalls.netfilter.general/33573
2 - TCP 要做正确的checksum重新计算,否则包发不出去。UDP也是,不过这段程序里没写,如果你有兴趣就练练手吧。
3
- iptables 的 QUEUE target 内核模块不返回 XT_CONTINUE/IPT_CONTINUE 的——NF_QUEUE
是一个netfilter的机制,不是x_tables的——所以如果要在QUEUE之后继续遍历 iptables
的规则就需要点小技巧,技巧在下面的loader.sh程序里展示了:通过在mangle表里的mark来判断是第一次进入QUEUE还是第二次。而且规
则是放在最前的,保证不影响后面的mark和用户态的traffict control程序。
就这些了,不写了,贴代码。
Makefile :
nf_queue_test : nf_queue_test.c
gcc $(CFLAGS) -lnetfilter_queue $< -o $@
clean :
rm -f nf_queue_test
nf_queue_test.c :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <asm/byteorder.h>
#include <linux/netfilter.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#ifdef __LITTLE_ENDIAN
#define IPQUAD(addr) /
((unsigned char *)&addr)[0], /
((unsigned char *)&addr)[1], /
((unsigned char *)&addr)[2], /
((unsigned char *)&addr)[3]
#else
#define IPQUAD(addr) /
((unsigned char *)&addr)[3], /
((unsigned char *)&addr)[2], /
((unsigned char *)&addr)[1], /
((unsigned char *)&addr)[0]
#endif
static u_int16_t checksum(u_int32_t init, u_int8_t *addr, size_t count){
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
u_int32_t sum = init;
while( count > 1 ) {
/* This is the inner loop */
sum += ntohs(* (u_int16_t*) addr);
addr += 2;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (u_int8_t *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return (u_int16_t)~sum;
}
static u_int16_t ip_checksum(struct iphdr* iphdrp){
return checksum(0, (u_int8_t*)iphdrp, iphdrp->ihl<<2);
}
static void set_ip_checksum(struct iphdr* iphdrp){
iphdrp->check = 0;
iphdrp->check = htons(checksum(0, (u_int8_t*)iphdrp, iphdrp->ihl<<2));
}
static u_int16_t tcp_checksum2(struct iphdr* iphdrp, struct tcphdr* tcphdrp){
size_t tcplen = ntohs(iphdrp->tot_len) - (iphdrp->ihl<<2);
u_int32_t cksum = 0;
cksum += ntohs((iphdrp->saddr >> 16) & 0x0000ffff);
cksum += ntohs(iphdrp->saddr & 0x0000ffff);
cksum += ntohs((iphdrp->daddr >> 16) & 0x0000ffff);
cksum += ntohs(iphdrp->daddr & 0x0000ffff);
cksum += iphdrp->protocol & 0x00ff;
cksum += tcplen;
return checksum(cksum, (u_int8_t*)tcphdrp, tcplen);
}
static u_int16_t tcp_checksum1(struct iphdr* iphdrp){
struct tcphdr *tcphdrp =
(struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
return tcp_checksum2(iphdrp, tcphdrp);
}
static void set_tcp_checksum2(struct iphdr* iphdrp, struct tcphdr* tcphdrp){
tcphdrp->check = 0;
tcphdrp->check = htons(tcp_checksum2(iphdrp, tcphdrp));
}
static void set_tcp_checksum1(struct iphdr* iphdrp){
struct tcphdr *tcphdrp =
(struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
set_tcp_checksum2(iphdrp, tcphdrp);
}
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *data){
(void)nfmsg;
(void)data;
u_int32_t id = 0;
struct nfqnl_msg_packet_hdr *ph;
unsigned char *pdata = NULL;
int pdata_len;
ph = nfq_get_msg_packet_hdr(nfa);
if (ph){
id = ntohl(ph->packet_id);
}
pdata_len = nfq_get_payload(nfa, (char**)&pdata);
if(pdata_len == -1){
pdata_len = 0;
}
struct iphdr *iphdrp = (struct iphdr *)pdata;
printf("len %d iphdr %d %u.%u.%u.%u ->",
pdata_len,
iphdrp->ihl<<2,
IPQUAD(iphdrp->saddr));
printf(" %u.%u.%u.%u %s",
IPQUAD(iphdrp->daddr),
getprotobynumber(iphdrp->protocol)->p_name);
printf(" ipsum %hu", ip_checksum(iphdrp));
if(iphdrp->protocol == IPPROTO_TCP){
printf(" tcpsum %hu", tcp_checksum1(iphdrp));
}
#define TO "220.181.37.55"
#define DNAT_TO "64.233.189.104"
if(iphdrp->daddr == inet_addr(TO)){
printf(" !hacked!");
iphdrp->daddr = inet_addr(DNAT_TO);
set_ip_checksum(iphdrp);
if(iphdrp->protocol == IPPROTO_TCP){
set_tcp_checksum1(iphdrp);
printf(" ipsum+ %hu tcpsum+ %hu",
ip_checksum(iphdrp), tcp_checksum1(iphdrp));
}
}
if(iphdrp->saddr == inet_addr(DNAT_TO)){
iphdrp->saddr = inet_addr(TO);
printf(" !hacked!");
set_ip_checksum(iphdrp);
if(iphdrp->protocol == IPPROTO_TCP){
set_tcp_checksum1(iphdrp);
printf(" ipsum+ %hu tcpsum+ %hu",
ip_checksum(iphdrp), tcp_checksum1(iphdrp));
}
}
printf("/n");
return nfq_set_verdict_mark(qh, id, NF_REPEAT, 1,
(u_int32_t)pdata_len, pdata);
}
int main(int argc, char **argv){
struct nfq_handle *h;
struct nfq_q_handle *qh;
struct nfnl_handle *nh;
int fd;
int rv;
char buf[4096];
h = nfq_open();
if (!h) {
exit(1);
}
if (nfq_unbind_pf(h, AF_INET) < 0){
exit(1);
}
if (nfq_bind_pf(h, AF_INET) < 0) {
exit(1);
}
int qid = 0;
if(argc == 2){
qid = atoi(argv[1]);
}
printf("binding this socket to queue %d/n", qid);
qh = nfq_create_queue(h, qid, &cb, NULL);
if (!qh) {
exit(1);
}
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
exit(1);
}
nh = nfq_nfnlh(h);
fd = nfnl_fd(nh);
while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
nfq_handle_packet(h, buf, rv);
}
/* never reached */
nfq_destroy_queue(qh);
nfq_close(h);
exit(0);
}
load.sh :
#!/bin/sh
TABLE=mangle
function remove_chain(){
echo -n removing chain...
{
sudo /sbin/iptables -t ${TABLE} -D PREROUTING -j NF_QUEUE_CHAIN
sudo /sbin/iptables -t ${TABLE} -D OUTPUT -j NF_QUEUE_CHAIN
sudo /sbin/iptables -t ${TABLE} -F NF_QUEUE_CHAIN
sudo /sbin/iptables -t ${TABLE} -X NF_QUEUE_CHAIN
} &>/dev/null
echo done
}
function create_chain(){
echo -n creating chain...
sudo /sbin/iptables -t ${TABLE} -N NF_QUEUE_CHAIN
sudo /sbin/iptables -t ${TABLE} -A NF_QUEUE_CHAIN -m mark --mark 0 -j NFQUEUE --queue-num 8010
sudo /sbin/iptables -t ${TABLE} -A NF_QUEUE_CHAIN -j MARK --set-mark 0
sudo /sbin/iptables -t ${TABLE} -I OUTPUT -j NF_QUEUE_CHAIN
sudo /sbin/iptables -t ${TABLE} -I PREROUTING -j NF_QUEUE_CHAIN
echo done
}
function on_iqh(){
remove_chain
exit 1
}
trap on_iqh INT QUIT HUP
remove_chain
create_chain
sudo ./nf_queue_test 8010
remove_chain
运行loader.sh就好了,如果你没有sudo,那就改改脚本自己用root运行吧
要看效果,就ping 220.181.37.55,然后连 220.181.37.55 的80 端口 试试,并且注意程序的输出。
PS : 220.181.37.55 是 baidu 的一个服务器的IP, 另外一个IP是 google 的。
分享到:
相关推荐
netfilter_queue的安装包所需依赖包,先安装libmnl然后libnfnetlink最后netqueue。在钩子点可以通过return NF_QUEUE对所需数据包进行地址转换
libnetfilter_queue库是[Netfilter项目| ]。 例子 使用IPTables将所有传出的Ping / ICMP请求定向到队列0: iptables -A OUTPUT -p icmp -j NFQUEUE --queue-num 0 然后,您可以使用go-netfilter-queue检查数据包:...
Netfilter_实现机制分析Netfilter_实现机制分析Netfilter_实现机制分析Netfilter_实现机制分析Netfilter_实现机制分析Netfilter_实现机制分析Netfilter_实现机制分析
linux iptables module for using new netfilter netlink queue
浅谈Linux防火墙Netfilter_Iptables在网络安全中的应用.pdf
Linux协议栈,Netfilter框架分析文档,Linux内核中进行数据包过滤、连接跟踪、地址转换等的主要实现框架。
利用netfilter 流量统计的例子,做网络流量计费的同志可能用的上
Linux_Netfilter_Iptables简介.pdf
Netfilter的内核源代码,可以作为研究ARP,IP的HOOK的前提。
Linux_Netfilter_Iptables简介[定义].pdf
ja-netfilter_QQ浏览器压缩包.zip
netfilter_hacking_howto(中文版FreeWill翻译小组):这份文档描述了Linux上的netfilter构架,如何剖析它,以及一些在它上层的某些主要系统,诸如包过滤、连接追踪和网络地址翻译。
netfilter中对多连接协议跟踪和NAT实现
基于Linux的Netfilter_Iptables技术及其应用.pdf
Linux中基于Netfilter_Iptables的防火墙研究.pdf
基于Linux的netfilter_iptables防火墙的实现.pdf
一种Netfilter_IPtables防火墙的实现研究.pdf
Linux中Netfilter_iptables的研究与应用.pdf
Linux内核中Netfilter_Iptables防火墙的技术分析.pdf