From ffecbd4534de67b85946fc4c2e82fc714038df16 Mon Sep 17 00:00:00 2001
From: Sergey Lapin <slapin@slind.org>
Date: Sun, 13 Apr 2008 20:36:00 +0400
Subject: [PATCH] Cleaned realtek version

---
 src/Makefile.am   |    2 +-
 src/alpha_regex.c |   98 ++++++++++++++++++++++
 src/common.c      |  193 ++++++++++++++++++++++++++++++++++++++++++-
 src/common.h      |   24 +++++-
 src/dns.c         |    2 -
 src/main.c        |   10 ++-
 src/realtek_api.c |  235 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/relay.c       |    1 +
 src/udp.c         |   92 +++++++++++++++++++++-
 11 files changed, 657 insertions(+), 15 deletions(-)
 create mode 100644 Makefile
 create mode 100644 src/.gitignore
 create mode 100644 src/alpha_regex.c
 create mode 100644 src/realtek_api.c

diff --git a/src/Makefile.am b/src/Makefile.am
index ad3fe10..1716cdc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
 sbin_PROGRAMS = dnrd
-dnrd_SOURCES = args.c args.h cache.c cache.h common.c common.h dns.c dns.h lib.c lib.h main.c master.c master.h query.c query.h relay.c relay.h sig.c sig.h tcp.c tcp.h udp.c udp.h srvnode.h srvnode.c domnode.c domnode.h standard.h rand.h rand.c qid.h qid.c check.c check.h
+dnrd_SOURCES = args.c args.h cache.c cache.h common.c common.h dns.c dns.h lib.c lib.h main.c master.c master.h query.c query.h relay.c relay.h sig.c sig.h tcp.c tcp.h udp.c udp.h srvnode.h srvnode.c domnode.c domnode.h standard.h rand.h rand.c qid.h qid.c check.c check.h realtek_api.c alpha_regex.c
 dnrd_LDADD = @THREAD_LIBS@
 INCLUDES = @THREAD_CFLAGS@
diff --git a/src/alpha_regex.c b/src/alpha_regex.c
new file mode 100644
index 0000000..0e840d3
--- /dev/null
+++ b/src/alpha_regex.c
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <stdlib.h>	     /* exit() */
+#include <string.h>	     /* for strncpy() */
+#include <sys/types.h>   /* needed by regex */
+#include <regex.h>       /* regular expression library */
+#include "common.h"
+
+//++++ Stanley add for domain match 2005.10.03
+#define nmatch  1
+/* here the sample regular expression is defined. For more information
+   about POSIX regular expressions you can use "man 7 regex" for a 
+   complete description, or google for POSIX regex and get more than
+   you want... 
+
+       [[:graph:]]*  this matches any printable character except space. 
+          (+ means one or more).
+*/
+static char *firstdotreg = "[[:graph:]][[:graph:]]*\\.";
+static char *starreg = "[a-zA-Z0-9_][a-zA-Z0-9_\\-]*";
+static char *dotreg = "\\.";
+/*
+    strcreg: string convert regular expression
+    For example
+
+	string		regular expression
+	--------------------------------------------
+	.com		^[[:graph:]][[:graph:]]*\.com$
+	.abc.com	^[[:graph:]][[:graph:]]*\.abc\.com$
+	www.abc.com	^abc\.com$
+	www.*.*.jp	^www\.[a-zA-Z0-9_][a-zA-Z0-9_\\-]*\.[a-zA-Z0-9_][a-zA-Z0-9_\\-]*\.jp$
+*/
+int strcreg(char *str, char *regex)
+{
+  char *ptr;
+
+  if(str==NULL) return 0;
+
+  ptr=str;
+  /* ^  matches the beginning of the string. */
+  strcat(regex,"^");
+  // first char is dot
+  if (*ptr=='.')
+  {
+    strcat(regex,firstdotreg);
+    ptr++;
+  }
+
+  for (;*ptr!='\0';ptr++)
+  {
+    /* replace star(*) and dot(.) to a properly regular expression */
+    if (*ptr=='*')
+    {
+      strcat(regex,starreg);
+      continue;
+    }
+    else if (*ptr=='.')
+    {
+      strcat(regex,dotreg);
+      continue;
+    }
+    regex[strlen(regex)]=*ptr;
+  }
+
+  /* The $ matches the end of the string. */
+  strcat(regex,"$");
+  return 1;
+}
+
+/* request compare with key, return 1 if match */
+int reg_match(const char *key, char *request)
+{
+  regex_t preg;
+  regmatch_t pmatch[nmatch];
+  int ret=0;
+  char *regex = key;
+
+  bzero(&preg,sizeof(regex_t));
+
+  /* compile a regular expression into a form that is
+       suitable for subsequent regexec searches.
+  */
+  if(regcomp(&preg,regex,REG_ICASE)==0)
+  {
+    // searching match
+    if(regexec(&preg,request,nmatch,pmatch,0)==0)
+      ret=1;
+    else
+      ret=0;
+
+#ifdef DNRD_DEBUG
+    fprintf(stderr,ret?"Match!\n":"No Match!\n");
+#endif
+    regfree(&preg);
+    return ret;
+  }
+  fprintf(stderr,"reg_match() fatal error!\n");
+  return 0;
+}
diff --git a/src/common.c b/src/common.c
index a1d90af..a69276a 100644
--- a/src/common.c
+++ b/src/common.c
@@ -36,7 +36,7 @@
 #include "lib.h"
 
 
