/* * ===================================================================================== * * 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); } |