1/* mrtrace.c
2
3   Subroutines that support minires tracing... */
4
5/*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2001-2003 by Internet Software Consortium
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 *   Internet Systems Consortium, Inc.
22 *   950 Charter Street
23 *   Redwood City, CA 94063
24 *   <info@isc.org>
25 *   http://www.isc.org/
26 *
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon, as part of a project for Nominum, Inc.   To learn more
29 * about Internet Systems Consortium, see http://www.isc.org/.  To
30 * learn more about Nominum, Inc., see ``http://www.nominum.com''.
31 */
32
33#include <omapip/omapip_p.h>
34
35#include "minires/minires.h"
36#include "arpa/nameser.h"
37
38static void trace_mr_output_input (trace_type_t *, unsigned, char *);
39static void trace_mr_output_stop (trace_type_t *);
40static void trace_mr_input_input (trace_type_t *, unsigned, char *);
41static void trace_mr_input_stop (trace_type_t *);
42static void trace_mr_statp_input (trace_type_t *, unsigned, char *);
43static void trace_mr_statp_stop (trace_type_t *);
44static void trace_mr_randomid_input (trace_type_t *, unsigned, char *);
45static void trace_mr_randomid_stop (trace_type_t *);
46trace_type_t *trace_mr_output;
47trace_type_t *trace_mr_input;
48trace_type_t *trace_mr_statp;
49trace_type_t *trace_mr_randomid;
50ssize_t trace_mr_send (int, void *, size_t, int);
51ssize_t trace_mr_read_playback (struct sockaddr_in *, void *, size_t);
52void trace_mr_read_record (struct sockaddr_in *, void *, ssize_t);
53ssize_t trace_mr_recvfrom (int s, void *, size_t, int,
54			   struct sockaddr *, SOCKLEN_T *);
55ssize_t trace_mr_read (int, void *, size_t);
56int trace_mr_connect (int s, struct sockaddr *, SOCKLEN_T);
57int trace_mr_socket (int, int, int);
58int trace_mr_bind (int, struct sockaddr *, SOCKLEN_T);
59int trace_mr_close (int);
60time_t trace_mr_time (time_t *);
61int trace_mr_select (int, fd_set *, fd_set *, fd_set *, struct timeval *);
62unsigned int trace_mr_res_randomid (unsigned int);
63
64extern TIME cur_time;
65
66#if defined (TRACING)
67void trace_mr_init ()
68{
69	trace_mr_output = trace_type_register ("mr-output", (void *)0,
70					       trace_mr_output_input,
71					       trace_mr_output_stop, MDL);
72	trace_mr_input = trace_type_register ("mr-input", (void *)0,
73					      trace_mr_input_input,
74					      trace_mr_input_stop, MDL);
75	trace_mr_statp = trace_type_register ("mr-statp", (void *)0,
76					      trace_mr_statp_input,
77					      trace_mr_statp_stop, MDL);
78	trace_mr_randomid = trace_type_register ("mr-randomid", (void *)0,
79						 trace_mr_randomid_input,
80						 trace_mr_randomid_stop, MDL);
81}
82
83void trace_mr_statp_setup (res_state statp)
84{
85	unsigned buflen = 0;
86	char *buf = (char *)0;
87	isc_result_t status;
88	int i;
89
90	if (trace_playback ()) {
91		int nscount;
92		status = trace_get_packet (&trace_mr_statp, &buflen, &buf);
93		if (status != ISC_R_SUCCESS) {
94			log_error ("trace_mr_statp: no statp packet found.");
95			return;
96		}
97		nscount = buflen / sizeof (struct in_addr);
98		if (nscount * (sizeof (struct in_addr)) != buflen ||
99		    nscount < 1) {
100			log_error ("trace_mr_statp: bogus length: %d",
101				   buflen);
102			return;
103		}
104		if (nscount > MAXNS)
105			nscount = MAXNS;
106		for (i = 0; i < nscount; i++) {
107#if defined (HAVE_SA_LEN)
108			statp -> nsaddr_list [i].sin_len =
109				sizeof (struct sockaddr_in);
110#endif
111			memset (&statp -> nsaddr_list [i], 0,
112				sizeof statp -> nsaddr_list [i]);
113			statp -> nsaddr_list [i].sin_port = htons (53); /*XXX*/
114			statp -> nsaddr_list [i].sin_family = AF_INET;
115			memcpy (&statp -> nsaddr_list [i].sin_addr,
116				(buf + i * (sizeof (struct in_addr))),
117				sizeof (struct in_addr));
118		}
119		statp -> nscount = nscount;
120		dfree (buf, MDL);
121		buf = (char *)0;
122	}
123	if (trace_record ()) {
124		trace_iov_t *iov;
125		iov = dmalloc ((statp -> nscount *
126				sizeof (trace_iov_t)), MDL);
127		if (!iov) {
128			trace_stop ();
129			log_error ("No memory for statp iov.");
130			return;
131		}
132		for (i = 0; i < statp -> nscount; i++) {
133			iov [i].buf =
134				(char *)&statp -> nsaddr_list [i].sin_addr;
135			iov [i].len = sizeof (struct in_addr);
136		}
137		trace_write_packet_iov (trace_mr_statp, i, iov, MDL);
138		dfree (iov, MDL);
139	}
140}
141#endif
142
143ssize_t trace_mr_send (int fd, void *msg, size_t len, int flags)
144{
145	ssize_t rv;
146#if defined (TRACING)
147	isc_result_t status;
148	unsigned buflen = 0;
149	char *inbuf = (char *)0;
150	u_int32_t result;
151	u_int32_t sflags;
152
153	if (trace_playback()) {
154		status = trace_get_packet (&trace_mr_output, &buflen, &inbuf);
155		if (status != ISC_R_SUCCESS) {
156			log_error ("trace_mr_recvfrom: no input found.");
157			errno = ECONNREFUSED;
158			return -1;
159		}
160		if (buflen < sizeof result) {
161			log_error ("trace_mr_recvfrom: data too short.");
162			errno = ECONNREFUSED;
163			dfree (inbuf, MDL);
164			return -1;
165		}
166		memcpy (&result, inbuf, sizeof result);
167		rv = ntohl (result);
168		dfree (inbuf, MDL);
169	} else
170#endif
171		rv = send (fd, msg, len, flags);
172#if defined (TRACING)
173	if (trace_record ()) {
174		trace_iov_t iov [3];
175		result = htonl (rv);
176		sflags = htonl (flags);
177		iov [0].len = sizeof result;
178		iov [0].buf = (char *)&result;
179		iov [1].len = sizeof sflags;
180		iov [1].buf = (char *)&flags;
181		iov [2].len = len;
182		iov [2].buf = msg;
183		trace_write_packet_iov (trace_mr_output, 3, iov, MDL);
184	}
185#endif
186	return rv;
187}
188
189#if defined (TRACING)
190ssize_t trace_mr_read_playback (struct sockaddr_in *from,
191				void *buf, size_t nbytes)
192{
193	isc_result_t status;
194	unsigned buflen = 0, left;
195	char *inbuf = (char *)0;
196	char *bufp;
197	u_int32_t result;
198
199	status = trace_get_packet (&trace_mr_input, &buflen, &inbuf);
200	if (status != ISC_R_SUCCESS) {
201		log_error ("trace_mr_recvfrom: no input found.");
202		errno = ECONNREFUSED;
203		return -1;
204	}
205	if (buflen < sizeof result) {
206		log_error ("trace_mr_recvfrom: data too short.");
207		errno = ECONNREFUSED;
208		dfree (inbuf, MDL);
209		return -1;
210	}
211	bufp = inbuf;
212	left = buflen;
213	memcpy (&result, bufp, sizeof result);
214	result = ntohl (result);
215	bufp += sizeof result;
216	left -= sizeof result;
217	if (result == 0) {
218		if (left < ((sizeof from -> sin_port) +
219			    sizeof (from -> sin_addr))) {
220			log_error ("trace_mr_recvfrom: data too short.");
221			errno = ECONNREFUSED;
222			dfree (inbuf, MDL);
223			return -1;
224		}
225		if (from)
226			memset (from, 0, sizeof *from);
227		if (from)
228			memcpy (&from -> sin_addr, bufp,
229				sizeof from -> sin_addr);
230		bufp += sizeof from -> sin_addr;
231		left -= sizeof from -> sin_addr;
232		if (from)
233			memcpy (&from -> sin_port, bufp,
234				sizeof from -> sin_port);
235		bufp += sizeof from -> sin_port;
236		left -= sizeof from -> sin_port;
237		if (from) {
238			from -> sin_family = AF_INET;
239#if defined(HAVE_SA_LEN)
240			from -> sin_len = sizeof (struct sockaddr_in);
241#endif
242		}
243		if (left > nbytes) {
244			log_error ("trace_mr_recvfrom: too much%s",
245				   " data.");
246			errno = ECONNREFUSED;
247			dfree (inbuf, MDL);
248			return -1;
249		}
250		memcpy (buf, bufp, left);
251		dfree (inbuf, MDL);
252		return left;
253	}
254	errno = ECONNREFUSED;
255	return -1;
256}
257
258void trace_mr_read_record (struct sockaddr_in *from, void *buf, ssize_t rv)
259{
260	trace_iov_t iov [4];
261	u_int32_t result;
262	int iolen = 0;
263	static char zero [4] = { 0, 0, 0, 0 };
264
265	if (rv < 0)
266		result = htonl (errno);		/* XXX */
267	else
268		result = 0;
269	iov [iolen].buf = (char *)&result;
270	iov [iolen++].len = sizeof result;
271	if (rv > 0) {
272		if (from) {
273			iov [iolen].buf = (char *)&from -> sin_addr;
274			iov [iolen++].len = sizeof from -> sin_addr;
275			iov [iolen].buf = (char *)&from -> sin_port;
276			iov [iolen++].len = sizeof from -> sin_port;
277		} else {
278			iov [iolen].buf = zero;
279			iov [iolen++].len = sizeof from -> sin_addr;
280			iov [iolen].buf = zero;
281			iov [iolen++].len = sizeof from -> sin_port;
282		}
283
284		iov [iolen].buf = buf;
285		iov [iolen++].len = rv;
286	}
287	trace_write_packet_iov (trace_mr_input, iolen, iov, MDL);
288}
289#endif
290
291ssize_t trace_mr_recvfrom (int s, void *buf, size_t len, int flags,
292			   struct sockaddr *from, SOCKLEN_T *fromlen)
293{
294	ssize_t rv;
295
296#if defined (TRACING)
297	if (trace_playback ())
298		rv = trace_mr_read_playback ((struct sockaddr_in *)from,
299					     buf, len);
300	else
301#endif
302		rv = recvfrom (s, buf, len, flags, from, fromlen);
303#if defined (TRACING)
304	if (trace_record ()) {
305		trace_mr_read_record ((struct sockaddr_in *)from, buf, rv);
306	}
307#endif
308	return rv;
309}
310
311ssize_t trace_mr_read (int d, void *buf, size_t nbytes)
312{
313	ssize_t rv;
314
315#if defined (TRACING)
316	if (trace_playback ())
317		rv = trace_mr_read_playback ((struct sockaddr_in *)0,
318					     buf, nbytes);
319	else
320#endif
321		rv = read (d, buf, nbytes);
322#if defined (TRACING)
323	if (trace_record ()) {
324		trace_mr_read_record ((struct sockaddr_in *)0, buf, rv);
325	}
326#endif
327	return rv;
328}
329
330int trace_mr_connect (int s, struct sockaddr *name, SOCKLEN_T namelen)
331{
332#if defined (TRACING)
333	if (!trace_playback ())
334#endif
335		return connect (s, name, namelen);
336#if defined (TRACING)
337	return 0;
338#endif
339}
340
341int trace_mr_socket (int domain, int type, int protocol)
342{
343#if defined (TRACING)
344	if (!trace_playback ())
345#endif
346		return socket (domain, type, protocol);
347#if defined (TRACING)
348	return 100;
349#endif
350}
351
352int trace_mr_bind (int s, struct sockaddr *name, SOCKLEN_T namelen)
353{
354#if defined (TRACING)
355	if (!trace_playback ())
356#endif
357		return bind (s, name, namelen);
358#if defined (TRACING)
359	return 0;
360#endif
361}
362
363int trace_mr_close (int s)
364{
365#if defined (TRACING)
366	if (!trace_playback ())
367#endif
368		return close (s);
369#if defined (TRACING)
370	return 0;
371#endif
372}
373
374time_t trace_mr_time (time_t *tp)
375{
376#if defined (TRACING)
377	if (trace_playback ()) {
378		if (tp)
379			*tp = cur_time;
380		return cur_time;
381	}
382#endif
383	return time (tp);
384}
385
386int trace_mr_select (int s, fd_set *r, fd_set *w, fd_set *x, struct timeval *t)
387{
388#if defined (TRACING)
389	trace_type_t *ttp = (trace_type_t *)0;
390
391	if (trace_playback ()) {
392		time_t nct = trace_snoop_time (&ttp);
393		time_t secr = t -> tv_sec;
394		t -> tv_sec = nct - cur_time;
395		if (t -> tv_sec > secr)
396			return 0;
397		if (ttp == trace_mr_input)
398			return 1;
399		return 0;
400	}
401#endif
402	return select (s, r, w, x, t);
403}
404
405unsigned int trace_mr_res_randomid (unsigned int oldid)
406{
407	u_int32_t id;
408	int rid = oldid;
409#if defined (TRACING)
410	unsigned buflen = 0;
411	char *buf = (char *)0;
412	isc_result_t status;
413
414	if (trace_playback ()) {
415		status = trace_get_packet (&trace_mr_randomid, &buflen, &buf);
416		if (status != ISC_R_SUCCESS) {
417			log_error ("trace_mr_statp: no statp packet found.");
418			return oldid;
419		}
420		if (buflen != sizeof id) {
421			log_error ("trace_mr_randomid: bogus length: %d",
422				   buflen);
423			return oldid;
424		}
425		memcpy (&id, buf, sizeof id);
426		dfree (buf, MDL);
427		buf = (char *)0;
428		rid = ntohl (id);
429	}
430	if (trace_record ()) {
431		id = htonl (rid);
432		trace_write_packet (trace_mr_randomid,
433				    sizeof id, (char *)&id, MDL);
434	}
435#endif
436	return rid;
437}
438
439#if defined (TRACING)
440static void trace_mr_output_input (trace_type_t *ttype,
441				   unsigned length, char *buf)
442{
443}
444
445static void trace_mr_output_stop (trace_type_t *ttype)
446{
447}
448
449static void trace_mr_input_input (trace_type_t *ttype,
450				  unsigned length, char *buf)
451{
452	log_error ("unaccounted-for minires input.");
453}
454
455static void trace_mr_input_stop (trace_type_t *ttype)
456{
457}
458
459static void trace_mr_statp_input (trace_type_t *ttype,
460				  unsigned length, char *buf)
461{
462	log_error ("unaccounted-for minires statp input.");
463}
464
465static void trace_mr_statp_stop (trace_type_t *ttype)
466{
467}
468
469static void trace_mr_randomid_input (trace_type_t *ttype,
470				     unsigned length, char *buf)
471{
472	log_error ("unaccounted-for minires randomid input.");
473}
474
475static void trace_mr_randomid_stop (trace_type_t *ttype)
476{
477}
478#endif
479