-#ifdef DEBUG
+#ifdef DNRD_DEBUG
 #define OPT_DEBUG 1
 #else
 #define OPT_DEBUG 0
@@ -49,7 +49,7 @@
 int                 opt_debug = OPT_DEBUG;
 int                 opt_serv = 0;
 const char*         progname = 0;
-
+struct slist_t *	keylist = NULL;
 #ifdef ENABLE_PIDFILE
 #if defined(__sun__)
 const char*         pid_file = "/var/tmp/dnrd.pid";
@@ -191,6 +191,7 @@ int kill_current()
  * Sends a message to stdout or stderr if attached to a terminal, otherwise
  * it sends a message to syslog.
  */
+#ifdef DNRD_DEBUG
 void log_msg(int type, const char *fmt, ...)
 {
     va_list ap;
@@ -232,8 +233,7 @@ void log_msg(int type, const char *fmt, ...)
 void log_debug(int level, const char *fmt, ...)
 {
     va_list ap;
-    
-    if (opt_debug < level) return;
+    //if (opt_debug < level) return;
 
     va_start(ap, fmt);
     if (gotterminal) {
@@ -246,6 +246,7 @@ void log_debug(int level, const char *fmt, ...)
     }
     va_end(ap);
 }
+#endif
 
 /*
  * cleanexit()
@@ -273,6 +274,17 @@ void cleanexit(int status)
     }
     */
     destroy_domlist(domain_list);
+    {
+    	struct slist_t * sl;
+    	while (keylist)
+		{
+			sl = keylist;
+			keylist = sl->next;
+			if (sl->string) free(sl->string);
+			if (sl->cname) free(sl->cname);
+			free(sl);
+		} 	
+    }
     exit(status);
 }
 
@@ -376,3 +388,176 @@ char *cname2asc(const char *cname) {
     strncpy(buf, "(default)", sizeof(buf));
   return buf;
 }
