rwrap: Compare dns names case insensitive.
[obnox/cwrap/resolv_wrapper.git] / tests / torture.c
1 /*
2  * Copyright (C) Andreas Schneider 2013 <asn@samba.org>
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the author nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "config.h"
35
36 #include "torture.h"
37
38 #include <errno.h>
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/socket.h>
43 #include <signal.h>
44 #include <fcntl.h>
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <time.h>
51 #include <stdbool.h>
52
53 #define TORTURE_DNS_SRV_IPV4 "127.0.0.10"
54 /* socket wrapper IPv6 prefix  fd00::5357:5fxx */
55 #define TORTURE_DNS_SRV_IPV6 "fd00::5357:5f0a"
56 #define TORTURE_DNS_SRV_PORT 53
57
58 #define TORTURE_SOCKET_DIR "/tmp/test_resolv_wrapper_XXXXXX"
59 #define TORTURE_DNS_SRV_PIDFILE "dns_srv.pid"
60 #define TORTURE_PCAP_FILE "socket_trace.pcap"
61
62 #define RWRAP_RESOLV_CONF_TMPL "rwrap_resolv_conf_XXXXXX"
63
64 const char *torture_server_address(int family)
65 {
66         switch (family) {
67         case AF_INET: {
68                 const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4");
69
70                 if (ip4 != NULL && ip4[0] != '\0') {
71                         return ip4;
72                 }
73
74                 return TORTURE_DNS_SRV_IPV4;
75         }
76 #ifdef HAVE_IPV6
77         case AF_INET6: {
78                 const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6");
79
80                 if (ip6 != NULL && ip6[0] != '\0') {
81                         return ip6;
82                 }
83
84                 return TORTURE_DNS_SRV_IPV6;
85         }
86 #endif
87         default:
88                 return NULL;
89         }
90
91         return NULL;
92 }
93
94 int torture_server_port(void)
95 {
96         char *env = getenv("TORTURE_SERVER_PORT");
97
98         if (env != NULL && env[0] != '\0' && strlen(env) < 6) {
99                 int port = atoi(env);
100
101                 if (port > 0 && port < 65536) {
102                         return port;
103                 }
104         }
105
106         return TORTURE_DNS_SRV_PORT;
107 }
108
109 void torture_setup_socket_dir(void **state)
110 {
111         struct torture_state *s;
112         const char *p;
113         size_t len;
114
115         s = malloc(sizeof(struct torture_state));
116         assert_non_null(s);
117
118         s->socket_dir = strdup(TORTURE_SOCKET_DIR);
119         assert_non_null(s->socket_dir);
120
121         p = mkdtemp(s->socket_dir);
122         assert_non_null(p);
123
124         /* pcap file */
125         len = strlen(p) + 1 + strlen(TORTURE_PCAP_FILE) + 1;
126
127         s->pcap_file = malloc(len);
128         assert_non_null(s->pcap_file);
129
130         snprintf(s->pcap_file, len, "%s/%s", p, TORTURE_PCAP_FILE);
131
132         /* pid file */
133         len = strlen(p) + 1 + strlen(TORTURE_DNS_SRV_PIDFILE) + 1;
134
135         s->srv_pidfile = malloc(len);
136         assert_non_null(s->srv_pidfile);
137
138         snprintf(s->srv_pidfile, len, "%s/%s", p, TORTURE_DNS_SRV_PIDFILE);
139
140         setenv("SOCKET_WRAPPER_DIR", p, 1);
141         setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1);
142         setenv("SOCKET_WRAPPER_PCAP_FILE", s->pcap_file, 1);
143
144         *state = s;
145 }
146
147 const char *torture_server_resolv_conf(void **state)
148 {
149         struct torture_state *s = (struct torture_state *) *state;
150         if (s == NULL) {
151                 return NULL;
152         }
153         return s->resolv_conf;
154 }
155
156 static char *torture_setup_resolv_conf(const char **nameservers, size_t num_ns)
157 {
158         char *path;
159         int rc_fd;
160         FILE *resolv_conf;
161         size_t i;
162
163         path = strdup(RWRAP_RESOLV_CONF_TMPL);
164         assert_non_null(path);
165         rc_fd = mkstemp(path);
166         assert_non_null(path);
167         resolv_conf = fdopen(rc_fd, "a");
168         assert_non_null(resolv_conf);
169
170         for (i = 0; i < num_ns; i++) {
171                 fputs("nameserver ", resolv_conf);
172                 fputs(nameservers[i], resolv_conf);
173                 fputs("\n", resolv_conf);
174         }
175         fflush(resolv_conf);
176
177         fclose(resolv_conf);
178         close(rc_fd);
179         return path;
180 }
181
182 static void torture_teardown_resolv_conf(char *resolv_conf_path)
183 {
184         unlink(resolv_conf_path);
185         free(resolv_conf_path);
186 }
187
188 static void torture_setup_dns_srv_ip(void **state,
189                                      int family,
190                                      const char *ip,
191                                      int port)
192 {
193         struct torture_state *s;
194         char start_dns_srv[1024] = {0};
195         int count = 0;
196         int rc;
197         const char *nameservers[1] = {
198             torture_server_address(family),
199         };
200
201         torture_setup_socket_dir(state);
202
203         s = (struct torture_state *) *state;
204
205         /* set default iface for the server */
206         setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
207
208         snprintf(start_dns_srv, sizeof(start_dns_srv),
209                  "%s/tests/dns_srv -b %s -p %d -D --pid %s",
210                  BINARYDIR, ip, port, s->srv_pidfile);
211
212         rc = system(start_dns_srv);
213         assert_int_equal(rc, 0);
214
215         do {
216                 struct stat sb;
217
218                 count++;
219                 if (count > 100) {
220                         break;
221                 }
222
223                 rc = stat(s->srv_pidfile, &sb);
224                 usleep(200);
225         } while (rc != 0);
226         assert_int_equal(rc, 0);
227
228         /* set default iface for the client */
229         setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1);
230
231         /* write a resolv.conf for the client */
232         s->resolv_conf = torture_setup_resolv_conf(nameservers, 1);
233 }
234
235 void torture_setup_dns_srv_ipv4(void **state)
236 {
237         torture_setup_dns_srv_ip(state,
238                                  AF_INET,
239                                  "0.0.0.0",
240                                  torture_server_port());
241 }
242
243 void torture_setup_dns_srv_ipv6(void **state)
244 {
245         torture_setup_dns_srv_ip(state,
246                                  AF_INET6,
247                                  "::",
248                                  torture_server_port());
249 }
250
251 void torture_teardown_socket_dir(void **state)
252 {
253         struct torture_state *s = (struct torture_state *) *state;
254         char *env = getenv("TORTURE_SKIP_CLEANUP");
255         char remove_cmd[1024] = {0};
256         int rc;
257
258         if (env != NULL && env[0] == '1') {
259                 fprintf(stderr, ">>> Skipping cleanup of %s", s->socket_dir);
260         } else {
261                 snprintf(remove_cmd, sizeof(remove_cmd), "rm -rf %s", s->socket_dir);
262
263                 rc = system(remove_cmd);
264                 if (rc < 0) {
265                         fprintf(stderr, "%s failed: %s", remove_cmd, strerror(errno));
266                 }
267         }
268
269         free(s->socket_dir);
270         free(s->pcap_file);
271         free(s->srv_pidfile);
272         free(s);
273 }
274
275 void torture_teardown_dns_srv(void **state)
276 {
277         struct torture_state *s = (struct torture_state *) *state;
278         char buf[8] = {0};
279         long int tmp;
280         ssize_t rc;
281         pid_t pid;
282         int fd;
283         bool is_running = true;
284         int count;
285
286         /* read the pidfile */
287         fd = open(s->srv_pidfile, O_RDONLY);
288         if (fd < 0) {
289                 goto done;
290         }
291
292         rc = read(fd, buf, sizeof(buf));
293         close(fd);
294         if (rc <= 0) {
295                 goto done;
296         }
297
298         buf[sizeof(buf) - 1] = '\0';
299
300         tmp = strtol(buf, NULL, 10);
301         if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) {
302                 goto done;
303         }
304
305         pid = (pid_t)(tmp & 0xFFFF);
306
307         /* Make sure the daemon goes away! */
308         for (count = 0; count < 10; count++) {
309                 kill(pid, SIGTERM);
310
311                 usleep(200);
312
313                 rc = kill(pid, 0);
314                 if (rc != 0) {
315                         is_running = false;
316                         break;
317                 }
318         }
319
320         if (is_running) {
321                 fprintf(stderr,
322                         "WARNING the DNS server is still running!\n");
323         }
324
325 done:
326         torture_teardown_resolv_conf(s->resolv_conf);
327         torture_teardown_socket_dir(state);
328 }
329
330 void torture_generate_random_buffer(uint8_t *out, int len)
331 {
332         int i;
333
334         srand(time(NULL));
335
336         for (i = 0; i < len; i++) {
337                 out[i] = (uint8_t)rand();
338         }
339 }