偶尔在网上看到了这篇文章,
并结合中的例子,
然后修改了一下tcp计算checksum部分,在linux2.6.24上用netfilter_queue在用户态实现NAT
程序功能: 将输出端目的地为 220.181.37.55 的包,都改为目的地为 202.118.236.130,输入段反之,达到DNAT的一小半功能,完整的NAT要做状态记录的.
直接上代码:
nf_queue_test.c
-
/*
-
* =====================================================================================
-
*
-
* Filename: nf_queue_test.c
-
*
-
* Description: 用netfilter_queue 在用户态修改网络数据包的例子程序
-
*
-
* Version: 1.0
-
* Created: 04/02/2010 09:49:48 AM
-
* Revision: none
-
* Compiler: gcc
-
*
-
* Author: LeiuX (xulei), xulei@pact518.hit.edu.cn
-
* Company: HIT
-
*
-
* =====================================================================================
-
*/
-
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <netdb.h>
-
#include <string.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
-
-
struct tcp_pseudo /*the tcp pseudo header*/
-
{
-
__u32 src_addr;
-
__u32 dst_addr;
-
__u8 zero;
-
__u8 proto;
-
__u16 length;
-
} pseudohead;
-
-
-
long checksum(unsigned short *addr, unsigned int count) {
-
/* Compute Internet Checksum for "count" bytes
-
* beginning at location "addr".
-
*/
-
register long sum = 0;
-
-
while( count > 1 ) {
-
/* This is the inner loop */
-
sum += * addr++;
-
count -= 2;
-
}
-
/* Add left-over byte, if any */
-
if( count > 0 )
-
sum += * (unsigned char *) addr;
-
-
/* Fold 32-bit sum to 16 bits */
-
while (sum>>16)
-
sum = (sum & 0xffff) + (sum >> 16);
-
-
return ~sum;
-
}
-
-
-
/*************************tcp checksum**********************/
-
long get_tcp_checksum(struct iphdr * myip, struct tcphdr * mytcp) {
-
-
__u16 total_len = ntohs(myip->tot_len);
-
-
int tcpopt_len = mytcp->doff*4 - 20;
-
int tcpdatalen = total_len - (mytcp->doff*4) - (myip->ihl*4);
-
-
pseudohead.src_addr=myip->saddr;
-
pseudohead.dst_addr=myip->daddr;
-
pseudohead.zero=0;
-
pseudohead.proto=IPPROTO_TCP;
-
pseudohead.length=htons(sizeof(struct tcphdr) + tcpopt_len + tcpdatalen);
-
-
int totaltcp_len = sizeof(struct tcp_pseudo) + sizeof(struct tcphdr) + tcpopt_len +tcpdatalen;
-
//unsigned short * tcp = new unsigned short[totaltcp_len];
-
-
unsigned short * tcp = malloc(totaltcp_len);
-
-
-
memcpy((unsigned char *)tcp,&pseudohead,sizeof(struct tcp_pseudo));
-
memcpy((unsigned char *)tcp+sizeof(struct tcp_pseudo),(unsigned char*)mytcp,sizeof(struct tcphdr));
-
memcpy((unsigned char *)tcp+sizeof(struct tcp_pseudo)+sizeof(struct tcphdr),(unsigned char *)myip+(myip->ihl*4)+(sizeof(struct tcphdr)), tcpopt_len);
-
memcpy((unsigned char *)tcp+sizeof(struct tcp_pseudo)+sizeof(structtcphdr)+tcpopt_len, (unsigned char *)mytcp+(mytcp->doff*4), tcpdatalen);
-
-
/* printf("pseud length: %d\n",pseudohead.length);
-
printf("tcp hdr length: %d\n",mytcp->doff*4);
-
printf("tcp hdr struct length: %d\n",sizeof(struct tcphdr));
-
printf("tcp opt length: %d\n",tcpopt_len);
-
printf("tcp total+psuedo length: %d\n",totaltcp_len);
-
-
fflush(stdout);
-
-
printf("tcp data len: %d, data start %u\n", tcpdatalen,mytcp + (mytcp->doff*4));
-
*/
-
-
-
return checksum(tcp,totaltcp_len);
-
-
}
-
-
static u_int16_t tcp_checksum(struct iphdr* iphdrp){
-
struct tcphdr *tcphdrp =
-
(struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
-
return get_tcp_checksum(iphdrp, tcphdrp);
-
}
-
-
static void set_tcp_checksum(struct iphdr* iphdrp){
-
struct tcphdr *tcphdrp =
-
(struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
-
tcphdrp->check = 0;
-
tcphdrp->check = get_tcp_checksum(iphdrp, tcphdrp);
-
}
-
/****************************tcp checksum end****************************/
-
-
-
/********************************Ip checksum*****************************/
-
static u_int16_t ip_checksum(struct iphdr* iphdrp){
-
return checksum((unsigned short*)iphdrp, iphdrp->ihl<<2);
-
}
-
-
static void set_ip_checksum(struct iphdr* iphdrp){
-
iphdrp->check = 0;
-
iphdrp->check = checksum((unsigned short*)iphdrp, iphdrp->ihl<<2);
-
}
-
/****************************Ip checksum end******************************/
-
-
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_checksum(iphdrp));
-
}
-
-
#define TO "220.181.37.55"
-
#define DNAT_TO "202.118.236.130"
-
-
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_checksum(iphdrp);
-
printf(" ipsum+ %hu tcpsum+ %hu",
-
ip_checksum(iphdrp), tcp_checksum(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_checksum(iphdrp);
-
printf(" ipsum+ %hu tcpsum+ %hu",
-
ip_checksum(iphdrp), tcp_checksum(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);
-
}
-
-
nfq_unbind_pf(h, AF_INET);
-
-
/*2.6.24 的内核有BUG, nfq_unbind_pf 返回值不正确,
-
见:http://article.gmane.org/gmane.c ... ilter.general/33573*/
-
-
/*
-
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);
-
}
阅读(1167) | 评论(0) | 转发(0) |