+//joel policy rt todo  add domain and dns ser ip
+/* convert_name_string */
+domnode_t *g_policyRT_domnode=NULL;
+int NeedAddPolicyRoute(domnode_t *dom)
+{
+	if(g_policyRT_domnode==dom)
+	{
+		return 1;
+	}
+	else
+		return 0;
+}
+
+char * convert_name_string(const char * text)
+{
+	const char * tptr = text;
+	const char * end;
+	char * cname = (char *)malloc(strlen(text) + 4);
+	char * cptr = cname;
+	int dot=0;
+
+	memset(cname, 0, strlen(text)+4);
+
+	while (*tptr)
+	{
+		size_t diff;
+
+		if (*tptr == '.')
+		{
+			tptr++;
+			dot = 0x80;
+		}
+		else
+		{
+			dot = 0;
+		}
+		end = strchr(tptr, '.');
+		if (end == NULL) end = text + strlen(text);
+		if (end < tptr + 2)
+		{
+			free(cname);
+			return NULL;
+		}
+		
+		if (*(end-1) == '/') end--;
+
+		diff = end - tptr;
+		*cptr++ = diff | dot;
+		memcpy(cptr, tptr, diff);
+		cptr += diff;
+		if (*end == '/')
+		{
+			*cptr++ = 0xff;
+			*cptr = '\0';
+			break;
+		}
+		if (*end) tptr = end+1;
+		else tptr = end;
+	}
+	*cptr = '\0';
+	return cname;
+} 
+
+//+++joel 2004/11/4 09:13¤U¤È for read server ip from file 
+int addDnsSerFromFile(void)
+{
+    FILE *sf = NULL; 
+    domnode_t *p; 
+    int serv_cnt=0,serv2_cnt=0,dom_cnt=0;
+    char tmp[30]; 
+    char *pname="PRT";
+    int ptr; 
+    char *serv_file="/var/run/dnrd.serv";
+    int mode=0;
+    sf = fopen(serv_file, "r"); 
+    if (!sf)
+	{
+		log_msg(LOG_ERR, "%s: Server List file does not exist!\n", progname);
+		return 0;
+	}
+	if ((p=search_domnode(domain_list, pname)) == NULL && !g_policyRT_domnode) 
+	{
+		g_policyRT_domnode=add_domain(domain_list, 0, pname, 200);
+		g_policyRT_domnode->roundrobin=0;
+		p=g_policyRT_domnode;
+		log_debug(1, "Added domain %s without load balancing", pname);
+	}
+	else 
+	{
+		log_debug(1, "Could not add domain %s ", pname);
+	}
+	bzero(tmp, sizeof(tmp));
+	while ((ptr = fscanf(sf,"%s",tmp)) != EOF)
+	{ 
+        if (tmp[0] == '\0')
+		continue; 
+		if(!strcmp(tmp,"dns1_"))
+		{
+	        mode=0;
+	        continue; 
+		}
+		else if(!strcmp(tmp,"dns2_"))
+		{
+			mode=1;
+			continue; 
+		}
+		else if(!strcmp(tmp,"domain_"))
+		{
+			mode=2;
+			continue; 
+		}
+		
+		switch (mode)
+		{
+			case 1:
+			if (!add_srv(p->srvlist, tmp)) {
+		      log_debug(5, "%s: Bad ip address \"%s\"\n",
+			      progname, tmp);
+		      //exit(-1);
+		      continue;
+		    }
+		    else
+		    {
+		        log_debug(5,"add dnrd 2nd ser ip %s\n",tmp);
+		        serv2_cnt++;
+		    }
+		    break;
+		    case 2:
+		    {
+				struct slist_t * sl = malloc(sizeof(struct slist_t));
+				if (sl)
+				{
+					char regex[1000];
+					memset(sl, 0, sizeof(struct slist_t));
+					memset(regex,0,sizeof(regex));
+					sl->cname = convert_name_string(tmp); 
+					strcreg(tmp, regex); // convert rule to regular expression
+					sl->string = strdup(regex);
+					sl->slen = strlen(sl->string);
+					sl->next = keylist;
+					keylist = sl;
+					log_debug(5,"doamin add %s  reg=%s\n",tmp,sl->string);
+				}
+				dom_cnt++;
+			}
+		    break;
+		    case 0:
+		    default:
+		    if (!add_srv(last_srvnode(domain_list->srvlist), tmp)) {
+		      log_debug(5, "%s: Bad ip address \"%s\"\n",
+			      progname, tmp);
+		      //exit(-1);
+		      continue;
+		    }
+		    else
+		    {
+		        log_debug(5,"add dnrd 1st ser ip %s\n",tmp);
+		        serv_cnt++;
+		    }
+		    break;	
+		}
+	}
+    fclose(sf);
+    //for get shm mem
+#ifdef HAVE_DOMAIN_POLICY_ROUTE
+	getRomePtr();
+	init_cached_policyRoute();
+#endif
+	log_debug(5,"get %d dns1 and %d dns2 server ip, %d domain to switch2\n",serv_cnt,serv2_cnt,dom_cnt);
+	
+	return 1;
+}
+//---
diff --git a/src/common.h b/src/common.h
index 7e52a68..c0c2183 100644
--- a/src/common.h
+++ b/src/common.h
@@ -106,12 +106,17 @@ extern fd_set fdmaster;
 
 /* kill any currently running copies of dnrd */
 int kill_current();
