Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / usr.sbin / IPXrouted / trace.c
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  * $FreeBSD: src/usr.sbin/IPXrouted/trace.c,v 1.6.2.1 2000/07/20 10:35:22 kris Exp $
39  * $DragonFly: src/usr.sbin/IPXrouted/trace.c,v 1.6 2006/01/22 03:43:38 swildner Exp $
40  *
41  * @(#)trace.c  8.1 (Berkeley) 6/5/93
42  */
43
44 /*
45  * Routing Table Management Daemon
46  */
47 #define RIPCMDS
48 #define SAPCMDS
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <sys/types.h>
52 #include <time.h>
53 #include "defs.h"
54
55 #define NRECORDS        50              /* size of circular trace buffer */
56 #ifdef DEBUG
57 FILE    *ftrace = stdout;
58 int     tracing = 1;
59 #else /* DEBUG */
60 FILE    *ftrace = NULL;
61 int     tracing = 0;
62 #endif
63
64 void dumpif(FILE *fd, struct interface *ifp);
65 void dumptrace(FILE *fd, char *dir, struct ifdebug *ifd);
66
67 static int iftraceinit(struct interface *, struct ifdebug *);
68
69 void
70 traceinit(struct interface *ifp)
71 {
72         if (iftraceinit(ifp, &ifp->int_input) &&
73             iftraceinit(ifp, &ifp->int_output))
74                 return;
75         tracing = 0;
76         syslog(LOG_ERR, "traceinit: can't init %s\n", ifp->int_name);
77 }
78
79 static int
80 iftraceinit(struct interface *ifp, struct ifdebug *ifd)
81 {
82         struct iftrace *t;
83
84         ifd->ifd_records =
85           (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
86         if (ifd->ifd_records == 0)
87                 return (0);
88         ifd->ifd_front = ifd->ifd_records;
89         ifd->ifd_count = 0;
90         for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
91                 t->ift_size = 0;
92                 t->ift_packet = 0;
93         }
94         ifd->ifd_if = ifp;
95         return (1);
96 }
97
98 void
99 traceon(char *file)
100 {
101
102         if (ftrace != NULL)
103                 return;
104         ftrace = fopen(file, "a");
105         if (ftrace == NULL)
106                 return;
107         dup2(fileno(ftrace), 1);
108         dup2(fileno(ftrace), 2);
109         tracing = 1;
110 }
111
112 void
113 traceoff(void)
114 {
115         if (!tracing)
116                 return;
117         if (ftrace != NULL)
118                 fclose(ftrace);
119         ftrace = NULL;
120         tracing = 0;
121 }
122
123 void
124 trace(struct ifdebug *ifd, struct sockaddr *who, char *p, int len, int m)
125 {
126         struct iftrace *t;
127
128         if (ifd->ifd_records == 0)
129                 return;
130         t = ifd->ifd_front++;
131         if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
132                 ifd->ifd_front = ifd->ifd_records;
133         if (ifd->ifd_count < NRECORDS)
134                 ifd->ifd_count++;
135         if (t->ift_size > 0 && t->ift_packet)
136                 free(t->ift_packet);
137         t->ift_packet = 0;
138         t->ift_stamp = time(0);
139         t->ift_who = *who;
140         if (len > 0) {
141                 t->ift_packet = malloc(len);
142                 if (t->ift_packet)
143                         bcopy(p, t->ift_packet, len);
144                 else
145                         len = 0;
146         }
147         t->ift_size = len;
148         t->ift_metric = m;
149 }
150
151 void
152 traceaction(FILE *fd, char *action, struct rt_entry *rt)
153 {
154         struct sockaddr_ipx *dst, *gate;
155         static struct bits {
156                 int     t_bits;
157                 char    *t_name;
158         } flagbits[] = {
159                 { RTF_UP,       "UP" },
160                 { RTF_GATEWAY,  "GATEWAY" },
161                 { RTF_HOST,     "HOST" },
162                 { 0 }
163         }, statebits[] = {
164                 { RTS_PASSIVE,  "PASSIVE" },
165                 { RTS_REMOTE,   "REMOTE" },
166                 { RTS_INTERFACE,"INTERFACE" },
167                 { RTS_CHANGED,  "CHANGED" },
168                 { 0 }
169         };
170         struct bits *p;
171         int first;
172         char *cp;
173
174         if (fd == NULL)
175                 return;
176         fprintf(fd, "%s ", action);
177         dst = (struct sockaddr_ipx *)&rt->rt_dst;
178         gate = (struct sockaddr_ipx *)&rt->rt_router;
179         fprintf(fd, "dst %s, ", ipxdp_ntoa(&dst->sipx_addr));
180         fprintf(fd, "router %s, metric %d, ticks %d, flags",
181              ipxdp_ntoa(&gate->sipx_addr), rt->rt_metric, rt->rt_ticks);
182         cp = " %s";
183         for (first = 1, p = flagbits; p->t_bits > 0; p++) {
184                 if ((rt->rt_flags & p->t_bits) == 0)
185                         continue;
186                 fprintf(fd, cp, p->t_name);
187                 if (first) {
188                         cp = "|%s";
189                         first = 0;
190                 }
191         }
192         fprintf(fd, " state");
193         cp = " %s";
194         for (first = 1, p = statebits; p->t_bits > 0; p++) {
195                 if ((rt->rt_state & p->t_bits) == 0)
196                         continue;
197                 fprintf(fd, cp, p->t_name);
198                 if (first) {
199                         cp = "|%s";
200                         first = 0;
201                 }
202         }
203         putc('\n', fd);
204         if (!tracepackets && (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
205                 dumpif(fd, rt->rt_ifp);
206         fflush(fd);
207 }
208
209 void
210 traceactionlog(char *action, struct rt_entry *rt)
211 {
212         struct sockaddr_ipx *dst, *gate;
213         static struct bits {
214                 int     t_bits;
215                 char    *t_name;
216         } flagbits[] = {
217                 { RTF_UP,       "UP" },
218                 { RTF_GATEWAY,  "GATEWAY" },
219                 { RTF_HOST,     "HOST" },
220                 { 0 }
221         }, statebits[] = {
222                 { RTS_PASSIVE,  "PASSIVE" },
223                 { RTS_REMOTE,   "REMOTE" },
224                 { RTS_INTERFACE,"INTERFACE" },
225                 { RTS_CHANGED,  "CHANGED" },
226                 { 0 }
227         };
228         struct bits *p;
229         int first;
230         char *cp;
231         char *lstr, *olstr;
232
233         dst = (struct sockaddr_ipx *)&rt->rt_dst;
234         gate = (struct sockaddr_ipx *)&rt->rt_router;
235         asprintf(&lstr, "%s dst %s,", action, ipxdp_ntoa(&dst->sipx_addr));
236         olstr = lstr;
237         asprintf(&lstr, "%s router %s, metric %d, ticks %d, flags",
238              olstr, ipxdp_ntoa(&gate->sipx_addr), rt->rt_metric, rt->rt_ticks);
239         free(olstr);
240         olstr = lstr;
241         cp = "%s %s";
242         for (first = 1, p = flagbits; p->t_bits > 0; p++) {
243                 if ((rt->rt_flags & p->t_bits) == 0)
244                         continue;
245                 asprintf(&lstr, cp, olstr, p->t_name);
246                 free(olstr);
247                 olstr = lstr;
248                 if (first) {
249                         cp = "%s|%s";
250                         first = 0;
251                 }
252         }
253         asprintf(&lstr, "%s state", olstr);
254         free(olstr);
255         olstr = lstr;
256         cp = "%s %s";
257         for (first = 1, p = statebits; p->t_bits > 0; p++) {
258                 if ((rt->rt_state & 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         syslog(LOG_DEBUG, "%s", lstr);
269         free(lstr);
270 }
271
272 void
273 tracesapactionlog(char *action, struct sap_entry *sap)
274 {
275         syslog(LOG_DEBUG, "%-12.12s  service %04X %-20.20s "
276                     "addr %s.%04X %c metric %d\n",
277                      action,
278                      ntohs(sap->sap.ServType),
279                      sap->sap.ServName,
280                      ipxdp_ntoa(&sap->sap.ipx),
281                      ntohs(sap->sap.ipx.x_port),
282                      (sap->clone ? 'C' : ' '),
283                      ntohs(sap->sap.hops));
284 }
285
286 void
287 dumpif(FILE *fd, struct interface *ifp)
288 {
289         if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
290                 fprintf(fd, "*** Packet history for interface %s ***\n",
291                         ifp->int_name);
292                 dumptrace(fd, "to", &ifp->int_output);
293                 dumptrace(fd, "from", &ifp->int_input);
294                 fprintf(fd, "*** end packet history ***\n");
295         }
296 }
297
298 void
299 dumptrace(FILE *fd, char *dir, struct ifdebug *ifd)
300 {
301         struct iftrace *t;
302         char *cp;
303
304         cp = !strcmp(dir, "to") ? "Output" : "Input";
305         if (ifd->ifd_front == ifd->ifd_records &&
306             ifd->ifd_front->ift_size == 0) {
307                 fprintf(fd, "%s: no packets.\n", cp);
308                 return;
309         }
310         fprintf(fd, "%s trace:\n", cp);
311         t = ifd->ifd_front - ifd->ifd_count;
312         if (t < ifd->ifd_records)
313                 t += NRECORDS;
314         for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
315                 if (t >= ifd->ifd_records + NRECORDS)
316                         t = ifd->ifd_records;
317                 if (t->ift_size == 0)
318                         continue;
319                 fprintf(fd, "%.24s: metric=%d\n", ctime(&t->ift_stamp),
320                         t->ift_metric);
321                 dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size);
322         }
323 }
324
325 void
326 dumppacket(FILE *fd, char *dir, struct sockaddr *source, char *cp, int size)
327 {
328         struct rip *msg = (struct rip *)cp;
329         struct netinfo *n;
330         struct sockaddr_ipx *who = (struct sockaddr_ipx *)source;
331
332         if (msg->rip_cmd && ntohs(msg->rip_cmd) < RIPCMD_MAX)
333                 fprintf(fd, "%s %s %s#%x", ripcmds[ntohs(msg->rip_cmd)],
334                     dir, ipxdp_ntoa(&who->sipx_addr), 
335                     ntohs(who->sipx_addr.x_port));
336         else {
337                 fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->rip_cmd),
338                     dir, ipxdp_ntoa(&who->sipx_addr), 
339                     ntohs(who->sipx_addr.x_port));
340                 fprintf(fd, "size=%d cp=%x packet=%x\n", size, 
341                         (u_int)cp, (u_int)packet);
342                 return;
343         }
344         switch (ntohs(msg->rip_cmd)) {
345
346         case RIPCMD_REQUEST:
347         case RIPCMD_RESPONSE:
348                 fprintf(fd, ":\n");
349                 size -= sizeof (u_short);
350                 n = msg->rip_nets;
351                 for (; size > 0; n++, size -= sizeof (struct netinfo)) {
352                         if (size < sizeof (struct netinfo))
353                                 break;
354                         fprintf(fd, "\tnet %s metric %d ticks %d\n",
355                              ipxdp_nettoa(n->rip_dst),
356                              ntohs(n->rip_metric),
357                              ntohs(n->rip_ticks));
358                 }
359                 break;
360
361         }
362 }
363
364 void
365 dumpsappacket(FILE *fd, char *dir, struct sockaddr *source, char *cp, int size)
366 {
367         struct sap_packet *msg = (struct sap_packet *)cp;
368         struct sap_info *n;
369         struct sockaddr_ipx *who = (struct sockaddr_ipx *)source;
370
371         if (msg->sap_cmd && ntohs(msg->sap_cmd) < SAPCMD_MAX)
372                 fprintf(fd, "%s %s %s#%x", sapcmds[ntohs(msg->sap_cmd)],
373                     dir, ipxdp_ntoa(&who->sipx_addr), 
374                     ntohs(who->sipx_addr.x_port));
375         else {
376                 fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->sap_cmd),
377                     dir, ipxdp_ntoa(&who->sipx_addr), 
378                     ntohs(who->sipx_addr.x_port));
379                 fprintf(fd, "size=%d cp=%x packet=%x\n", size, 
380                         (u_int)cp, (u_int)packet);
381                 return;
382         }
383         switch (ntohs(msg->sap_cmd)) {
384
385         case SAP_REQ:
386         case SAP_RESP:
387         case SAP_REQ_NEAR:
388         case SAP_RESP_NEAR:
389                 fprintf(fd, ":\n");
390                 size -= sizeof (u_short);
391                 n = msg->sap;
392                 for (; size > 0; n++, size -= sizeof (struct sap_info)) {
393                         if (size < sizeof (struct sap_info))
394                                 break;
395                         fprintf(fd, "  service %04X %-20.20s "
396                                     "addr %s.%04X metric %d\n",
397                              ntohs(n->ServType),
398                              n->ServName,
399                              ipxdp_ntoa(&n->ipx),
400                              ntohs(n->ipx.x_port),
401                              ntohs(n->hops));
402                 }
403                 break;
404
405         }
406 }
407
408 void
409 dumpsaptable(FILE *fd, struct sap_hash *sh)
410 {
411         struct sap_entry *sap;
412         struct sap_hash *hash;
413         int x = 0;
414
415         fprintf(fd, "------- SAP table dump. -------\n");
416         for (hash = sh; hash < &sh[SAPHASHSIZ]; hash++, x++) {
417                 fprintf(fd, "HASH %d\n", x);
418                 sap = hash->forw;
419                 for (; sap != (struct sap_entry *)hash; sap = sap->forw) {
420                         fprintf(fd, "  service %04X %-20.20s "
421                                     "addr %s.%04X %c metric %d\n",
422                                      ntohs(sap->sap.ServType),
423                                      sap->sap.ServName,
424                                      ipxdp_ntoa(&sap->sap.ipx),
425                                      ntohs(sap->sap.ipx.x_port),
426                                      (sap->clone ? 'C' : ' '),
427                                      ntohs(sap->sap.hops));
428                 }
429         }
430         fprintf(fd, "\n");
431 }
432
433 void
434 dumpriptable(FILE *fd)
435 {
436         struct rt_entry *rip;
437         struct rthash *hash;
438         int x;
439         struct rthash *rh = nethash;
440
441         fprintf(fd, "------- RIP table dump. -------\n");
442         x = 0;
443         fprintf(fd, "Network table.\n");
444
445         for (hash = rh; hash < &rh[ROUTEHASHSIZ]; hash++, x++) {
446                 fprintf(fd, "HASH %d\n", x);
447                 rip = hash->rt_forw;
448                 for (; rip != (struct rt_entry *)hash; rip = rip->rt_forw) {
449                         fprintf(fd, "  dest %s\t", 
450                                 ipxdp_ntoa(&satoipx_addr(rip->rt_dst)));
451                         fprintf(fd, "%s metric %d, ticks %d\n",
452                                 ipxdp_ntoa(&satoipx_addr(rip->rt_router)),
453                                 rip->rt_metric,
454                                 rip->rt_ticks);
455                 }
456         }
457         fprintf(fd, "\n");
458 }
459
460 union ipx_net_u net;
461
462 char *
463 ipxdp_nettoa(union ipx_net val)
464 {
465         static char buf[100];
466         
467         net.net_e = val;
468         sprintf(buf, "%lx", ntohl(net.long_e));
469         return (buf);
470 }
471
472
473 char *
474 ipxdp_ntoa(struct ipx_addr *addr)
475 {
476     static char buf[100];
477
478     sprintf(buf, "%s#%x:%x:%x:%x:%x:%x",
479         ipxdp_nettoa(addr->x_net),
480         addr->x_host.c_host[0], addr->x_host.c_host[1], 
481         addr->x_host.c_host[2], addr->x_host.c_host[3], 
482         addr->x_host.c_host[4], addr->x_host.c_host[5]);
483         
484     return(buf);
485 }