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/* 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)	(NULL)
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#ifdef HAVE_FILE_SYSTEM
44  const char *randfile = RANDFILE;
45#endif
46
47  if (! been_seeded)
48    {
49#ifdef HAVE_FILE_SYSTEM
50      int fd, n = 0;
51#endif
52      unsigned int c = 0, seed = 0, badseed;
53#ifdef HAVE_FILE_SYSTEM
54      char sbuf[sizeof(seed)];
55      char *s;
56#endif
57      struct timeval now;
58
59      /* get the bad seed as a backup */
60      /* (but we'd rather have something more random) */
61      gettimeofday(&now, NULL);
62      badseed = now.tv_sec ^ now.tv_usec ^ (getpid() << 16);
63
64#ifdef HAVE_FILE_SYSTEM
65      fd = open(randfile, O_RDONLY);
66      if (fd < 0)
67	seed = badseed;
68      else
69	{
70	  s = (char *) &seed;
71	  while ( (c < sizeof(seed)) &&
72		  ((n = read(fd, sbuf, sizeof(seed)) > 0)) )
73	    {
74	      memcpy(s, sbuf, n);
75	      s += n;
76	      c += n;
77	    }
78	  if (n < 0)
79	    {
80	      seed = badseed;
81	    }
82	}
83      if (seed != badseed)
84	close(fd);
85#else
86      seed = badseed;
87#endif
88
89      srand(seed);
90      been_seeded = 1;
91    }
92
93  /* Some rand() implementations have less randomness in low bits
94   * than in high bits, so we only pay attention to the high ones.
95   * But most implementations don't touch the high bit, so we
96   * ignore that one.
97   */
98  return( (unsigned short) (rand() >> 15) );
99}
100
101void canonicalise(char *s)
102{
103  char *p;
104  int l = strlen(s);
105
106  for (p=s; *p; p++)
107    *p = tolower(*p);
108
109  if (l>0 && s[l-1] == '.')
110    s[l-1] = 0;
111}
112
113/*
114* memory counters - debugging only
115*/
116#if defined(DEBUG_MEMORY)
117static unsigned int allocated_memory_count = 0;
118void dnsr_mem_used(void)
119{
120	printf("Total memory used: %u bytes\n", allocated_memory_count);
121}
122#endif
123
124void safe_free(void *mem)
125{
126#if defined(DEBUG_MEMORY)
127	unsigned int size;
128	char *ptr = mem;
129	if (ptr == NULL)
130	{
131		printf("safe_free: NULL pointer!\n");
132		return;
133	}
134	else if (((unsigned int)ptr)&3)
135	{
136		printf("safe_free: Memory at 0x%08x not aligned!\n", mem);
137	}
138	else
139	{
140		if (*(--(unsigned int *)ptr) != 0xDEADBEEF)
141		{
142			printf("safe_free: Memory at 0x%08x untagged!\n", mem);
143		}
144		else
145		{
146			size = *(--(unsigned int *)ptr);
147			allocated_memory_count -= size;
148			mem = ptr;
149		}
150	}
151#endif
152	free(mem);
153}
154
155/* for use during startup */
156void *safe_malloc(int size)
157{
158#if defined(DEBUG_MEMORY)
159  char *ret = memalign(4, ((size+3)&~3)+3*sizeof(unsigned int));
160#else
161  void *ret = malloc(size);
162#endif
163
164  if (!ret)
165    die("could not get memory", NULL);
166
167#if defined(DEBUG_MEMORY)
168   *(unsigned int *)ret = size;
169   ret += sizeof(unsigned int);
170   *(unsigned int *)ret = 0xDEADBEEF;
171   ret += sizeof(unsigned int);
172   memset(ret, 0, size);
173   *(unsigned int *)(ret+((size+3)&~3)) = 0xDEADBEEF;
174   allocated_memory_count += size;
175#endif
176
177  return ret;
178}
179
180char *safe_string_alloc(char *cp)
181{
182  char *ret = NULL;
183
184  if (cp && strlen(cp) != 0)
185    {
186      ret = safe_malloc(strlen(cp)+1);
187      strcpy(ret, cp);
188    }
189
190  return ret;
191}
192
193void die(char *message, char *arg1)
194{
195  char *errmess = strerror(errno);
196
197  if (!arg1)
198    arg1 = errmess;
199
200  fprintf(stderr, "dnsmasq: ");
201  fprintf(stderr, message, arg1, errmess);
202  fprintf(stderr, "\n");
203
204  syslog(LOG_CRIT, message, arg1, errmess);
205  syslog(LOG_CRIT, "FAILED to start up");
206  exit(1);
207}
208
209int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
210{
211  if (s1->sa.sa_family == s2->sa.sa_family)
212    {
213      if (s1->sa.sa_family == AF_INET &&
214	  s1->in.sin_port == s2->in.sin_port &&
215	  memcmp(&s1->in.sin_addr, &s2->in.sin_addr, sizeof(struct in_addr)) == 0)
216	return 1;
217#ifdef HAVE_IPV6
218      if (s1->sa.sa_family == AF_INET6 &&
219	  s1->in6.sin6_port == s2->in6.sin6_port &&
220	  s1->in6.sin6_flowinfo == s2->in6.sin6_flowinfo &&
221	  memcmp(&s1->in6.sin6_addr, &s2->in6.sin6_addr, sizeof(struct in6_addr)) == 0)
222	return 1;
223#endif
224    }
225  return 0;
226}
227
228int sa_len(union mysockaddr *addr)
229{
230#ifdef HAVE_SOCKADDR_SA_LEN
231  return addr->sa.sa_len;
232#else
233#ifdef HAVE_IPV6
234  if (addr->sa.sa_family == AF_INET6)
235    return sizeof(addr->in6);
236  else
237#endif
238    return sizeof(addr->in);
239#endif
240}
241