Skip to content

Instantly share code, notes, and snippets.

@fqrouter
Created April 16, 2011 18:00
Show Gist options
  • Save fqrouter/923347 to your computer and use it in GitHub Desktop.
Save fqrouter/923347 to your computer and use it in GitHub Desktop.
dnsproxycn的服务器
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <map>
#include <string>
using namespace std;
#define MAXSOCKET 10
#define MINDELAY 500
#define MAXDELAY 2000
#define IP6HOSTFILE "ip6hosts.txt"
std::map <string, string> ip6Table;
typedef struct _UDPSOCK_INFO
{
SOCKET UDPSocket;
SOCKADDR_STORAGE UDPFrom;
SOCKADDR_IN UDPTo;
char SendBuffer[1024];
int SendBufferLen;
int gettimes;
DWORD start, end;
}UDPSOCK_INFO, *PUDPSOCK_INFO;
//DNS header structure
struct DNS_HEADER
{
unsigned short id; // identification number
unsigned char rd :1; // recursion desired
unsigned char tc :1; // truncated message
unsigned char aa :1; // authoritive answer
unsigned char opcode :4; // purpose of message
unsigned char qr :1; // query/response flag
unsigned char rcode :4; // response code
unsigned char cd :1; // checking disabled
unsigned char ad :1; // authenticated data
unsigned char z :1; // its z! reserved
unsigned char ra :1; // recursion available
unsigned char q_count_h; // number of question entries
unsigned char q_count_l; // number of question entries
unsigned char ans_count_h; // number of answer entries
unsigned char ans_count_l; // number of answer entries
unsigned char auth_count_h; // number of authority entries
unsigned char auth_count_l; // number of authority entries
unsigned char add_count_h; // number of resource entries
unsigned char add_count_l; // number of resource entries
};
#pragma pack(push, 1)
struct RES_RECORD
{
char name[2];
unsigned char type_h;
unsigned char type_l;
unsigned char _class_h;
unsigned char _class_l;
unsigned char ttl_hh;
unsigned char ttl_h;
unsigned char ttl_l;
unsigned char ttl_ll;
unsigned char data_len_h;
unsigned char data_len_l;
in6_addr i6addr;
};
#pragma pack(pop)
void CreateIP6Table ();
int CheckIP6 ( char*, in6_addr* );
int main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET DNSUDP;
SOCKADDR_IN UDPAddr_in;
struct fd_set fds_read, fds_write;
struct timeval timeout;
int selectret, i;
UDPSOCK_INFO UDPSock[MAXSOCKET];
CreateIP6Table();
// Initialize Winsock version 2.2
if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("Server: WSAStartup failed with error %ld\n", WSAGetLastError());
return -1;
}
DNSUDP = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (DNSUDP == INVALID_SOCKET)
{
printf("Server: Error at udp socket(): %ld\n", WSAGetLastError());
WSACleanup();
return -1;
}
UDPAddr_in.sin_family = AF_INET;
UDPAddr_in.sin_port = htons(53);
UDPAddr_in.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(DNSUDP, (SOCKADDR *)&UDPAddr_in, sizeof(UDPAddr_in)) == SOCKET_ERROR)
{
printf("Server: udp bind() failed! Error: %ld.\n", WSAGetLastError());
closesocket(DNSUDP);
WSACleanup();
return -1;
}
printf("DNS Proxy Starting...\n");
for ( i=0; i<MAXSOCKET; i++)
UDPSock[i].UDPSocket = INVALID_SOCKET;
timeout.tv_sec = 0;
timeout.tv_usec = 100;
while (true)
{
FD_ZERO(&fds_read);
FD_ZERO(&fds_write);
FD_SET(DNSUDP, &fds_read);
for (i=0; i<MAXSOCKET; i++)
{
if (UDPSock[i].UDPSocket != INVALID_SOCKET)
FD_SET(UDPSock[i].UDPSocket, &fds_read);
}
selectret = select(0, &fds_read, &fds_write, 0, &timeout);
switch (selectret)
{
case 0:
// Timed out, do whatever you want to handle this situation
//printf("Server: Timeout while waiting !...\n");
break;
case SOCKET_ERROR:
printf("Server: Some error encountered with code number: %ld\n", WSAGetLastError());
break;
default:
if (FD_ISSET(DNSUDP, &fds_read)!=0)
{
char Buffer[1024];
SOCKADDR_STORAGE from;
int fromlen, bytecount, sockNo;
fromlen = sizeof(SOCKADDR_STORAGE);
bytecount = recvfrom(DNSUDP, Buffer, 1024, 0, (SOCKADDR *)&from, &fromlen);
//printf("read %d bytes from client\n", bytecount);
if (bytecount > 0)
{
sockNo = 10000;
for (i=0; i<MAXSOCKET; i++)
{
if (UDPSock[i].UDPSocket == INVALID_SOCKET)
{
sockNo = i;
break;
}
}
if (sockNo != 10000)
{
UDPSock[sockNo].UDPFrom = from;
UDPSock[sockNo].SendBufferLen = bytecount;
int j;
for (j=0; j< bytecount; j++)
{
UDPSock[sockNo].SendBuffer[j] = Buffer[j];
//printf("%02X ", (unsigned char)Buffer[j]);
}
//printf("\n");
//for (j=0; j< bytecount; j++)
//{
// if (Buffer[j] < 0x20) printf(". "); else printf("%c ", Buffer[j]);
//}
//printf("\n");
UDPSock[sockNo].UDPSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (UDPSock[sockNo].UDPSocket == INVALID_SOCKET)
{
printf("Server: Error at udp socket(), error code: %ld.\n", WSAGetLastError());
}
else
{
//printf("Server: udp socket(%d) is OK!\n", sockNo);
////////////////////////////////////////////////////////////////////
in6_addr i6addr;
int ret = CheckIP6( Buffer, &i6addr );
if (ret!=0)
{
struct DNS_HEADER *dns = NULL;
struct RES_RECORD *rr = NULL;
dns = (struct DNS_HEADER *)&Buffer;
dns->qr = 1;
dns->ra = 1;
dns->ans_count_h = 0;
dns->ans_count_l = 1;
rr = (struct RES_RECORD *)&Buffer[bytecount];
rr->name[0]=(char)0xc0;
rr->name[1]=(char)0x0c;
rr->type_h = 0;
rr->type_l = 28;
rr->_class_h = 0;
rr->_class_l = 1;
rr->ttl_hh = 0x3f;
rr->ttl_h = 0xff;
rr->ttl_l = 0xff;
rr->ttl_ll = 0xff;
rr->data_len_h = 0;
rr->data_len_l = 16;
rr->i6addr = i6addr;
bytecount += 28;
//for (j=0; j< bytecount; j++)
//{
// printf("%02X ", (unsigned char)Buffer[j]);
//}
//printf("\n");
for (j=0; j< bytecount; j++)
{
UDPSock[sockNo].SendBuffer[j] = Buffer[j];
}
UDPSock[sockNo].SendBufferLen = bytecount;
UDPSock[sockNo].start = GetTickCount();
UDPSock[sockNo].end = UDPSock[sockNo].start;
UDPSock[sockNo].gettimes = 100;
}
////////////////////////////////////////////////////////////////////
else
{
UDPAddr_in.sin_family = AF_INET;
UDPAddr_in.sin_addr.s_addr = (rand()>=16384)?inet_addr( "8.8.8.8" ):inet_addr("8.8.4.4");
//UDPAddr_in.sin_addr.s_addr = inet_addr( "8.8.8.8" );
UDPAddr_in.sin_port = htons( 53 );
UDPSock[sockNo].UDPTo = UDPAddr_in;
// Connect to server.
if (sendto(UDPSock[sockNo].UDPSocket, UDPSock[sockNo].SendBuffer, UDPSock[sockNo].SendBufferLen, 0, (SOCKADDR *)&UDPAddr_in, sizeof(UDPAddr_in))==-1)
{
printf( "Failed to sendto(), error code: %ld.\n", WSAGetLastError());
closesocket(UDPSock[sockNo].UDPSocket);
UDPSock[sockNo].UDPSocket=INVALID_SOCKET;
}
else
{
UDPSock[sockNo].start = GetTickCount();
UDPSock[sockNo].end = UDPSock[sockNo].start;
UDPSock[sockNo].gettimes = 0;
}
}
}
}
}
}
for (i=0; i<MAXSOCKET; i++)
{
if ((FD_ISSET(UDPSock[i].UDPSocket, &fds_read)!=0))
{
char Buffer[1024];
int bytecount;
int fromlen;
fromlen = sizeof(SOCKADDR_STORAGE);
bytecount = recvfrom(UDPSock[i].UDPSocket, Buffer, 1024, 0, (SOCKADDR *)&UDPSock[i].UDPTo, &fromlen);
UDPSock[i].end = GetTickCount();
UDPSock[i].gettimes ++;
//printf("Read from DNS server! byte:%d\n", bytecount);
if(bytecount>0)
{
UDPSock[i].SendBufferLen = bytecount;
int j;
for ( j=0; j<bytecount; j++)
{
UDPSock[i].SendBuffer[j] = Buffer[j];
//printf("%02X ", (unsigned char)Buffer[j]);
}
//printf("\n");
//for ( j=0; j<bytecount; j++)
// if (Buffer[j]<0x20) printf(". "); else printf("%c ",Buffer[j]);
//printf("\n");
}
else
{
closesocket(UDPSock[i].UDPSocket);
UDPSock[i].UDPSocket = INVALID_SOCKET;
}
}
}
break;
}
for (i=0; i<MAXSOCKET; i++)
{
DWORD tmnow;
DWORD delay;
if (UDPSock[i].UDPSocket != INVALID_SOCKET)
{
tmnow = GetTickCount();
delay = tmnow - UDPSock[i].start;
if (UDPSock[i].gettimes > 0)
{
if ( (delay > MINDELAY)||(UDPSock[i].gettimes==100) )
{
int fromlen = sizeof(SOCKADDR_STORAGE);
int ret = sendto(DNSUDP, UDPSock[i].SendBuffer, UDPSock[i].SendBufferLen, 0, (SOCKADDR *)&UDPSock[i].UDPFrom, fromlen);
//if (UDPSock[i].gettimes > 1)
//{
if (UDPSock[i].gettimes == 100)
printf("used %dms, !! local force ipv6 !!\t", delay);
else
printf("used %dms, got %d UDP(s) in %dms\t", delay, UDPSock[i].gettimes, UDPSock[i].end - UDPSock[i].start );
int j;
//for ( j=0; j<UDPSock[i].SendBufferLen; j++)
//{
// printf("%02X ", (unsigned char)UDPSock[i].SendBuffer[j]);
//}
//printf("\n");
//for ( j=0; j<UDPSock[i].SendBufferLen; j++)
// if (UDPSock[i].SendBuffer[j]<0x20) printf(". "); else printf("%c ",UDPSock[i].SendBuffer[j]);
//printf("\n");
j = 13;
while (UDPSock[i].SendBuffer[j] != 0 )
{
if (UDPSock[i].SendBuffer[j]<0x20) printf("."); else printf("%c", UDPSock[i].SendBuffer[j]);
j++;
}
printf("\n");
//}
closesocket(UDPSock[i].UDPSocket);
UDPSock[i].UDPSocket = INVALID_SOCKET;
}
}
else
{
if ( delay > MAXDELAY )
{
printf("overtime! used %dms, got %d UDP\t", delay, UDPSock[i].gettimes);
int j = 13;
while (UDPSock[i].SendBuffer[j] != 0 )
{
if (UDPSock[i].SendBuffer[j]<0x20) printf("."); else printf("%c", UDPSock[i].SendBuffer[j]);
j++;
}
printf("\n");
closesocket(UDPSock[i].UDPSocket);
UDPSock[i].UDPSocket = INVALID_SOCKET;
}
}
}
}
}
printf("Server: Finished receiving. Closing the socket...\n");
if (closesocket(DNSUDP) != 0)
printf("Server: udp closesocket() failed! Error code: %ld\n", WSAGetLastError());
else
printf("Server: udp closesocket() is OK...\n");
printf("Server: Cleaning up...\n");
if(WSACleanup() != 0)
printf("Server: WSACleanup() failed! Error code: %ld\n", WSAGetLastError());
else
printf("Server: WSACleanup() is OK\n");
return 0;
}
///////////////////////////////////////////////////////////
void CreateIP6Table ()
{
FILE *IP6File;
char filename[255], line[255], addr[100], hostname[100];
int ret;
ret = GetCurrentDirectory(255, filename);
strcat_s ( filename, 255, "\\");
strcat_s ( filename, 255, IP6HOSTFILE);
//printf("%s\n", filename);
ret = fopen_s( &IP6File, filename, "r");
if (ret != 0)
{
printf("open ip6 hosts file failure!\n");
return;
}
//printf("ip6 table creating...\n\n");
while(fgets(line,sizeof(line),IP6File))
{
int index, num, len ;
num = 0; index = 0;
len = strlen(line);
if ( (len>0) && (line[0]!='#') && (isspace(line[0])==0) )
{
//while ( (index<len)&&(isspace(line[index])!= 0) ) index++;
while ( (index<len)&&(isspace(line[index])== 0) ) addr[num++] = line[index++];
addr[num]='\0';
while ( (index<len)&&(isspace(line[index])!= 0) ) index++;
num = 0;
while ( (index<len)&&(isspace(line[index])== 0) ) hostname[num++] = line[index++];
hostname[num]='\0';
//printf("%s\t%s\n", addr, hostname);
ip6Table.insert( pair <string, string> (hostname, addr));
}
}
/*
map<string,string>::iterator p;
strcpy_s(hostname, 100, "www.google.com");
p = ip6Table.find(hostname);
if (p != ip6Table.end())
strcpy_s(addr, 100, (*p).second.c_str());
printf("%s\n", addr);
*/
fclose(IP6File);
//printf("ip6 table created.\n\n");
}
int CheckIP6(char* Buffer, in6_addr* i6addr)
{
int ret, i, dot;
char hostname[100], addr[100];
i=13; dot=0;
while ( Buffer[i] != 0 )
{
if (Buffer[i]<0x20)
{
hostname[i-13]='.';
dot++;
}
else hostname[i-13] = Buffer[i];
i++;
}
hostname[i-13]='\0';
addr[0]='\0';
map<string,string>::iterator p;
p = ip6Table.find(hostname);
if (p == ip6Table.end())
{
if (dot>1)
{
int j;
i=0; j=0;
hostname[j]='*'; j++;
while ( hostname[i]!='.') i++;
while ( hostname[i]!='\0') hostname[j++]=hostname[i++];
hostname[j] = '\0';
p = ip6Table.find(hostname);
}
else return 0;
}
if (p != ip6Table.end())
{
strcpy_s(addr, 100, (*p).second.c_str());
//printf("%s %s\n", hostname, addr);
sockaddr_in6 saddr;
int saddrLen = sizeof(saddr);
ret = WSAStringToAddress(addr, AF_INET6, NULL, (LPSOCKADDR)&saddr, &saddrLen);
if (ret != 0)
{
printf("wsastringtoaddress failure! Error code: %ld\n", WSAGetLastError());
return 0;
}
else
{
*i6addr = saddr.sin6_addr;
return 1;
}
}
else
{
return 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment