1/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
2
3   This program is free software; you can redistribute it and/or modify
4   it under the terms of the GNU General Public License as published by
5   the Free Software Foundation; version 2 dated June, 1991.
6
7   This program is distributed in the hope that it will be useful,
8   but WITHOUT ANY WARRANTY; without even the implied warranty of
9   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10   GNU General Public License for more details.
11*/
12
13/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
16
17/* foxconn wklin added start, 08/31/2007 @mpoe */
18#ifdef MULTIPLE_PPPOE
19int mpoe = 0; /* for multiple wan, forward dns query to all ifs */
20#endif /* MULTIPLE_PPPOE */
21/* foxconn wklin added end, 08/31/2007 */
22
23static struct frec *frec_list;
24
25static struct frec *get_new_frec(time_t now);
26static struct frec *lookup_frec(unsigned short id);
27static struct frec *lookup_frec_by_sender(unsigned short id,
28					  union mysockaddr *addr);
29static unsigned short get_id(void);
30static void get_device_id(char src_mac[], char id[]);
31
32/* foxconn removed start by Jenny Zhao, 12/10/2008,@Russia_PPTP new spec*/
33#if 0
34/* Foxconn added start, zacker, 07/29/2008,@Russia_PPTP */
35extern keyword_t pptp_domain;
36extern Session2_DNS pptp_dhcp_dns_tbl;
37
38int is_pptp_dhcp_dns(unsigned long uiDNSIP)
39{
40    int i;
41
42    for(i=0; i<pptp_dhcp_dns_tbl.iDNSCount; i++)
43    {
44        if(uiDNSIP == pptp_dhcp_dns_tbl.DNSEntry[i])
45        {
46            return 1;
47        }
48    }
49
50    return 0;
51}
52
53int is_pptp_domain_matched(char *namebuff)
54{
55    keyword_t *keyword=NULL;
56    int matched = 0;
57
58    if (!namebuff)
59        return matched;
60
61    for (keyword = &pptp_domain; keyword; keyword=keyword->next)
62    {
63        if (keyword->wildcard == 1)
64        {
65            char *p;
66            if (p=strcasestr(namebuff,keyword->name))
67            {
68                if (*(p+strlen(keyword->name)) == '\0')
69                {
70                    matched = 1;
71                    fprintf(stderr, "wildcard matched %s\n", keyword->name);
72                    break;
73                }
74            }
75        }
76        else if (strcasecmp(namebuff,keyword->name) == 0)
77        {
78            matched = 1;
79            fprintf(stderr, "matched %s\n", keyword->name);
80            break;
81        }
82    }
83    return matched;
84}
85/* Foxconn added end, zacker, 07/29/2008,@Russia_PPTP */
86#endif
87/* foxconn removed end by Jenny Zhao, 12/10/2008,@Russia_PPTP new spec*/
88
89/* foxconn wklin added start, 09/03/2007 @mpoe */
90#ifdef MULTIPLE_PPPOE
91
92/* foxconn added start Bob Guo, 10/24/2007 */
93
94extern Session2_DNS    Session2_Dns_Tbl;
95
96int IsSession2DNS(unsigned long uiDNSIP)
97{
98    int i;
99
100    for(i=0; i<Session2_Dns_Tbl.iDNSCount; i++)
101    {
102        if(uiDNSIP == Session2_Dns_Tbl.DNSEntry[i])
103        {
104            return 1;
105        }
106    }
107
108    return 0;
109}
110
111int IsDomainKeywordMatched(char *namebuff)
112{
113    extern keyword_t *keyword_list;
114    keyword_t *keyword=NULL;
115    int matched = 0;
116
117    if (!namebuff)
118	return matched;
119	for (keyword = keyword_list; keyword; keyword=keyword->next)
120	{
121        if (keyword->wildcard == 1)
122        {
123            char *p;
124            if (p=strcasestr(namebuff,keyword->name))
125            {
126                if (*(p+strlen(keyword->name)) == '\0')
127                {
128                    matched = 1;
129                    fprintf(stderr, "wildcard matched %s\n", keyword->name);
130                    break;
131                }
132            }
133        }
134        else if (strcasestr(namebuff,keyword->name))
135        {
136            matched = 1;
137	        fprintf(stderr, "matched %s\n", keyword->name);
138	        break;
139	    }
140    }
141    return matched;
142
143}
144/* foxconn added end Bob Guo, 10/24/2007 */
145#if 0
146static void private_domain_check(HEADER *header, int n, char *namebuff)
147{
148    extern void extract_set_addr(HEADER *, int);
149
150    if(IsDomainKeywordMatched(namebuff) == 1)
151        extract_set_addr(header, n);
152
153}
154#else
155#define MAX_QUERY_NAME  1500
156static void private_domain_check(HEADER *header, int n, char *namebuff)
157{
158    char qryname[MAX_QUERY_NAME], *p;
159    int i, j=0;
160    extern void extract_set_addr(HEADER *, int);
161
162    if ( NULL == header )
163         return;
164    p= (char *)header + sizeof(HEADER);
165    i = *p;
166
167      /* Find the domain name in questions area, and use this name to compare with the
168          keyword.                weal @ March 4, 2008 */
169    while (i && j < MAX_QUERY_NAME ){
170        for(;i>0;i--){
171            qryname[j++] = *(++p);
172            }
173        i = *(++p);
174        if (i)
175            qryname[j++] = '.';
176        }
177
178    qryname[j++] = '\0';
179
180    if(IsDomainKeywordMatched(qryname) == 1)
181        extract_set_addr(header, n);
182
183}
184#endif
185
186#endif /* MULTIPLE_PPPOE */
187/* foxconn wklin added end, 09/03/2007 */
188/* May be called more than once. */
189void forward_init(int first)
190{
191  struct frec *f;
192
193  if (first)
194    frec_list = NULL;
195  for (f = frec_list; f; f = f->next)
196    f->new_id = 0;
197}
198
199/* Send a UDP packet with it's source address set as "source"
200   unless nowild is true, when we just send it with the kernel default */
201static void send_from(int fd, int nowild, char *packet, int len,
202		      union mysockaddr *to, struct all_addr *source,
203		      unsigned int iface)
204{
205  struct msghdr msg;
206  struct iovec iov[1];
207  union {
208    struct cmsghdr align; /* this ensures alignment */
209#if defined(IP_PKTINFO)
210    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
211#elif defined(IP_SENDSRCADDR)
212    char control[CMSG_SPACE(sizeof(struct in_addr))];
213#endif
214#ifdef HAVE_IPV6
215    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
216#endif
217  } control_u;
218
219  iov[0].iov_base = packet;
220  iov[0].iov_len = len;
221
222  msg.msg_control = NULL;
223  msg.msg_controllen = 0;
224  msg.msg_flags = 0;
225  msg.msg_name = to;
226  msg.msg_namelen = sa_len(to);
227  msg.msg_iov = iov;
228  msg.msg_iovlen = 1;
229
230  if (!nowild && to->sa.sa_family == AF_INET)
231    {
232      msg.msg_control = &control_u;
233      msg.msg_controllen = sizeof(control_u);
234      {
235	struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
236#if defined(IP_PKTINFO)
237
238	struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
239	pkt->ipi_ifindex = 0;
240	pkt->ipi_spec_dst = source->addr.addr4;
241	msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
242	cmptr->cmsg_level = SOL_IP;
243	cmptr->cmsg_type = IP_PKTINFO;
244#elif defined(IP_SENDSRCADDR)
245	struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
246	*a = source->addr.addr4;
247	msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
248	cmptr->cmsg_level = IPPROTO_IP;
249	cmptr->cmsg_type = IP_SENDSRCADDR;
250#endif
251      }
252    }
253
254#ifdef HAVE_IPV6
255  if (to->sa.sa_family == AF_INET6)
256    {
257      msg.msg_control = &control_u;
258      msg.msg_controllen = sizeof(control_u);
259      {
260	struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
261	struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
262	pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
263	pkt->ipi6_addr = source->addr.addr6;
264	msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
265	cmptr->cmsg_type = IPV6_PKTINFO;
266	cmptr->cmsg_level = IPV6_LEVEL;
267      }
268    }
269#endif
270
271  /* certain Linux kernels seem to object to setting the source address in the IPv6 stack
272     by returning EINVAL from sendmsg. In that case, try again without setting the
273     source address, since it will nearly alway be correct anyway.  IPv6 stinks. */
274  if (sendmsg(fd, &msg, 0) == -1 && errno == EINVAL)
275    {
276      msg.msg_controllen = 0;
277      sendmsg(fd, &msg, 0);
278    }
279}
280
281static unsigned short search_servers(struct daemon *daemon, time_t now, struct all_addr **addrpp,
282				     unsigned short qtype, char *qdomain, int *type, char **domain)
283
284{
285  /* If the query ends in the domain in one of our servers, set
286     domain to point to that name. We find the largest match to allow both
287     domain.org and sub.domain.org to exist. */
288
289  unsigned int namelen = strlen(qdomain);
290  unsigned int matchlen = 0;
291  struct server *serv;
292  unsigned short flags = 0;
293
294  for (serv = daemon->servers; serv; serv=serv->next)
295    /* domain matches take priority over NODOTS matches */
296    if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.'))
297      {
298	unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
299	*type = SERV_FOR_NODOTS;
300	if (serv->flags & SERV_NO_ADDR)
301	  flags = F_NXDOMAIN;
302	else if (serv->flags & SERV_LITERAL_ADDRESS)
303	  {
304	    if (sflag & qtype)
305	      {
306		flags = sflag;
307		if (serv->addr.sa.sa_family == AF_INET)
308		  *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
309#ifdef HAVE_IPV6
310		else
311		  *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
312#endif
313	      }
314	    else if (!flags)
315	      flags = F_NOERR;
316	  }
317      }
318    else if (serv->flags & SERV_HAS_DOMAIN)
319      {
320	unsigned int domainlen = strlen(serv->domain);
321	if (namelen >= domainlen &&
322	    hostname_isequal(qdomain + namelen - domainlen, serv->domain) &&
323	    domainlen >= matchlen)
324	  {
325	    unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
326	    *type = SERV_HAS_DOMAIN;
327	    *domain = serv->domain;
328	    matchlen = domainlen;
329	    if (serv->flags & SERV_NO_ADDR)
330	      flags = F_NXDOMAIN;
331	    else if (serv->flags & SERV_LITERAL_ADDRESS)
332	      {
333		if ((sflag | F_QUERY ) & qtype)
334		  {
335		    flags = qtype;
336		    if (serv->addr.sa.sa_family == AF_INET)
337		      *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
338#ifdef HAVE_IPV6
339		    else
340		      *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
341#endif
342		  }
343		else if (!flags)
344		  flags = F_NOERR;
345	      }
346	  }
347      }
348
349  if (flags & ~(F_NOERR | F_NXDOMAIN)) /* flags set here means a literal found */
350    {
351      if (flags & F_QUERY)
352	log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL, 0);
353      else
354	log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0);
355    }
356  else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
357    flags = F_NXDOMAIN;
358
359  if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon->mxnames))
360    flags = F_NOERR;
361
362  if (flags == F_NXDOMAIN || flags == F_NOERR)
363    log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL, 0);
364
365  return  flags;
366}
367
368/* Foxconn add start, Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
369#ifdef OPENDNS_PARENTAL_CONTROL
370#define HTONS_CHARS(n) (unsigned char)((n) >> 8), (unsigned char)(n)
371
372static int add_device_id(struct daemon *daemon, HEADER *header, size_t plen, unsigned char *pheader,
373 			 size_t pheader_len, struct frec *forward)
374{
375   const unsigned char clientid[11] = { HTONS_CHARS(4), HTONS_CHARS(15),
376 				       'O', 'p', 'e', 'n', 'D', 'N', 'S' };
377   const unsigned char fixed[11] = { 0, HTONS_CHARS(T_OPT),
378 				    HTONS_CHARS(PACKETSZ),
379 				    0, 0, 0, 0, HTONS_CHARS(0) };
380   const int option_len = sizeof(clientid) + sizeof(daemon->device_id);
381   unsigned char *p = (unsigned char *)header;
382   unsigned short rdlen;
383
384   if ((pheader == NULL && plen + sizeof(fixed) + option_len <= PACKETSZ)
385       || (pheader != NULL && pheader + pheader_len == p + plen
386 	  && plen + option_len <= PACKETSZ))
387   {
388       if (pheader == NULL)
389 	   {
390 	       pheader = p + plen;
391 	       memcpy(p + plen, fixed, sizeof(fixed));
392 	       plen += sizeof(fixed);
393 	       header->arcount = htons(ntohs(header->arcount) + 1);
394 	       /* Since the client didn't send a pseudoheader, it won't be
395 	          expecting one in the response. */
396 	       forward->discard_pseudoheader = 1;
397#ifdef USE_SYSLOG
398 	       if (daemon->options & OPT_LOG)
399 	           my_syslog(LOG_DEBUG, "pseudoheader added");
400#endif
401 	   }
402       /* Append a CLIENTID option to the pseudoheader. */
403       memcpy(p + plen, clientid, sizeof(clientid));
404       plen += sizeof(clientid);
405       memcpy(p + plen, daemon->device_id,
406 	     sizeof(daemon->device_id));
407       plen += sizeof(daemon->device_id);
408       /* Update the pseudoheader's RDLEN field. */
409       p = pheader + 9;
410       GETSHORT(rdlen, p);
411       p = pheader + 9;
412       PUTSHORT(rdlen + option_len, p);
413#ifdef USE_SYSLOG
414       if (daemon->options & OPT_LOG)
415 	       my_syslog(LOG_DEBUG, "device ID added");
416#endif
417   }
418   return plen;
419}
420#endif
421/* Foxconn add end  , Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
422
423//#define QUERY_DEBUG 1 /* Michael */
424
425/* returns new last_server */
426static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *udpaddr,
427			  struct all_addr *dst_addr, unsigned int dst_iface,
428			  HEADER *header, size_t plen, time_t now, struct frec *forward)
429{
430  //struct frec *forward;   /* Foxconn removed by EricHuang, 12/28/2007 */
431  char *domain = NULL;
432  int forwardall = 0, type = 0;
433  struct all_addr *addrp = NULL;
434  unsigned short flags = 0;
435  unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
436  struct server *start = NULL;
437
438    /* Foxconn, add by MJ., for clarifying this issue. 2011.07.04 */
439#ifdef QUERY_DEBUG
440    printf("\n\n%s: sent from %s\n", __FUNCTION__, inet_ntoa(udpaddr->in.sin_addr));
441    if(udpaddr->sa.sa_family == AF_INET)
442        printf("A query from IPv4.\n");
443    else
444        printf("A query from IPv6.\n");
445#endif
446    /* Foxconn, add-end by MJ., for clarifying this issue. 2011.07.04 */
447
448  /* Foxconn add start, Tony W.Y. Wang, 12/05/2008, @Parental Control OpenDNS */
449#ifdef OPENDNS_PARENTAL_CONTROL
450  FILE *fp;
451  char flag;
452  char dnsquery_src_mac[20] = "";
453  char device_id[32] = "";
454  if((fp = fopen("/tmp/opendns.flag", "r")))
455  {
456      flag = fgetc(fp);
457      fclose(fp);
458  }
459  daemon->have_device_id = 0;
460  if(flag == '1')          /* Parental Control Enabled */
461  {
462      get_mac_from_arp(inet_ntoa(udpaddr->in.sin_addr), dnsquery_src_mac); /* Get MAC Address from ARP according to Soure IP */
463      get_device_id(dnsquery_src_mac, device_id);
464      daemon->have_device_id = 1;
465      if(char_to_byte(device_id, daemon->device_id))
466          return;
467  }
468#endif
469  /* Foxconn add end  , Tony W.Y. Wang, 12/05/2008, @Parental Control OpenDNS */
470#ifdef MULTIPLE_PPPOE
471    int iToSession2, iIsSession2DNS;
472
473    iToSession2 = IsDomainKeywordMatched(daemon->namebuff);
474    /* if (mpoe == 1) */ /* Foxconn modified, zacker, 07/29/2008 */
475    if (mpoe == 1 && forward)
476        forward->forwardall = 1;    //forwardall = 1;       /* Foxconn modified by EricHuang, 01/02/2008 */
477
478#endif
479/* foxconn removed start by Jenny Zhao, 12/10/2008,@Russia_PPTP new spec*/
480#if 0
481    /* Foxconn added start, zacker, 07/29/2008,@Russia_PPTP */
482    int iToDhcpDNS, iIsDhcpDNS;
483    iToDhcpDNS = is_pptp_domain_matched(daemon->namebuff);
484    /* Foxconn added end, zacker, 07/29/2008,@Russia_PPTP */
485#endif
486/* foxconn removed end by Jenny Zhao, 12/10/2008,@Russia_PPTP new spec*/
487
488  /* may be  recursion not speced or no servers available. */
489    if (!header->rd || !daemon->servers)
490        forward = NULL;
491  /* Foxconn modified , Tony W.Y. Wang, 12/11/2008, @Parental Control OpenDNS to add device id in every DNS Query */
492#ifdef OPENDNS_PARENTAL_CONTROL
493    else if ( (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr))) && (flag != '1')) /* Foxconn modified by EricHuang, 01/02/2008 */
494#else
495    else if ( forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr))) /* Foxconn modified by EricHuang, 01/02/2008 */
496#endif
497    {
498        /* retry on existing query, send to all available servers  */
499        domain = forward->sentto->domain;
500        if (!(daemon->options & OPT_ORDER))
501        {
502            forward->forwardall = 1;  //forwardall = 1;       /* Foxconn modified by EricHuang, 01/02/2008 */
503            daemon->last_server = NULL;
504        }
505        type = forward->sentto->flags & SERV_TYPE;
506        if (!(start = forward->sentto->next))
507            start = daemon->servers; /* at end of list, recycle */
508        header->id = htons(forward->new_id);
509    }
510    else
511    {
512        if (gotname)
513	        flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
514
515        if (!flags && !(forward = get_new_frec(now)))
516        	/* table full - server failure. */
517        	flags = F_NEG;
518
519        if (forward)
520        {
521          /* Foxconn add start, Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
522#ifdef OPENDNS_PARENTAL_CONTROL
523          size_t pheader_len;
524          unsigned char *pheader;
525          pheader = find_pseudoheader(header, plen, &pheader_len, NULL);
526#endif
527          /* Foxconn add end  , Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
528          /* Foxconn moved start by EricHuang, 01/02/2008 */
529          /* foxconn added start Bob, 07/15/2011, check NULL pointer */
530          if(udpaddr==NULL)
531          {
532          	return;
533          }
534          /* foxconn added end Bob, 07/15/2011, check NULL pointer */
535          forward->source = *udpaddr;
536          forward->dest = *dst_addr;
537          forward->iface = dst_iface;
538          forward->new_id = get_id();
539          forward->fd = udpfd;
540          forward->orig_id = ntohs(header->id);
541          forward->forwardall = 0;              /* Foxconn added by EricHuang, 01/02/2007 */
542#ifdef OPENDNS_PARENTAL_CONTROL
543          forward->discard_pseudoheader = 0;    /* Foxconn add, Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
544#endif
545          header->id = htons(forward->new_id);
546          /* Foxconn moved start by EricHuang, 01/02/2008 */
547
548          /* In strict_order mode, or when using domain specific servers
549             always try servers in the order specified in resolv.conf,
550             otherwise, use the one last known to work. */
551
552          if (type != 0  || (daemon->options & OPT_ORDER))
553            start = daemon->servers;
554          else if (!(start = daemon->last_server))
555          {
556              start = daemon->servers;
557              forward->forwardall = 1; //forwardall = 1;    /* Foxconn modified by EricHuang, 01/02/2007 */
558          }
559          /* Foxconn add start, Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
560#ifdef OPENDNS_PARENTAL_CONTROL
561          if (daemon->have_device_id)
562              plen = add_device_id(daemon, header, plen, pheader, pheader_len, forward);
563#endif
564          /* Foxconn add end  , Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
565          /*
566          forward->source = *udpaddr;
567          forward->dest = *dst_addr;
568          forward->iface = dst_iface;
569          forward->new_id = get_id();
570          forward->fd = udpfd;
571          forward->orig_id = ntohs(header->id);
572          header->id = htons(forward->new_id);
573          */
574        }
575    }
576
577  /* check for send errors here (no route to host)
578     if we fail to send to all nameservers, send back an error
579     packet straight away (helps modem users when offline)  */
580
581  if (!flags && forward)
582    {
583      struct server *firstsentto = start;
584      int forwarded = 0;
585      /* Foxconn add start, Max Ding, 07/06/2011 */
586      /* According to spec:
587       * When the DNS query includes the type of AAAA or A6,
588       * if there is a DNS server configured with an IPv6 address,
589       * forward the query to the IPv6 DNS server. If there is
590       * no DNS server configured with an IPv6 address or the
591       * query fails to get an answer from the IPv6 DNS server (e.g. timeout, error...),
592       * forward the query to the IPv4 DNS server configured.
593       *
594       * "query fail case" is to be implemented.
595       */
596      unsigned short sflag = 0;
597      int second_try = 0;
598      /* Foxconn add end, Max Ding, 07/06/2011 */
599
600      while (1)
601	{
602	  /* only send to servers dealing with our domain.
603	     domain may be NULL, in which case server->domain
604	     must be NULL also. */
605	  sflag = (start->addr.sa.sa_family == AF_INET) ? F_IPV4 : F_IPV6;/* Foxconn added by Max Ding, 07/06/2011 */
606
607      if (type == (start->flags & SERV_TYPE) &&
608           ((gotname & F_QUERY) || (sflag & gotname)) &&/* Foxconn added by Max Ding, 07/06/2011 */
609	      (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)))
610	    {
611#ifdef MULTIPLE_PPPOE
612	            char *pdnsServer;
613	            struct sockaddr_in *p;
614	            int iSendResult = 0;
615
616#if 0
617                /* Foxconn, add by MJ., 2011.07.05 */
618                /* We don't forward a ipv4 query packets to DNS server with ipv6
619                    * address, vice versa*/
620                if(udpaddr)	/* foxconn added Bob, 07/15/2011, check NULL pointer */
621                {
622                	if(!(start->flags & SERV_LITERAL_ADDRESS) && (start->addr.sa.sa_family != udpaddr->sa.sa_family) )
623                	{
624                    	//printf("=> don't forward this query.\n");
625                    	goto try_next_server;
626                	}
627                }
628                /* Foxconn, add-end by MJ., 2011.07.05 */
629#endif
630
631	            p = (struct sockaddr_in *)&(start->addr.sa);
632	            pdnsServer = inet_ntoa(p->sin_addr);
633	            iIsSession2DNS = IsSession2DNS(p->sin_addr.s_addr);
634
635	            if(iIsSession2DNS == iToSession2)
636	            {
637	                iSendResult = sendto(start->sfd->fd, (char *)header, plen, 0, &start->addr.sa, sa_len(&start->addr));
638	            }
639		        if (!(start->flags & SERV_LITERAL_ADDRESS) && iSendResult != -1)
640#else
641
642
643/* foxconn modified start by Jenny Zhao, 12/10/2008,@Russia_PPTP new spec*/
644#if 0
645            /* Foxconn, add by MJ., 2011.07.05 */
646            /* We don't forward a ipv4 query packets to DNS server with ipv6 address, vice versa*/
647            if(!(start->flags & SERV_LITERAL_ADDRESS) && (start->addr.sa.sa_family != udpaddr->sa.sa_family) ){
648                //printf("=> don't forward this query 2.\n");
649                goto try_next_server;
650            }
651            /* Foxconn, add-end by MJ., 2011.07.05 */
652#endif
653            /* Foxconn modified start, zacker, 07/29/2008,@Russia_PPTP */
654            if (!(start->flags & SERV_LITERAL_ADDRESS) &&
655                sendto(start->sfd->fd, (char *)header, plen, 0,
656                &start->addr.sa,
657                sa_len(&start->addr)) != -1)
658#if 0
659            char *pdnsServer;
660            struct sockaddr_in *p;
661            int iSendResult = 0;
662            p = (struct sockaddr_in *)&(start->addr.sa);
663            pdnsServer = inet_ntoa(p->sin_addr);
664            iIsDhcpDNS = is_pptp_dhcp_dns(p->sin_addr.s_addr);
665
666            if(iIsDhcpDNS == iToDhcpDNS)
667            {
668                iSendResult = sendto(start->sfd->fd, (char *)header, plen, 0, &start->addr.sa, sa_len(&start->addr));
669            }
670            if (!(start->flags & SERV_LITERAL_ADDRESS) && iSendResult != -1)
671            /* Foxconn modified end, zacker, 07/29/2008,@Russia_PPTP */
672#endif
673/* foxconn modified end by Jenny Zhao, 12/10/2008,@Russia_PPTP new spec*/
674#endif /* MULTIPLE_PPPOE */
675    		{
676
677                /* Foxconn, add by MJ., for clarifying this issue. */
678#ifdef QUERY_DEBUG
679                    char *pdnsServer;
680                    struct sockaddr_in *p;
681
682                    p = (struct sockaddr_in *)&(start->addr.sa);
683                    pdnsServer = inet_ntoa(p->sin_addr);
684                    printf("\nsend to %s\n", pdnsServer);
685                    if (start->addr.sa.sa_family == AF_INET)
686                        printf("DNS server is using an IPv4 address.\n");
687                    else
688                        printf("DNS server is using an IPv6 address.\n");
689#endif
690                /* Foxconn, add-end by MJ., for clarifying this issue. */
691
692
693
694    		  if (!gotname)
695    		    strcpy(daemon->namebuff, "query");
696    		  if (start->addr.sa.sa_family == AF_INET)
697    		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
698    			      (struct all_addr *)&start->addr.in.sin_addr, 0);
699#ifdef HAVE_IPV6
700    		  else
701    		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
702    			      (struct all_addr *)&start->addr.in6.sin6_addr, 0);
703#endif
704    		  forwarded = 1;
705    		  forward->sentto = start;
706    		  //if (!forwardall)
707    		  if (!forward->forwardall)     /* Foxconn modified by EricHuang, 01/02/2008 */
708    		    break;
709
710    		  forward->forwardall++;    /* Foxconn added by EricHuang, 01/02/2008 */
711    		}/* Sento */
712        } /* check if server is legal */
713
714try_next_server:
715	  if (!(start = start->next))
716 	    start = daemon->servers;
717
718	  if (start == firstsentto)
719      {
720	      /* Foxconn add start, Max Ding, 07/06/2011 */
721          /* According to Home Router Spec IPv6 part:
722           * if there is no DNS server configured with an IPv6 address,
723           * forward the query to the IPv4 DNS server configured.
724           * if there is no DNS server configured with an IPv4 address,
725           * forward the query to the IPv6 DNS server configured.
726           */
727          if ((second_try == 0) && (forwarded == 0))
728          {
729              if ((gotname & F_IPV4) && !(gotname & F_IPV6))
730              {
731                  gotname = F_IPV6;
732                  second_try = 1;
733                  continue;
734              }
735              else if ((gotname & F_IPV6) && !(gotname & F_IPV4))
736              {
737                  gotname = F_IPV4;
738                  second_try = 1;
739                  continue;
740              }
741          }
742	      break;
743       }
744	}/* End of while(1) */
745
746    if (forwarded)
747        return;
748
749      /* could not send on, prepare to return */
750      header->id = htons(forward->orig_id);
751      forward->new_id = 0; /* cancel */
752    }
753
754  /* could not send on, return empty answer or address if known for whole domain */
755  plen = setup_reply(header, (unsigned int)plen, addrp, flags, daemon->local_ttl);
756  if( udpaddr && dst_addr)
757  {
758      send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
759  }
760
761  return;
762}
763
764/* Foxconn modified, Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
765#ifdef OPENDNS_PARENTAL_CONTROL
766static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
767			 union mysockaddr *serveraddr, unsigned int n, int discard_pseudoheader)
768#else
769static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
770			 union mysockaddr *serveraddr, unsigned int n)
771#endif
772{
773  unsigned char *pheader, *sizep;
774  unsigned int plen;
775
776  /* If upstream is advertising a larger UDP packet size
777	 than we allow, trim it so that we don't get overlarge
778	 requests for the client. */
779
780  if ((pheader = find_pseudoheader(header, n, &plen, &sizep)))
781    {
782      unsigned short udpsz;
783      unsigned char *psave = sizep;
784
785      GETSHORT(udpsz, sizep);
786      if (udpsz > daemon->edns_pktsz)
787	      PUTSHORT(daemon->edns_pktsz, psave);
788	  /* Foxconn add start, Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
789#ifdef OPENDNS_PARENTAL_CONTROL
790	  if (discard_pseudoheader
791	  && pheader + plen == (unsigned char *)header + n)
792 	  {
793 	      header->arcount = htons(ntohs(header->arcount) - 1);
794 	      n -= plen;
795 	      pheader = NULL;
796 	  }
797#endif
798 	  /* Foxconn add end  , Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
799  }
800
801  /* Complain loudly if the upstream server is non-recursive. */
802  if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0)
803    {
804      char addrbuff[ADDRSTRLEN];
805#ifdef HAVE_IPV6
806      if (serveraddr->sa.sa_family == AF_INET)
807	inet_ntop(AF_INET, &serveraddr->in.sin_addr, addrbuff, ADDRSTRLEN);
808      else if (serveraddr->sa.sa_family == AF_INET6)
809	inet_ntop(AF_INET6, &serveraddr->in6.sin6_addr, addrbuff, ADDRSTRLEN);
810#else
811      strcpy(addrbuff, inet_ntoa(serveraddr->in.sin_addr));
812#endif
813#ifdef USE_SYSLOG /* foxconn wklin added, 08/13/2007 */
814      syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
815#endif
816      return 0;
817    }
818
819  if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
820    return n;
821
822  if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
823    {
824      if (!(daemon->bogus_addr &&
825	    check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now)))
826	extract_addresses(header, n, daemon->namebuff, now, daemon->doctors);
827    }
828  else
829    {
830      unsigned short flags = F_NEG;
831      int munged = 0;
832
833      if (header->rcode == NXDOMAIN)
834	{
835	  /* if we forwarded a query for a locally known name (because it was for
836	     an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
837	     since we know that the domain exists, even if upstream doesn't */
838	  if (extract_request(header, n, daemon->namebuff, NULL) &&
839	      check_for_local_domain(daemon->namebuff, now, daemon->mxnames))
840	    {
841	      munged = 1;
842	      header->rcode = NOERROR;
843	    }
844	  else
845	    flags |= F_NXDOMAIN;
846	}
847
848      if (!(daemon->options & OPT_NO_NEG))
849	extract_neg_addrs(header, n, daemon->namebuff, now, flags);
850
851      /* do this after extract_neg_addrs. Ensure NODATA reply and remove
852	 nameserver info. */
853      if (munged)
854	{
855	  header->ancount = htons(0);
856	  header->nscount = htons(0);
857	  header->arcount = htons(0);
858	}
859    }
860
861  /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
862     sections of the packet. Find the new length here and put back pseudoheader
863     if it was removed. */
864  return resize_packet(header, n, pheader, plen);
865}
866
867/* sets new last_server */
868void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
869{
870    /* packet from peer server, extract data for cache, and send to
871     original requester */
872    struct frec *forward;
873    HEADER *header;
874    union mysockaddr serveraddr;
875    socklen_t addrlen = sizeof(serveraddr);
876    int n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
877    size_t nn;
878
879    /* Foxconn add start, Tony W.Y. Wang, 07/09/2010, @Parental Control OpenDNS */
880#ifdef OPENDNS_PARENTAL_CONTROL
881    FILE *fp;
882    char flag;
883    if((fp = fopen("/tmp/opendns.flag", "r")))
884    {
885        flag = fgetc(fp);
886        fclose(fp);
887    }
888#endif
889    /* Foxconn add start, Tony W.Y. Wang, 07/09/2010, @Parental Control OpenDNS */
890    /* Determine the address of the server replying  so that we can mark that as good */
891    serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
892#ifdef HAVE_IPV6
893    if (serveraddr.sa.sa_family == AF_INET6)
894    serveraddr.in6.sin6_flowinfo = htonl(0);
895#endif
896
897    header = (HEADER *)daemon->packet;
898    forward = lookup_frec(ntohs(header->id)); /* Foxconn added by EricHuang, 01/02/2008 */
899
900    if (n >= (int)sizeof(HEADER) && header->qr && forward)
901    {
902        /* Foxconn added start by EricHuang, 01/02/2008 */
903        struct server *server = forward->sentto;
904        /* Foxconn add start, Tony W.Y. Wang, 07/09/2010 */
905#ifdef OPENDNS_PARENTAL_CONTROL
906        if ((header->rcode == SERVFAIL || header->rcode == REFUSED) && forward->forwardall == 0 && (flag != '1'))
907#else
908        if ((header->rcode == SERVFAIL || header->rcode == REFUSED) && forward->forwardall == 0)
909#endif
910        /* Foxconn add end, Tony W.Y. Wang, 07/09/2010 */
911        /* for broken servers, attempt to send to another one. */
912        {
913            unsigned char *pheader;
914            size_t plen;
915
916            /* recreate query from reply */
917            pheader = find_pseudoheader(header, (size_t)n, &plen, NULL);
918            header->ancount = htons(0);
919            header->nscount = htons(0);
920            header->arcount = htons(0);
921            if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
922            {
923               forward->forwardall = 1;
924               header->qr = 0;
925               header->tc = 0;
926               forward_query(daemon, -1, NULL, NULL, 0, header, nn, now, forward);
927               return;
928            }
929        }
930        /* Foxconn added end by EricHuang, 01/02/2008 */
931
932
933        /* find good server by address if possible, otherwise assume the last one we sent to */
934        if ((forward->sentto->flags & SERV_TYPE) == 0)
935        {
936
937            if (header->rcode == SERVFAIL || header->rcode == REFUSED)
938                server = NULL;
939            else
940            {
941                struct server *last_server;
942                /* find good server by address if possible, otherwise assume the last one we sent to */
943                for (last_server = daemon->servers; last_server; last_server = last_server->next)
944                    if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
945                    sockaddr_isequal(&last_server->addr, &serveraddr))
946                    {
947                        server = last_server;
948                        break;
949                    }
950            }
951            daemon->last_server = server;
952
953	    }
954
955
956        /* If the answer is an error, keep the forward record in place in case
957        we get a good reply from another server. Kill it when we've
958        had replies from all to avoid filling the forwarding table when
959        everything is broken */
960        if (forward->forwardall == 0 || --forward->forwardall == 1 ||
961            (header->rcode != REFUSED && header->rcode != SERVFAIL))
962        {
963#ifdef OPENDNS_PARENTAL_CONTROL
964            if ((nn = process_reply(daemon, header, now, &server->addr, (size_t)n,
965                forward->discard_pseudoheader))) /* Foxconn modified, Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
966#else
967            if ((nn = process_reply(daemon, header, now,  &server->addr, (size_t)n)))
968#endif
969            {
970            /* foxconn wklin added start, 09/03/2007 @mpoe */
971#ifdef MULTIPLE_PPPOE
972                private_domain_check(header, n, daemon->namebuff);
973#endif /* MULTIPLE_PPPOE */
974            /* foxconn wklin added end, 09/03/2007 */
975
976                header->id = htons(forward->orig_id);
977                header->ra = 1; /* recursion if available */
978                send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
979                &forward->source, &forward->dest, forward->iface);
980            }
981            forward->new_id = 0; /* cancel */
982        }
983    }
984}
985
986void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
987{
988  HEADER *header = (HEADER *)daemon->packet;
989  union mysockaddr source_addr;
990  unsigned short type;
991  struct iname *tmp;
992  struct all_addr dst_addr;
993  int check_dst = !(daemon->options & OPT_NOWILD);
994  int m, n, if_index = 0;
995  struct iovec iov[1];
996  struct msghdr msg;
997  struct cmsghdr *cmptr;
998  union {
999    struct cmsghdr align; /* this ensures alignment */
1000#ifdef HAVE_IPV6
1001    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1002#endif
1003#if defined(IP_PKTINFO)
1004    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
1005#elif defined(IP_RECVDSTADDR)
1006    char control[CMSG_SPACE(sizeof(struct in_addr)) +
1007		 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1008#endif
1009  } control_u;
1010
1011  iov[0].iov_base = daemon->packet;
1012  iov[0].iov_len = daemon->edns_pktsz;
1013
1014  msg.msg_control = control_u.control;
1015  msg.msg_controllen = sizeof(control_u);
1016  msg.msg_flags = 0;
1017  msg.msg_name = &source_addr;
1018  msg.msg_namelen = sizeof(source_addr);
1019  msg.msg_iov = iov;
1020  msg.msg_iovlen = 1;
1021
1022  if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
1023    return;
1024
1025  /* wklin modified start, 01/24/2007 */
1026  /* Before getting dns IPs from ISP, dnsmasq will reject the
1027   * queries from clients, and client will thus think the dns queries
1028   * fails. When DoD is on, the first Internet access will always fail.
1029   * Modified the code here after the packet is consumed, so that the
1030   * dnsmasq won't reject the queries.
1031   */
1032  if (!daemon->servers)
1033    return;
1034  /* wklin modified end, 01/24/2007 */
1035
1036  source_addr.sa.sa_family = listen->family;
1037#ifdef HAVE_IPV6
1038  if (listen->family == AF_INET6)
1039    {
1040      check_dst = 1;
1041      source_addr.in6.sin6_flowinfo = htonl(0);
1042    }
1043#endif
1044
1045  if (check_dst && msg.msg_controllen < sizeof(struct cmsghdr))
1046    return;
1047
1048#if defined(IP_PKTINFO)
1049  if (check_dst && listen->family == AF_INET)
1050    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
1051      if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
1052	{
1053	  dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
1054	  if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
1055	}
1056#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
1057  if (check_dst && listen->family == AF_INET)
1058    {
1059      for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
1060	if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
1061	  dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
1062	else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1063	  if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
1064    }
1065#endif
1066
1067#ifdef HAVE_IPV6
1068  if (listen->family == AF_INET6)
1069    {
1070      for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
1071	if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
1072	  {
1073	    dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
1074	    if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
1075	  }
1076    }
1077#endif
1078
1079  if (n < (int)sizeof(HEADER) || header->qr)
1080    return;
1081
1082  /* enforce available interface configuration */
1083  if (check_dst)
1084    {
1085      struct ifreq ifr;
1086
1087      if (if_index == 0)
1088	return;
1089
1090      if (daemon->if_except || daemon->if_names)
1091	{
1092#ifdef SIOCGIFNAME
1093	  ifr.ifr_ifindex = if_index;
1094	  if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
1095	    return;
1096#else
1097	  if (!if_indextoname(if_index, ifr.ifr_name))
1098	    return;
1099#endif
1100	}
1101
1102      for (tmp = daemon->if_except; tmp; tmp = tmp->next)
1103	if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
1104	  return;
1105
1106      if (daemon->if_names || daemon->if_addrs)
1107	{
1108	  for (tmp = daemon->if_names; tmp; tmp = tmp->next)
1109	    if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
1110	      break;
1111	  if (!tmp)
1112	    for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
1113	      if (tmp->addr.sa.sa_family == listen->family)
1114		{
1115		  if (tmp->addr.sa.sa_family == AF_INET &&
1116		      tmp->addr.in.sin_addr.s_addr == dst_addr.addr.addr4.s_addr)
1117		    break;
1118#ifdef HAVE_IPV6
1119		  else if (tmp->addr.sa.sa_family == AF_INET6 &&
1120			   memcmp(&tmp->addr.in6.sin6_addr,
1121				  &dst_addr.addr.addr6,
1122				  sizeof(struct in6_addr)) == 0)
1123		    break;
1124#endif
1125		}
1126	  if (!tmp)
1127	    return;
1128	}
1129    }
1130
1131  if (extract_request(header, (unsigned int)n, daemon->namebuff, &type))
1132    {
1133      if (listen->family == AF_INET)
1134	log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
1135		  (struct all_addr *)&source_addr.in.sin_addr, type);
1136#ifdef HAVE_IPV6
1137      else
1138	log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
1139		  (struct all_addr *)&source_addr.in6.sin6_addr, type);
1140#endif
1141    }
1142
1143  m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, daemon, now);
1144  if (m >= 1)
1145    send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
1146  else
1147    forward_query(daemon, listen->fd, &source_addr, &dst_addr, if_index,
1148		  header, n, now, NULL); /* Foxconn modified by EricHuang, 01/02/2008 */
1149}
1150
1151static int read_write(int fd, char *packet, int size, int rw)
1152{
1153  int n, done;
1154
1155  for (done = 0; done < size; done += n)
1156    {
1157    retry:
1158      if (rw)
1159	n = read(fd, &packet[done], (size_t)(size - done));
1160      else
1161	n = write(fd, &packet[done], (size_t)(size - done));
1162
1163      if (n == 0)
1164	return 0;
1165      else if (n == -1)
1166	{
1167	  if (errno == EINTR)
1168	    goto retry;
1169	  else if (errno == EAGAIN)
1170	    {
1171	      struct timespec waiter;
1172	      waiter.tv_sec = 0;
1173	      waiter.tv_nsec = 10000;
1174	      nanosleep(&waiter, NULL);
1175	      goto retry;
1176	    }
1177	  else
1178	    return 0;
1179	}
1180    }
1181  return 1;
1182}
1183
1184/* The daemon forks before calling this: it should deal with one connection,
1185   blocking as neccessary, and then return. Note, need to be a bit careful
1186   about resources for debug mode, when the fork is suppressed: that's
1187   done by the caller. */
1188char *tcp_request(struct daemon *daemon, int confd, time_t now)
1189{
1190  int size = 0, m;
1191  unsigned short qtype, gotname;
1192  unsigned char c1, c2;
1193  /* Max TCP packet + slop */
1194  char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
1195  HEADER *header;
1196  struct server *last_server;
1197
1198  while (1)
1199    {
1200      if (!packet ||
1201	  !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1202	  !(size = c1 << 8 | c2) ||
1203	  !read_write(confd, packet, size, 1))
1204       	return packet;
1205
1206      if (size < (int)sizeof(HEADER))
1207	continue;
1208
1209      header = (HEADER *)packet;
1210
1211      if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
1212	{
1213	  union mysockaddr peer_addr;
1214	  socklen_t peer_len = sizeof(union mysockaddr);
1215
1216	  if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
1217	    {
1218	      if (peer_addr.sa.sa_family == AF_INET)
1219		log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
1220			  (struct all_addr *)&peer_addr.in.sin_addr, qtype);
1221#ifdef HAVE_IPV6
1222	      else
1223		log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
1224			  (struct all_addr *)&peer_addr.in6.sin6_addr, qtype);
1225#endif
1226	    }
1227	}
1228
1229      /* m > 0 if answered from cache */
1230      m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, daemon, now);
1231
1232      if (m == 0)
1233	{
1234	  unsigned short flags = 0;
1235	  struct all_addr *addrp = NULL;
1236	  int type = 0;
1237	  char *domain = NULL;
1238
1239	  if (gotname)
1240	    flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
1241
1242	  if (type != 0  || (daemon->options & OPT_ORDER) || !daemon->last_server)
1243	    last_server = daemon->servers;
1244	  else
1245	    last_server = daemon->last_server;
1246
1247	  if (!flags && last_server)
1248	    {
1249	      struct server *firstsendto = NULL;
1250
1251	      /* Loop round available servers until we succeed in connecting to one.
1252	         Note that this code subtley ensures that consecutive queries on this connection
1253	         which can go to the same server, do so. */
1254	      while (1)
1255		{
1256		  if (!firstsendto)
1257		    firstsendto = last_server;
1258		  else
1259		    {
1260		      if (!(last_server = last_server->next))
1261			last_server = daemon->servers;
1262
1263		      if (last_server == firstsendto)
1264			break;
1265		    }
1266
1267		  /* server for wrong domain */
1268		  if (type != (last_server->flags & SERV_TYPE) ||
1269		      (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
1270		    continue;
1271
1272		  if ((last_server->tcpfd == -1) &&
1273		      (last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
1274		      connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
1275		    {
1276		      close(last_server->tcpfd);
1277		      last_server->tcpfd = -1;
1278		    }
1279
1280		  if (last_server->tcpfd == -1)
1281		    continue;
1282
1283		  c1 = size >> 8;
1284		  c2 = size;
1285
1286		  if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
1287		      !read_write(last_server->tcpfd, &c2, 1, 0) ||
1288		      !read_write(last_server->tcpfd, packet, size, 0) ||
1289		      !read_write(last_server->tcpfd, &c1, 1, 1) ||
1290		      !read_write(last_server->tcpfd, &c2, 1, 1))
1291		    {
1292		      close(last_server->tcpfd);
1293		      last_server->tcpfd = -1;
1294		      continue;
1295		    }
1296
1297		  m = (c1 << 8) | c2;
1298		  if (!read_write(last_server->tcpfd, packet, m, 1))
1299		    return packet;
1300
1301		  if (!gotname)
1302		    strcpy(daemon->namebuff, "query");
1303		  if (last_server->addr.sa.sa_family == AF_INET)
1304		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
1305			      (struct all_addr *)&last_server->addr.in.sin_addr, 0);
1306#ifdef HAVE_IPV6
1307		  else
1308		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
1309			      (struct all_addr *)&last_server->addr.in6.sin6_addr, 0);
1310#endif
1311
1312		  /* There's no point in updating the cache, since this process will exit and
1313		     lose the information after one query. We make this call for the alias and
1314		     bogus-nxdomain side-effects. */
1315		  /* Foxconn modified, Tony W.Y. Wang, 12/02/2008, @Parental Control OpenDNS */
1316#ifdef OPENDNS_PARENTAL_CONTROL
1317		  m = process_reply(daemon, header, now, &last_server->addr, (unsigned int)m, 0);
1318#else
1319		  m = process_reply(daemon, header, now, &last_server->addr, (unsigned int)m);
1320#endif
1321		  break;
1322		}
1323	    }
1324
1325	  /* In case of local answer or no connections made. */
1326	  if (m == 0)
1327	    m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
1328	}
1329
1330      c1 = m>>8;
1331      c2 = m;
1332      if (!read_write(confd, &c1, 1, 0) ||
1333	  !read_write(confd, &c2, 1, 0) ||
1334	  !read_write(confd, packet, m, 0))
1335	return packet;
1336    }
1337}
1338
1339static struct frec *get_new_frec(time_t now)
1340{
1341  struct frec *f = frec_list, *oldest = NULL;
1342  time_t oldtime = now;
1343  int count = 0;
1344  static time_t warntime = 0;
1345
1346  while (f)
1347    {
1348      if (f->new_id == 0)
1349	{
1350	  f->time = now;
1351	  return f;
1352	}
1353
1354      if (difftime(f->time, oldtime) <= 0)
1355	{
1356	  oldtime = f->time;
1357	  oldest = f;
1358	}
1359
1360      count++;
1361      f = f->next;
1362    }
1363
1364  /* can't find empty one, use oldest if there is one
1365     and it's older than timeout */
1366  if (oldest && difftime(now, oldtime)  > TIMEOUT)
1367    {
1368      oldest->time = now;
1369      return oldest;
1370    }
1371
1372  if (count > FTABSIZ)
1373    { /* limit logging rate so syslog isn't DOSed either */
1374      if (!warntime || difftime(now, warntime) > LOGRATE)
1375	{
1376	  warntime = now;
1377#ifdef USE_SYSLOG /* foxconn wklin added, 08/13/2007 */
1378	  syslog(LOG_WARNING, "forwarding table overflow: check for server loops.");
1379#endif
1380	}
1381      return NULL;
1382    }
1383
1384  if ((f = (struct frec *)malloc(sizeof(struct frec))))
1385    {
1386      f->next = frec_list;
1387      f->time = now;
1388      frec_list = f;
1389    }
1390  return f; /* OK if malloc fails and this is NULL */
1391}
1392
1393static struct frec *lookup_frec(unsigned short id)
1394{
1395  struct frec *f;
1396
1397  for(f = frec_list; f; f = f->next)
1398    if (f->new_id == id)
1399      return f;
1400
1401  return NULL;
1402}
1403
1404static struct frec *lookup_frec_by_sender(unsigned short id,
1405					  union mysockaddr *addr)
1406{
1407    struct frec *f;
1408
1409    if( addr )
1410    {
1411  	    for(f = frec_list; f; f = f->next)
1412    	    if (f->new_id &&
1413			    f->orig_id == id &&
1414			    sockaddr_isequal(&f->source, addr))
1415          return f;
1416    }
1417
1418  return NULL;
1419}
1420
1421
1422/* return unique random ids between 1 and 65535 */
1423static unsigned short get_id(void)
1424{
1425  unsigned short ret = 0;
1426
1427  while (ret == 0)
1428    {
1429      ret = rand16();
1430
1431      /* scrap ids already in use */
1432      if ((ret != 0) && lookup_frec(ret))
1433	ret = 0;
1434    }
1435
1436  return ret;
1437}
1438
1439/* Foxconn add start, Tony W.Y. Wang, 12/05/2008, @Parental Control OpenDNS */
1440#ifdef OPENDNS_PARENTAL_CONTROL
1441#define PROC_ARP_FILE    "/proc/net/arp"
1442int get_mac_from_arp(char *dnsquery_src_ip, char *src_mac)
1443{
1444    FILE *fp;
1445    char buf[512];
1446    char buffer[64];
1447    int  i = 0, index = 0;
1448    int exist_num = 0;
1449    char *p_str;
1450    if (!(fp = fopen(PROC_ARP_FILE, "r"))) {
1451        perror(PROC_ARP_FILE);
1452        return 0;
1453    }
1454    fgets(buf, sizeof(buf), fp); /* ignore the first line */
1455    while (fgets(buf, sizeof(buf), fp)) {      /* get all the lines */
1456        p_str = strstr (buf, dnsquery_src_ip); /* check whether the src_ip exist in the line */
1457        if(p_str)
1458        {
1459            p_str = p_str + 41;
1460            strncpy(buf,p_str,17);             /* get MAC 00:11:22:33:44:55 */
1461            buf[17] = '\0';
1462            for(i=0; i<17; i++)                /* transfor MAC to 001122334455 */
1463            {
1464                if(buf[i] != ':')
1465                {
1466                    buffer[index] = buf[i];
1467                    index++;
1468                }
1469            }
1470            buffer[index] = '\0';
1471            strcpy(src_mac, buffer);
1472		    fclose(fp);
1473		    return 0;
1474        }
1475    }
1476    fclose(fp);
1477    return 1;
1478}
1479
1480int char_to_byte(char string_id[], unsigned char byte_id[])
1481{
1482    int i = 0;
1483    int tmp = 0;
1484    for (i=0; i<16; i+=2)
1485    {
1486        if(string_id[i] >= '0' && string_id[i] <= '9')
1487            tmp = string_id[i] - '0';
1488        else if(string_id[i] >= 'A' && string_id[i] <= 'F')
1489            tmp = string_id[i] - 'A' + 10;
1490        if(string_id[i+1] >= '0' && string_id[i+1] <= '9')
1491            tmp = tmp*16 + (string_id[i+1] - '0');
1492        else if(string_id[i+1] >= 'A' && string_id[i+1] <= 'F')
1493            tmp = tmp*16 + (string_id[i+1] - 'A' + 10);
1494        byte_id[i/2] = (unsigned char)tmp;
1495    }
1496    return 0;
1497}
1498
1499static void get_device_id(char src_mac[], char id[])
1500{
1501    FILE *fp;
1502    char opendns_tbl[2048] = "";
1503    int is_found = 0;
1504    char *p_str = NULL;
1505
1506    if((fp = fopen("/tmp/opendns.tbl", "r")))
1507    {
1508        while (fgets(opendns_tbl, sizeof(opendns_tbl), fp))
1509        {
1510            p_str = strstr (opendns_tbl, "DEFAULT");
1511            if(p_str)
1512            {
1513                is_found = 1;
1514                p_str = p_str + strlen("DEFAULT") + 1;
1515                strncpy(id, p_str, 16);
1516                id[16] = '\0';
1517            }
1518            //p_str = strstr (opendns_tbl, src_mac);
1519            p_str = strcasestr (opendns_tbl, src_mac);
1520            if(p_str)
1521            {
1522                is_found = 1;
1523                p_str = p_str + strlen(src_mac) + 1;
1524                strncpy(id, p_str, 16);
1525                id[16] = '\0';
1526                break;
1527            }
1528        }
1529        fclose(fp);
1530    }
1531    if(!is_found)
1532    {
1533        strcpy(id, "0000111111111111");
1534    }
1535}
1536#endif
1537/* Foxconn add end  , Tony W.Y. Wang, 12/05/2008, @Parental Control OpenDNS */
1538
1539
1540