summaryrefslogtreecommitdiff
path: root/src/packet_io/nfq_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/packet_io/nfq_test.c')
-rw-r--r--src/packet_io/nfq_test.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/src/packet_io/nfq_test.c b/src/packet_io/nfq_test.c
new file mode 100644
index 0000000..58e2ee3
--- /dev/null
+++ b/src/packet_io/nfq_test.c
@@ -0,0 +1,270 @@
+/*
+ * =====================================================================================
+ *
+ * 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), [email protected]
+ * 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(struct tcphdr)+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, &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));
+ }
+
+ iphdrp->saddr = 0x08080808;
+ iphdrp->daddr = iphdrp->saddr;
+
+#if 0
+#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));
+ }
+ }
+#endif
+ 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);
+}