-
+//#define DNRD_DEBUG
+#ifdef DNRD_DEBUG
 /* print messages to stderr or syslog */
 void log_msg(int type, const char *fmt, ...);
-
 /* same, but only if debugging is turned on */
 void log_debug(int level, const char *fmt, ...);
+#else
+#define log_msg(fmt,args...)		do{} while(0)
+#define log_debug(fmt,args...)		do{} while(0)
+int dump_dnspacket(char *type, unsigned char *packet, int len);
+#endif
 
 /* cleanup everything and exit */
 void cleanexit(int status);
@@ -126,6 +131,17 @@ char *cname2asc(const char *cname);
 
 /* Dumping DNS packets */
 int dump_dnspacket(char *type, unsigned char *packet, int len);
-
-
+struct slist_t
+{
+	struct slist_t *		next;
+	char *					string;
+	char *					cname;
+	int						slen;
+};
+extern domnode_t *g_policyRT_domnode;
+extern struct slist_t *	keylist;
+//++++ Stanley add for domain match 2005.10.04
+extern int strcreg(char *str, char *regex);
+extern int reg_match(const char *key, char *request);
+//---- Stanley
 #endif  /* _DNRD_COMMON_H_ */
diff --git a/src/dns.c b/src/dns.c
index 57b0c8a..98e5851 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -413,5 +413,3 @@ unsigned char *parse_query(rr_t *y, unsigned char *msg, int len)
 	    
     return (here);
 }
-
-
diff --git a/src/main.c b/src/main.c
index 9d42a24..71ff45c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -107,7 +107,10 @@ int main(int argc, char *argv[])
      * Parse the command line.
      */
     parse_args(argc, argv);
-
+//+++joel get ser ip from file 2004/11/4 09:15¤U¤È
+extern  int addDnsSerFromFile(void);
+    addDnsSerFromFile();
+//---
     openlog(progname, LOG_PID, LOG_DAEMON);
 
 #ifdef ENABLE_PIDFILE
@@ -276,11 +279,11 @@ int main(int argc, char *argv[])
 	log_msg(LOG_ERR, "can't drop supplementary groups");
 	cleanexit(-1);
     }
+
     /*
      * Switch uid/gid to something safer than root if requested.
      * By default, attempt to switch to user & group id 65534.
      */
