1/* dnsmasq is Copyright (c) 2000 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
14/* Some code in this file contributed by Rob Funk. */
15
16#include "dnsmasq.h"
17
18/* Prefer arc4random(3) over random(3) over rand(3) */
19/* Also prefer /dev/urandom over /dev/random, to preserve the entropy pool */
20#ifdef HAVE_ARC4RANDOM
21# define rand()		arc4random()
22# define srand(s)	(void)0
23# define RANDFILE	(NULL)
24#else
25# ifdef HAVE_RANDOM
26#  define rand()	random()
27#  define srand(s)	srandom(s)
28# endif
29# ifdef HAVE_DEV_URANDOM
30#  define RANDFILE	"/dev/urandom"
31# else
32#  ifdef HAVE_DEV_RANDOM
33#   define RANDFILE	"/dev/random"
34#  else
35#   define RANDFILE	(NULL)
36#  endif
37# endif
38#endif
39
40unsigned short rand16(void)
41{
42  static int been_seeded = 0;
43  const char *randfile = RANDFILE;
44
45  if (! been_seeded)
46    {
47      int fd, n = 0;
48      unsigned int c = 0, seed = 0, badseed;
49      char sbuf[sizeof(seed)];
50      char *s;
51      struct timeval now;
52
53      /* get the bad seed as a backup */
54      /* (but we'd rather have something more random) */
55      gettimeofday(&now, NULL);
56      badseed = now.tv_sec ^ now.tv_usec ^ (getpid() << 16);
57
58      fd = open(randfile, O_RDONLY);
59      if (fd < 0)
60	seed = badseed;
61      else
62	{
63	  s = (char *) &seed;
64	  while ((c < sizeof(seed)) &&
65		 ((n = read(fd, sbuf, sizeof(seed)) > 0)))
66	    {
67	      memcpy(s, sbuf, n);
68	      s += n;
69	      c += n;
70	    }
71	  if (n < 0)
72	    seed = badseed;
73	  close(fd);
74	}
75
76      srand(seed);
77      been_seeded = 1;
78    }
79
80  /* Some rand() implementations have less randomness in low bits
81   * than in high bits, so we only pay attention to the high ones.
82   * But most implementations don't touch the high bit, so we
83   * ignore that one.
84   */
85  return( (unsigned short) (rand() >> 15) );
86}
87
88int atoi_check(char *a, int *res)
89{
90  char *p;
91
92  for (p = a; *p; p++)
93     if (*p < '0' || *p > '9')
94       return 0;
95
96  *res = atoi(a);
97  return 1;
98}
99
100int legal_char(char c)
101{
102  /* check for legal char a-z A-Z 0-9 -
103     (also / , used for RFC2317 and _ used in windows queries) */
104  if ((c >= 'A' && c <= 'Z') ||
105      (c >= 'a' && c <= 'z') ||
106      (c >= '0' && c <= '9') ||
107      c == '-' || c == '/' || c == '_')
108    return 1;
109
110  return 0;
111}
112
113int canonicalise(char *s)
114{
115  /* check for legal chars and remove trailing .
116     also fail empty string. */
117  int l = strlen(s);
118  char c;
119
120  if (l == 0) return 0;
121
122  if (s[l-1] == '.')
123    {
124      if (l == 1) return 0;
125      s[l-1] = 0;
126    }
127
128  while ((c = *s++))
129    if (c != '.' && !legal_char(c))
130      return 0;
131
132  return 1;
133}
134
135/* for use during startup */
136void *safe_malloc(int size)
137{
138  void *ret = malloc(size);
139
140  if (!ret)
141    die("could not get memory", NULL);
142
143  return ret;
144}
145
146char *safe_string_alloc(char *cp)
147{
148  char *ret = NULL;
149
150  if (cp && strlen(cp) != 0)
151    {
152      ret = safe_malloc(strlen(cp)+1);
153      strcpy(ret, cp);
154    }
155
156  return ret;
157}
158
159void complain(char *message, char *arg1)
160{
161  char *errmess = strerror(errno);
162
163  if (!arg1)
164    arg1 = errmess;
165
166  fprintf(stderr, "dnsmasq: ");
167  fprintf(stderr, message, arg1, errmess);
168  fprintf(stderr, "\n");
169
170#ifdef USE_SYSLOG /* foxconn wklin added, 08/13/2007 */
171  syslog(LOG_CRIT, message, arg1, errmess);
172#endif
173}
174
175void die(char *message, char *arg1)
176{
177  complain(message, arg1);
178#ifdef USE_SYSLOG /* foxconn wklin added, 08/13/2007 */
179  syslog(LOG_CRIT, "FAILED to start up");
180#endif
181  exit(1);
182}
183
184int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
185{
186  if (s1->sa.sa_family == s2->sa.sa_family)
187    {
188      if (s1->sa.sa_family == AF_INET &&
189	  s1->in.sin_port == s2->in.sin_port &&
190	  memcmp(&s1->in.sin_addr, &s2->in.sin_addr, sizeof(struct in_addr)) == 0)
191	return 1;
192#ifdef HAVE_IPV6
193      if (s1->sa.sa_family == AF_INET6 &&
194	  s1->in6.sin6_port == s2->in6.sin6_port &&
195	  s1->in6.sin6_flowinfo == s2->in6.sin6_flowinfo &&
196	  memcmp(&s1->in6.sin6_addr, &s2->in6.sin6_addr, sizeof(struct in6_addr)) == 0)
197	return 1;
198#endif
199    }
200  return 0;
201}
202
203int sa_len(union mysockaddr *addr)
204{
205#ifdef HAVE_SOCKADDR_SA_LEN
206  return addr->sa.sa_len;
207#else
208#ifdef HAVE_IPV6
209  if (addr->sa.sa_family == AF_INET6)
210    return sizeof(addr->in6);
211  else
212#endif
213    return sizeof(addr->in);
214#endif
215}
216
217/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
218int hostname_isequal(unsigned char *a, unsigned char *b)
219{
220  unsigned int c1, c2;
221
222  do {
223    c1 = *a++;
224    c2 = *b++;
225
226    if (c1 >= 'A' && c1 <= 'Z')
227      c1 += 'a' - 'A';
228    if (c2 >= 'A' && c2 <= 'Z')
229      c2 += 'a' - 'A';
230
231    if (c1 != c2)
232      return 0;
233  } while (c1);
234
235  return 1;
236}
237
238time_t dnsmasq_time(int fd)
239{
240#ifdef HAVE_BROKEN_RTC
241  /* we use uptime as a time-base, rather than epoch time
242     because epoch time can break when a machine contacts
243     a nameserver and updates it. */
244  char buf[30];
245  lseek(fd, 0, SEEK_SET);
246  read(fd, buf, 30);
247  return (time_t)atol(buf);
248#else
249  fd = 0; /* stop warning */
250  return time(NULL);
251#endif
252}
253
254int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
255{
256  return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
257}