1/*
2 * Copyright (c) 1985, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Copyright (c) 1995 John Hay.  All rights reserved.
6 *
7 * This file includes significant work done at Cornell University by
8 * Bill Nesheim.  That work included by permission.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#ifndef lint
40#if 0
41static char sccsid[] = "@(#)trace.c	8.1 (Berkeley) 6/5/93";
42#endif
43static const char rcsid[] =
44  "$FreeBSD$";
45#endif /* not lint */
46
47/*
48 * Routing Table Management Daemon
49 */
50#define	RIPCMDS
51#define	SAPCMDS
52#include <stdlib.h>
53#include <unistd.h>
54#include <sys/types.h>
55#include <time.h>
56#include "defs.h"
57
58#define	NRECORDS	50		/* size of circular trace buffer */
59#ifdef DEBUG
60FILE	*ftrace = stdout;
61int	tracing = 1;
62#else /* DEBUG */
63FILE	*ftrace = NULL;
64int	tracing = 0;
65#endif
66
67void dumpif(FILE *fd, struct interface *ifp);
68void dumptrace(FILE *fd, char *dir, struct ifdebug *ifd);
69static int iftraceinit(struct interface *ifp, struct ifdebug *ifd);
70
71void
72traceinit(ifp)
73	register struct interface *ifp;
74{
75	if (iftraceinit(ifp, &ifp->int_input) &&
76	    iftraceinit(ifp, &ifp->int_output))
77		return;
78	tracing = 0;
79	syslog(LOG_ERR, "traceinit: can't init %s\n", ifp->int_name);
80}
81
82static int
83iftraceinit(ifp, ifd)
84	struct interface *ifp;
85	register struct ifdebug *ifd;
86{
87	register struct iftrace *t;
88
89	ifd->ifd_records =
90	  (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
91	if (ifd->ifd_records == 0)
92		return (0);
93	ifd->ifd_front = ifd->ifd_records;
94	ifd->ifd_count = 0;
95	for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
96		t->ift_size = 0;
97		t->ift_packet = 0;
98	}
99	ifd->ifd_if = ifp;
100	return (1);
101}
102
103void
104traceon(file)
105	char *file;
106{
107
108	if (ftrace != NULL)
109		return;
110	ftrace = fopen(file, "a");
111	if (ftrace == NULL)
112		return;
113	dup2(fileno(ftrace), 1);
114	dup2(fileno(ftrace), 2);
115	tracing = 1;
116}
117
118void
119traceoff(void)
120{
121	if (!tracing)
122		return;
123	if (ftrace != NULL)
124		fclose(ftrace);
125	ftrace = NULL;
126	tracing = 0;
127}
128
129void
130trace(ifd, who, p, len, m)
131	register struct ifdebug *ifd;
132	struct sockaddr *who;
133	char *p;
134	int len, m;
135{
136	register struct iftrace *t;
137
138	if (ifd->ifd_records == 0)
139		return;
140	t = ifd->ifd_front++;
141	if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
142		ifd->ifd_front = ifd->ifd_records;
143	if (ifd->ifd_count < NRECORDS)
144		ifd->ifd_count++;
145	if (t->ift_size > 0 && t->ift_packet)
146		free(t->ift_packet);
147	t->ift_packet = 0;
148	t->ift_stamp = time(0);
149	t->ift_who = *who;
150	if (len > 0) {
151		t->ift_packet = malloc(len);
152		if (t->ift_packet)
153			bcopy(p, t->ift_packet, len);
154		else
155			len = 0;
156	}
157	t->ift_size = len;
158	t->ift_metric = m;
159}
160
161void
162traceaction(fd, action, rt)
163	FILE *fd;
164	char *action;
165	struct rt_entry *rt;
166{
167	struct sockaddr_ipx *dst, *gate;
168	static struct bits {
169		int	t_bits;
170		char	*t_name;
171	} flagbits[] = {
172		{ RTF_UP,	"UP" },
173		{ RTF_GATEWAY,	"GATEWAY" },
174		{ RTF_HOST,	"HOST" },
175		{ 0 }
176	}, statebits[] = {
177		{ RTS_PASSIVE,	"PASSIVE" },
178		{ RTS_REMOTE,	"REMOTE" },
179		{ RTS_INTERFACE,"INTERFACE" },
180		{ RTS_CHANGED,	"CHANGED" },
181		{ 0 }
182	};
183	register struct bits *p;
184	register int first;
185	char *cp;
186
187	if (fd == NULL)
188		return;
189	fprintf(fd, "%s ", action);
190	dst = (struct sockaddr_ipx *)&rt->rt_dst;
191	gate = (struct sockaddr_ipx *)&rt->rt_router;
192	fprintf(fd, "dst %s, ", ipxdp_ntoa(&dst->sipx_addr));
193	fprintf(fd, "router %s, metric %d, ticks %d, flags",
194	     ipxdp_ntoa(&gate->sipx_addr), rt->rt_metric, rt->rt_ticks);
195	cp = " %s";
196	for (first = 1, p = flagbits; p->t_bits > 0; p++) {
197		if ((rt->rt_flags & p->t_bits) == 0)
198			continue;
199		fprintf(fd, cp, p->t_name);
200		if (first) {
201			cp = "|%s";
202			first = 0;
203		}
204	}
205	fprintf(fd, " state");
206	cp = " %s";
207	for (first = 1, p = statebits; p->t_bits > 0; p++) {
208		if ((rt->rt_state & p->t_bits) == 0)
209			continue;
210		fprintf(fd, cp, p->t_name);
211		if (first) {
212			cp = "|%s";
213			first = 0;
214		}
215	}
216	putc('\n', fd);
217	if (!tracepackets && (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
218		dumpif(fd, rt->rt_ifp);
219	fflush(fd);
220}
221
222void
223traceactionlog(action, rt)
224	char *action;
225	struct rt_entry *rt;
226{
227	struct sockaddr_ipx *dst, *gate;
228	static struct bits {
229		int	t_bits;
230		char	*t_name;
231	} flagbits[] = {
232		{ RTF_UP,	"UP" },
233		{ RTF_GATEWAY,	"GATEWAY" },
234		{ RTF_HOST,	"HOST" },
235		{ 0 }
236	}, statebits[] = {
237		{ RTS_PASSIVE,	"PASSIVE" },
238		{ RTS_REMOTE,	"REMOTE" },
239		{ RTS_INTERFACE,"INTERFACE" },
240		{ RTS_CHANGED,	"CHANGED" },
241		{ 0 }
242	};
243	register struct bits *p;
244	register int first;
245	char *cp;
246	char *lstr, *olstr;
247
248	dst = (struct sockaddr_ipx *)&rt->rt_dst;
249	gate = (struct sockaddr_ipx *)&rt->rt_router;
250	asprintf(&lstr, "%s dst %s,", action, ipxdp_ntoa(&dst->sipx_addr));
251	olstr = lstr;
252	asprintf(&lstr, "%s router %s, metric %d, ticks %d, flags",
253	     olstr, ipxdp_ntoa(&gate->sipx_addr), rt->rt_metric, rt->rt_ticks);
254	free(olstr);
255	olstr = lstr;
256	cp = "%s %s";
257	for (first = 1, p = flagbits; p->t_bits > 0; p++) {
258		if ((rt->rt_flags & p->t_bits) == 0)
259			continue;
260		asprintf(&lstr, cp, olstr, p->t_name);
261		free(olstr);
262		olstr = lstr;
263		if (first) {
264			cp = "%s|%s";
265			first = 0;
266		}
267	}
268	asprintf(&lstr, "%s state", olstr);
269	free(olstr);
270	olstr = lstr;
271	cp = "%s %s";
272	for (first = 1, p = statebits; p->t_bits > 0; p++) {
273		if ((rt->rt_state & p->t_bits) == 0)
274			continue;
275		asprintf(&lstr, cp, olstr, p->t_name);
276		free(olstr);
277		olstr = lstr;
278		if (first) {
279			cp = "%s|%s";
280			first = 0;
281		}
282	}
283	syslog(LOG_DEBUG, "%s", lstr);
284	free(lstr);
285}
286
287void
288tracesapactionlog(action, sap)
289	char *action;
290	struct sap_entry *sap;
291{
292	syslog(LOG_DEBUG, "%-12.12s  service %04X %-20.20s "
293		    "addr %s.%04X %c metric %d\n",
294		     action,
295		     ntohs(sap->sap.ServType),
296		     sap->sap.ServName,
297		     ipxdp_ntoa(&sap->sap.ipx),
298		     ntohs(sap->sap.ipx.x_port),
299		     (sap->clone ? 'C' : ' '),
300		     ntohs(sap->sap.hops));
301}
302
303void
304dumpif(fd, ifp)
305	register struct interface *ifp;
306	FILE *fd;
307{
308	if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
309		fprintf(fd, "*** Packet history for interface %s ***\n",
310			ifp->int_name);
311		dumptrace(fd, "to", &ifp->int_output);
312		dumptrace(fd, "from", &ifp->int_input);
313		fprintf(fd, "*** end packet history ***\n");
314	}
315}
316
317void
318dumptrace(fd, dir, ifd)
319	FILE *fd;
320	char *dir;
321	register struct ifdebug *ifd;
322{
323	register struct iftrace *t;
324	char *cp = !strcmp(dir, "to") ? "Output" : "Input";
325
326	if (ifd->ifd_front == ifd->ifd_records &&
327	    ifd->ifd_front->ift_size == 0) {
328		fprintf(fd, "%s: no packets.\n", cp);
329		return;
330	}
331	fprintf(fd, "%s trace:\n", cp);
332	t = ifd->ifd_front - ifd->ifd_count;
333	if (t < ifd->ifd_records)
334		t += NRECORDS;
335	for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
336		if (t >= ifd->ifd_records + NRECORDS)
337			t = ifd->ifd_records;
338		if (t->ift_size == 0)
339			continue;
340		fprintf(fd, "%.24s: metric=%d\n", ctime(&t->ift_stamp),
341			t->ift_metric);
342		dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size);
343	}
344}
345
346void
347dumppacket(fd, dir, source, cp, size)
348	FILE *fd;
349	char *dir;
350	struct sockaddr *source;
351	char *cp;
352	register int size;
353{
354	register struct rip *msg = (struct rip *)cp;
355	register struct netinfo *n;
356	struct sockaddr_ipx *who = (struct sockaddr_ipx *)source;
357
358	if (msg->rip_cmd && ntohs(msg->rip_cmd) < RIPCMD_MAX)
359		fprintf(fd, "%s %s %s#%x", ripcmds[ntohs(msg->rip_cmd)],
360		    dir, ipxdp_ntoa(&who->sipx_addr),
361		    ntohs(who->sipx_addr.x_port));
362	else {
363		fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->rip_cmd),
364		    dir, ipxdp_ntoa(&who->sipx_addr),
365		    ntohs(who->sipx_addr.x_port));
366		fprintf(fd, "size=%d cp=%p packet=%p\n", size,
367			cp, packet);
368		return;
369	}
370	switch (ntohs(msg->rip_cmd)) {
371
372	case RIPCMD_REQUEST:
373	case RIPCMD_RESPONSE:
374		fprintf(fd, ":\n");
375		size -= sizeof (u_short);
376		n = msg->rip_nets;
377		for (; size > 0; n++, size -= sizeof (struct netinfo)) {
378			if (size < sizeof (struct netinfo))
379				break;
380			fprintf(fd, "\tnet %s metric %d ticks %d\n",
381			     ipxdp_nettoa(n->rip_dst),
382			     ntohs(n->rip_metric),
383			     ntohs(n->rip_ticks));
384		}
385		break;
386
387	}
388}
389
390void
391dumpsappacket(fd, dir, source, cp, size)
392	FILE *fd;
393	char *dir;
394	struct sockaddr *source;
395	char *cp;
396	register int size;
397{
398	register struct sap_packet *msg = (struct sap_packet *)cp;
399	register struct sap_info *n;
400	struct sockaddr_ipx *who = (struct sockaddr_ipx *)source;
401
402	if (msg->sap_cmd && ntohs(msg->sap_cmd) < SAPCMD_MAX)
403		fprintf(fd, "%s %s %s#%x", sapcmds[ntohs(msg->sap_cmd)],
404		    dir, ipxdp_ntoa(&who->sipx_addr),
405		    ntohs(who->sipx_addr.x_port));
406	else {
407		fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->sap_cmd),
408		    dir, ipxdp_ntoa(&who->sipx_addr),
409		    ntohs(who->sipx_addr.x_port));
410		fprintf(fd, "size=%d cp=%p packet=%p\n", size,
411			cp, packet);
412		return;
413	}
414	switch (ntohs(msg->sap_cmd)) {
415
416	case SAP_REQ:
417	case SAP_RESP:
418	case SAP_REQ_NEAR:
419	case SAP_RESP_NEAR:
420		fprintf(fd, ":\n");
421		size -= sizeof (u_short);
422		n = msg->sap;
423		for (; size > 0; n++, size -= sizeof (struct sap_info)) {
424			if (size < sizeof (struct sap_info))
425				break;
426			fprintf(fd, "  service %04X %-20.20s "
427				    "addr %s.%04X metric %d\n",
428			     ntohs(n->ServType),
429			     n->ServName,
430			     ipxdp_ntoa(&n->ipx),
431			     ntohs(n->ipx.x_port),
432			     ntohs(n->hops));
433		}
434		break;
435
436	}
437}
438
439void
440dumpsaptable(fd, sh)
441	FILE *fd;
442	struct sap_hash *sh;
443{
444	register struct sap_entry *sap;
445	struct sap_hash *hash;
446	int x = 0;
447
448	fprintf(fd, "------- SAP table dump. -------\n");
449	for (hash = sh; hash < &sh[SAPHASHSIZ]; hash++, x++) {
450		fprintf(fd, "HASH %d\n", x);
451		sap = hash->forw;
452		for (; sap != (struct sap_entry *)hash; sap = sap->forw) {
453			fprintf(fd, "  service %04X %-20.20s "
454				    "addr %s.%04X %c metric %d\n",
455				     ntohs(sap->sap.ServType),
456				     sap->sap.ServName,
457				     ipxdp_ntoa(&sap->sap.ipx),
458				     ntohs(sap->sap.ipx.x_port),
459				     (sap->clone ? 'C' : ' '),
460				     ntohs(sap->sap.hops));
461		}
462	}
463	fprintf(fd, "\n");
464}
465
466void
467dumpriptable(fd)
468	FILE *fd;
469{
470	register struct rt_entry *rip;
471	struct rthash *hash;
472	int x;
473	struct rthash *rh = nethash;
474
475	fprintf(fd, "------- RIP table dump. -------\n");
476	x = 0;
477	fprintf(fd, "Network table.\n");
478
479	for (hash = rh; hash < &rh[ROUTEHASHSIZ]; hash++, x++) {
480		fprintf(fd, "HASH %d\n", x);
481		rip = hash->rt_forw;
482		for (; rip != (struct rt_entry *)hash; rip = rip->rt_forw) {
483			fprintf(fd, "  dest %s\t",
484				ipxdp_ntoa(&satoipx_addr(rip->rt_dst)));
485			fprintf(fd, "%s metric %d, ticks %d\n",
486				ipxdp_ntoa(&satoipx_addr(rip->rt_router)),
487				rip->rt_metric,
488				rip->rt_ticks);
489		}
490	}
491	fprintf(fd, "\n");
492}
493
494union ipx_net_u net;
495
496char *
497ipxdp_nettoa(val)
498union ipx_net val;
499{
500	static char buf[100];
501	net.net_e = val;
502	(void)sprintf(buf, "%u", ntohl(net.long_e));
503	return (buf);
504}
505
506
507char *
508ipxdp_ntoa(addr)
509struct ipx_addr *addr;
510{
511    static char buf[100];
512
513    (void)sprintf(buf, "%s#%x:%x:%x:%x:%x:%x",
514	ipxdp_nettoa(addr->x_net),
515	addr->x_host.c_host[0], addr->x_host.c_host[1],
516	addr->x_host.c_host[2], addr->x_host.c_host[3],
517	addr->x_host.c_host[4], addr->x_host.c_host[5]);
518
519    return(buf);
520}
521