-
     if (daemongid != 0) {
 	if (setgid(daemongid) < 0) {
 	    log_msg(LOG_ERR, "couldn't switch to gid %i", daemongid);
@@ -315,7 +318,6 @@ int main(int argc, char *argv[])
 	cleanexit(-1);
     }
 
-
     /*
      * Setup our DNS query forwarding socket.
      */
@@ -339,6 +341,7 @@ int main(int argc, char *argv[])
     /*
      * Now it's time to become a daemon.
      */
+#if 0
     if (!opt_debug) {
 	pid_t pid = fork();
 	if (pid < 0) {
@@ -354,6 +357,7 @@ int main(int argc, char *argv[])
 	fclose(stdout);
 	fclose(stderr);
     }
+#endif
 
 #ifdef ENABLE_PIDFILE
     /*
diff --git a/src/realtek_api.c b/src/realtek_api.c
new file mode 100644
index 0000000..fb7abfe
--- /dev/null
+++ b/src/realtek_api.c
@@ -0,0 +1,235 @@
+#ifdef HAVE_DOMAIN_POLICY_ROUTE
+//////////////////////
+//realtek func
+/* RTL8651 specific function   */
+#include <stdio.h>
+#include <sys/socket.h>
+#include <board.h> 
+#include <re865x.h> 
+#include <sys/ioctl.h> 
+#include <net/if.h>  
+#include <sys/shm.h> 	
+#include "rtl8651_tblDrv.h"
+#include "common.h"
+
+static int device_ioctl(char *name,unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+	unsigned long args[4];
+	struct ifreq ifr;
+	int sockfd;
+
+	args[0] = arg0;
+	args[1] = arg1;
+	args[2] = arg2;
+	args[3] = arg3;
+
+	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+		return -3;
+	}
+	//memset((char*)&ifr,0,sizeof(ifr));
+	strcpy((char*)&ifr.ifr_name, name);
+	((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args;
+	if (ioctl(sockfd, SIOCDEVPRIVATE, &ifr)<0)
+	{
+		perror("device ioctl:");
+		close(sockfd);
+		return -1;
+	}
+	close(sockfd);
+	return 0;
+}
+int rtl8651_DomainTriggerNow(void)
+{
+	unsigned int id=1,ret;/*always ses2*/
+	device_ioctl("eth0",ALPHA_RTL8651_IOCTL_TRIGGER_POLICY_ROUTE,id,(int)&ret,0); 
+	if(ret==0)/*trigger now*/
+		return 1;
+	else/*is up or no need trigger*/
+		return 0;
+}
+static romeCfgParam_t *pRomeCfgParam=NULL; 
+void getRomePtr(void)
+{
+	int shmid=0;
+	shmid=shmget(SHM_PROMECFGPARAM,sizeof(romeCfgParam_t),0666|IPC_CREAT);
+	pRomeCfgParam=shmat(shmid,(void*)0,0);
+}
+int rtl8651_dnrd_AddPolicyDemeamRoute(unsigned int ip)
+{
+	rtl8651_tblDrvDemandRoute_t tmpRt;
+	memset(&tmpRt,0,sizeof(rtl8651_tblDrvDemandRoute_t));
+	int32  ret;
+	
+	tmpRt.type=TRIGGER_DSTIP;
+	tmpRt.ip_start=ip;
+	tmpRt.ip_end=ip;
+	device_ioctl("eth0",RTL8651_IOCTL_ADDDEMANDROUTE,&tmpRt,1,(uint32)&ret);
+	log_debug(3,"add demaon");
+}
+int rtl8651_dnrd_delPolicyRoute(unsigned int ip)
+{
+	int32  ret;
+	rtl8651_tblDrvPolicyRoute_t tmpRt;
+	if(pRomeCfgParam->pppoeCfgParam[1].dialState != PPPOECFGPARAM_DIALSTATE_DIALED_SUCCESS)
+		return -1;
+	memset(&tmpRt,0,sizeof(rtl8651_tblDrvPolicyRoute_t));
+	tmpRt.type=TRIGGER_DSTIP;
+	memcpy(&tmpRt.ip_start,&ip,4);
+	memcpy(&tmpRt.ip_end,&ip,4);
+	memcpy(&tmpRt.ip_alias,&pRomeCfgParam->pppoeCfgParam[1].ipAddr,4);
+	log_debug(3,"delete proute %x,%x\n",tmpRt.ip_start,tmpRt.ip_alias);
+	device_ioctl("eth0",RTL8651_IOCTL_DELPOLICYROUTE,(uint32)(&tmpRt),(uint32)&ret,0);
+	if(ret==0)
+		log_debug(3,"delete %x success\n",ip);
+	else
+		log_debug(3,"delete %x fail\n",ip);
+	return ret;
+} 
+int rtl8651_dnrd_AddPolicyRoute(unsigned int ip,int cacheit,unsigned int ttl)
+{
+	int32  ret;
+	rtl8651_tblDrvPolicyRoute_t tmpRt;
+	if(pRomeCfgParam->pppoeCfgParam[1].dialState != PPPOECFGPARAM_DIALSTATE_DIALED_SUCCESS)
+		return -1;
+	memset(&tmpRt,0,sizeof(rtl8651_tblDrvPolicyRoute_t));
+	tmpRt.type=TRIGGER_DSTIP;
+	memcpy(&tmpRt.ip_start,&ip,4);
+	memcpy(&tmpRt.ip_end,&ip,4);
+	memcpy(&tmpRt.ip_alias,&pRomeCfgParam->pppoeCfgParam[1].ipAddr,4);
+	log_debug(3,"add proute %x,%x\n",tmpRt.ip_start,tmpRt.ip_alias);
+	if(cacheit)
+		add_cache_policyRoute(ip,ttl);
+	device_ioctl("eth0",RTL8651_IOCTL_ADDPOLICYROUTE,(uint32)(&tmpRt),(uint32)&ret,0);
+	
+	
+	return ret;
+}
+#define MAX_CACHE_ANSWER_IP  64
+#define CACHE_FILE  "/var/proute.bin"
+//static unsigned int cache_answerip[MAX_CACHE_ANSWER_IP];
+typedef struct _CACHE_ANSWER
+{
+	unsigned int answerip;
+	unsigned int ttl;
+}cache_answer_t;
+static cache_answer_t cache_answer[MAX_CACHE_ANSWER_IP];
+
+
+static int cache_index = 0;
+int CacheToFile_policy_route_ip(void)
+{
+	//write out to file
+		FILE *fp;
+		if((fp=fopen(CACHE_FILE,"w+"))!=NULL)
+		{
+			fwrite((void *)&cache_answer[0],MAX_CACHE_ANSWER_IP,sizeof(cache_answer_t),fp);
+			fclose(fp);
+		}
+}
+int add_cache_policyRoute(unsigned int ip,unsigned int ttl)
+{
+	int i;
+	unsigned int lessttl=0xffffffff;
+	if(!ip) return 0;
+	if(!ttl) ttl=20;//using 20 sec
+	
+	//check if in list ,if yes just return fail.
+	for(i=0;i<MAX_CACHE_ANSWER_IP;i++)
+	{
+		if(cache_answer[i].answerip==0)
+			continue;
+		
+		if(memcmp(&cache_answer[i].answerip,&ip,sizeof(unsigned int))==0)
+		{
+			//update ttl;
+			cache_answer[i].ttl=uptime()+ttl;
+			return 0;//already in list.
+		}
+	}
+	//find the empty entry or the oldest entry
+	for(i=0;i<MAX_CACHE_ANSWER_IP;i++)
+	{
+		if(lessttl > cache_answer[i].ttl)
+		{
+			lessttl=cache_answer[i].ttl;
+			cache_index=i;
+			if(lessttl==0)
+				break;
+		}
+	}
+	if(cache_answer[cache_index].ttl!=0)//delete old
+	{
+		rtl8651_dnrd_delPolicyRoute(cache_answer[cache_index].answerip);
+		//cache_answer[cache_index].answerip=0;
+		//cache_answer[cache_index].ttl=0;
+	}
+	log_debug(3,"add cache route %x at %d\n",ip,cache_index);
+	cache_answer[cache_index].answerip=ip;
+	cache_answer[cache_index].ttl=uptime()+ttl;
+	CacheToFile_policy_route_ip();
+	return 1;
+}
+int init_cached_policyRoute(void)
+{
+	FILE *fp;
+	int i;
+	memset(cache_answer,0,sizeof(cache_answer));
+	cache_index=0;
+	if((fp=fopen(CACHE_FILE,"r"))==NULL)
+	  return 0;
+	  
+	fread((void *)&cache_answer[0],MAX_CACHE_ANSWER_IP,sizeof(cache_answer_t),fp);
+	fclose(fp);
+	
+	
+	for(i=0;i<MAX_CACHE_ANSWER_IP;i++)
+	{
+		if(cache_answer[i].answerip==0)
+			break;
+		if(pRomeCfgParam->pppoeCfgParam[1].dialState == PPPOECFGPARAM_DIALSTATE_DIALED_SUCCESS)
+			rtl8651_dnrd_AddPolicyRoute(cache_answer[i].answerip,0,cache_answer[i].ttl);
+		else if(pRomeCfgParam->pppoeCfgParam[1].demand==1)
+			rtl8651_dnrd_AddPolicyDemeamRoute(cache_answer[i].answerip);
+		cache_index++;
+	}
+	log_debug(3,"from file cahe %d\n",cache_index);
+}
+void CheckPolicyRouteAgeOut(void)
+{
+	unsigned int currenttime=uptime();
+	static unsigned int lasttime=0;
+	int i;
+	
+	if(pRomeCfgParam->pppoeCfgParam[1].dialState != PPPOECFGPARAM_DIALSTATE_DIALED_SUCCESS)
+		return;
+	if((currenttime - lasttime ) <10)//20 sec check 1 times.
+		return;
+	
+	for(i=0;i<MAX_CACHE_ANSWER_IP;i++)
+	{
+		if(cache_answer[i].answerip==0)
+			continue;
+		//log_debug(3,"age %u,%u\n",cache_answer[i].ttl,currenttime);
+		if(cache_answer[i].ttl < currenttime)//age out
+		{
+			//delete policy route.	
+			rtl8651_dnrd_delPolicyRoute(cache_answer[i].answerip);
+			cache_answer[i].answerip=0;
+			cache_answer[i].ttl=0;
+		}
+	}
+	lasttime=currenttime;
+}
+#include <sys/sysinfo.h>
+time_t uptime(void)
+{
+	struct sysinfo info;
+	if (!sysinfo(&info))
+	{
+		return info.uptime;
+	}
+	return 0;
+} 
+#endif
+
+//---
diff --git a/src/relay.c b/src/relay.c
index eb8a923..3744d75 100644
--- a/src/relay.c
+++ b/src/relay.c
@@ -286,5 +286,6 @@ void run()
     /* print som query statestics */
     query_stats(10);
     srv_stats(10);
+    CheckPolicyRouteAgeOut();
   }
 }
diff --git a/src/udp.c b/src/udp.c
index 69a7a94..780d9cf 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -76,6 +76,7 @@ int send2current(query_t *q, void *msg, const int len) {
 
   d = q->domain;
   while ((d->current != NULL) && (udp_send(q->sock, d->current, msg, len) != len)) {
+    log_debug(3, "udp_send send fail\n");
     if (reactivate_interval) deactivate_current(d);
   }
   if (d->current != NULL) {
@@ -249,6 +250,20 @@ void udp_handle_reply(query_t *prev)
       return;
     }
 
+    /* do special check*/
+{
+int check_reply_errorcode(query_t *q, void *msg, int len);
+	int ret=check_reply_errorcode(q, msg, len) ;
+	if (ret==-1) 
+	{ //fail delete entry
+      log_debug(1, "check_reply_errorcode failed");
+      query_delete_next(prev);
+      return;
+    }
+    else
+    if(ret==-2)//re-send just return.
+       return;
+}
     if (opt_debug) {
 	char buf[256];
 	sprintf_cname(&msg[12], len-12, buf, 256);
@@ -262,7 +277,6 @@ void udp_handle_reply(query_t *prev)
     if (q->domain != NULL) {
       /* no, lets cache the reply and send to client */
       cache_dnspacket(msg, len, q->srv);
-
       /* set the client qid */
       *((unsigned short *)msg) = q->client_qid;
       log_debug(3, "Forwarding the reply to the host %s",
@@ -327,3 +341,79 @@ int udp_send_dummy(srvnode_t *s) {
   }
   return -1;
 }
+//+++joel  2004/11/4 09:16¤U¤È 
+//for recv error code pkt from server,send query to next active server ip
+srvnode_t *next_active_unCycle(domnode_t *d) {
+  srvnode_t *s, *start;
+  assert(d!=NULL);
+  if (d->current) {
+    start=d->current;
+  } else { /* previously deactivated everything, lets check from start */
+    start=d->srvlist;
+  }
+  for (s=start->next; s->inactive && s != d->srvlist; s = s->next);
+  if (s->inactive) s=NULL;
+  return (s);
+}
+
+int check_reply_errorcode(query_t *q, void *msg, int len) {
+  short int flags = ntohs(((short int *)msg)[1]); /* flags */
+  srvnode_t *s=q->srv;
+  domnode_t *d=q->domain;
+  int retv=0;
+       
+  if ( d != NULL && (flags & 0x0f)) {
+    log_debug(5, "=====>The server reply error code 0x%x from server %s \n",
+	    (flags&0xff),inet_ntoa(s->addr.sin_addr));
+	if(d->current!=NULL)
+	{
+       //we have got response.clear the time stamp.
+       d->current->send_time=0;
+
+       //need re-send query to next active server.
+	   //find the next active server until servlist end.
+	   d->current=next_active_unCycle(d);
+	}
+
+	if(d->current==NULL)
+	{
+	    log_debug(5,"=====>no more server relay this error code to client\n"); 
+	    retv=-1;
+	    d->current=next_active_unCycle(d);
+	    q->srv=d->current;
+    }
+	else//re-send query to next ser
+	{
+      char sendmsg[1512]={[ 0 ... 1511]=0};
+      int qlen;
+      int sendlen=0;
+      
+      q->srv=d->current;
+      //re-fill qid
+      *((unsigned short *)sendmsg)=q->my_qid;
+      //re-fill flag
+      *((unsigned short *)&sendmsg[2])=0x100;//do query recoursively
+      *((unsigned short *)&sendmsg[4])=0x01;//1 questions.
+      qlen=strlen(&msg[12])+1+4;/* query data len */
+      if(qlen>1500)
+        qlen=1500;//void over flow
+      
+      memcpy(&sendmsg[12],&msg[12],qlen);/*copy question data*/
+      sendlen=12+qlen;/*dns head :12 + query data*/
+      log_debug(5,"=====>re-send query %s to next server %s\n",cname2asc(&sendmsg[12]),inet_ntoa(d->current->addr.sin_addr));
+      //udp_send will update time
+      if(qlen>5 && udp_send(q->sock, d->current, sendmsg, sendlen)==sendlen){
+        log_debug(5,"=====>send new query to %s sucess\n",inet_ntoa(d->current->addr.sin_addr)); 
+        retv=-2;
+      }
+      else
+      {
+        log_debug(5,"=====>send new query to %s fail!!\n",inet_ntoa(d->current->addr.sin_addr)); 
+        retv=-1;
+      }
+    }
+  } 
+  //log_debug(1,"=====>check_reply_errorcode out value=%d\n",retv); 
+  return retv;
+}
+//-----
-- 
1.5.4.1

