route.c revision 18836
1/*
2 * Copyright (c) 1983, 1988, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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#ifndef lint
35#if 0
36static char sccsid[] = "From: @(#)route.c	8.6 (Berkeley) 4/28/95";
37#endif
38static const char rcsid[] =
39	"$Id: route.c,v 1.19 1996/09/05 23:34:09 julian Exp $";
40#endif /* not lint */
41
42#include <sys/param.h>
43#include <sys/protosw.h>
44#include <sys/socket.h>
45#include <sys/mbuf.h>
46
47#include <net/if.h>
48#include <net/if_dl.h>
49#include <net/if_types.h>
50#define  KERNEL
51#include <net/route.h>
52#undef KERNEL
53
54#include <netinet/in.h>
55#include <netipx/ipx.h>
56#include <netatalk/at.h>
57
58#ifdef NS
59#include <netns/ns.h>
60#endif
61
62#include <sys/sysctl.h>
63
64#include <netdb.h>
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <unistd.h>
69#include <err.h>
70#include <time.h>
71#include "netstat.h"
72
73#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
74
75/*
76 * Definitions for showing gateway flags.
77 */
78struct bits {
79	u_long	b_mask;
80	char	b_val;
81} bits[] = {
82	{ RTF_UP,	'U' },
83	{ RTF_GATEWAY,	'G' },
84	{ RTF_HOST,	'H' },
85	{ RTF_REJECT,	'R' },
86	{ RTF_DYNAMIC,	'D' },
87	{ RTF_MODIFIED,	'M' },
88	{ RTF_DONE,	'd' }, /* Completed -- for routing messages only */
89	{ RTF_CLONING,	'C' },
90	{ RTF_XRESOLVE,	'X' },
91	{ RTF_LLINFO,	'L' },
92	{ RTF_STATIC,	'S' },
93	{ RTF_PROTO1,	'1' },
94	{ RTF_PROTO2,	'2' },
95	{ RTF_WASCLONED,'W' },
96	{ RTF_PRCLONING,'c' },
97	{ RTF_PROTO3,	'3' },
98	{ RTF_BLACKHOLE,'B' },
99	{ RTF_BROADCAST,'b' },
100	{ 0 }
101};
102
103static union {
104	struct	sockaddr u_sa;
105	u_short	u_data[128];
106} pt_u;
107
108int	do_rtent = 0;
109struct	rtentry rtentry;
110struct	radix_node rnode;
111struct	radix_mask rmask;
112struct	radix_node_head *rt_tables[AF_MAX+1];
113
114int	NewTree = 0;
115
116static struct sockaddr *kgetsa __P((struct sockaddr *));
117static void p_tree __P((struct radix_node *));
118static void p_rtnode __P(());
119static void ntreestuff __P(());
120static void np_rtentry __P((struct rt_msghdr *));
121static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
122static void p_flags __P((int, char *));
123static void p_rtentry __P((struct rtentry *));
124
125/*
126 * Print routing tables.
127 */
128void
129routepr(rtree)
130	u_long rtree;
131{
132	struct radix_node_head *rnh, head;
133	int i;
134
135	printf("Routing tables\n");
136
137	if (Aflag == 0 && NewTree)
138		ntreestuff();
139	else {
140		if (rtree == 0) {
141			printf("rt_tables: symbol not in namelist\n");
142			return;
143		}
144
145		kget(rtree, rt_tables);
146		for (i = 0; i <= AF_MAX; i++) {
147			if ((rnh = rt_tables[i]) == 0)
148				continue;
149			kget(rnh, head);
150			if (i == AF_UNSPEC) {
151				if (Aflag && af == 0) {
152					printf("Netmasks:\n");
153					p_tree(head.rnh_treetop);
154				}
155			} else if (af == AF_UNSPEC || af == i) {
156				pr_family(i);
157				do_rtent = 1;
158				pr_rthdr();
159				p_tree(head.rnh_treetop);
160			}
161		}
162	}
163}
164
165/*
166 * Print address family header before a section of the routing table.
167 */
168void
169pr_family(af)
170	int af;
171{
172	char *afname;
173
174	switch (af) {
175	case AF_INET:
176		afname = "Internet";
177		break;
178	case AF_IPX:
179		afname = "IPX";
180		break;
181#ifdef NS
182	case AF_NS:
183		afname = "XNS";
184		break;
185#endif
186	case AF_ISO:
187		afname = "ISO";
188		break;
189	case AF_APPLETALK:
190		afname = "AppleTalk";
191		break;
192	case AF_CCITT:
193		afname = "X.25";
194		break;
195	default:
196		afname = NULL;
197		break;
198	}
199	if (afname)
200		printf("\n%s:\n", afname);
201	else
202		printf("\nProtocol Family %d:\n", af);
203}
204
205/* column widths; each followed by one space */
206#define	WID_DST		18	/* width of destination column */
207#define	WID_GW		18	/* width of gateway column */
208
209/*
210 * Print header for routing table columns.
211 */
212void
213pr_rthdr()
214{
215	if (Aflag)
216		printf("%-8.8s ","Address");
217	printf("%-*.*s %-*.*s %-6.6s  %6.6s%8.8s  %8.8s %6s\n",
218		WID_DST, WID_DST, "Destination",
219		WID_GW, WID_GW, "Gateway",
220		"Flags", "Refs", "Use", "Netif", "Expire");
221}
222
223static struct sockaddr *
224kgetsa(dst)
225	register struct sockaddr *dst;
226{
227
228	kget(dst, pt_u.u_sa);
229	if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
230		kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
231	return (&pt_u.u_sa);
232}
233
234static void
235p_tree(rn)
236	struct radix_node *rn;
237{
238
239again:
240	kget(rn, rnode);
241	if (rnode.rn_b < 0) {
242		if (Aflag)
243			printf("%-8.8x ", (int)rn);
244		if (rnode.rn_flags & RNF_ROOT) {
245			if (Aflag)
246				printf("(root node)%s",
247				    rnode.rn_dupedkey ? " =>\n" : "\n");
248		} else if (do_rtent) {
249			kget(rn, rtentry);
250			p_rtentry(&rtentry);
251			if (Aflag)
252				p_rtnode();
253		} else {
254			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
255				   NULL, 0, 44);
256			putchar('\n');
257		}
258		if ((rn = rnode.rn_dupedkey))
259			goto again;
260	} else {
261		if (Aflag && do_rtent) {
262			printf("%-8.8x ", (int)rn);
263			p_rtnode();
264		}
265		rn = rnode.rn_r;
266		p_tree(rnode.rn_l);
267		p_tree(rn);
268	}
269}
270
271char	nbuf[20];
272
273static void
274p_rtnode()
275{
276	struct radix_mask *rm = rnode.rn_mklist;
277
278	if (rnode.rn_b < 0) {
279		if (rnode.rn_mask) {
280			printf("\t  mask ");
281			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
282				   NULL, 0, -1);
283		} else if (rm == 0)
284			return;
285	} else {
286		sprintf(nbuf, "(%d)", rnode.rn_b);
287		printf("%6.6s %8.8x : %8.8x", nbuf, (int)rnode.rn_l, (int)rnode.rn_r);
288	}
289	while (rm) {
290		kget(rm, rmask);
291		sprintf(nbuf, " %d refs, ", rmask.rm_refs);
292		printf(" mk = %8.8x {(%d),%s",
293			(int)rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
294		if (rmask.rm_flags & RNF_NORMAL) {
295			struct radix_node rnode_aux;
296			printf(" <normal>, ");
297			kget(rmask.rm_leaf, rnode_aux);
298			p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask),
299				    NULL, 0, -1);
300		} else
301		    p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask),
302				NULL, 0, -1);
303		putchar('}');
304		if ((rm = rmask.rm_mklist))
305			printf(" ->");
306	}
307	putchar('\n');
308}
309
310static void
311ntreestuff()
312{
313	size_t needed;
314	int mib[6];
315	char *buf, *next, *lim;
316	register struct rt_msghdr *rtm;
317
318        mib[0] = CTL_NET;
319        mib[1] = PF_ROUTE;
320        mib[2] = 0;
321        mib[3] = 0;
322        mib[4] = NET_RT_DUMP;
323        mib[5] = 0;
324        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
325		err(1, "sysctl: net.route.0.0.dump estimate");
326	}
327
328	if ((buf = malloc(needed)) == 0) {
329		err(2, "malloc(%lu)", (unsigned long)needed);
330	}
331        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
332		err(1, "sysctl: net.route.0.0.dump");
333	}
334	lim  = buf + needed;
335	for (next = buf; next < lim; next += rtm->rtm_msglen) {
336		rtm = (struct rt_msghdr *)next;
337		np_rtentry(rtm);
338	}
339}
340
341static void
342np_rtentry(rtm)
343	register struct rt_msghdr *rtm;
344{
345	register struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
346#ifdef notdef
347	static int masks_done, banner_printed;
348#endif
349	static int old_af;
350	int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
351
352#ifdef notdef
353	/* for the moment, netmasks are skipped over */
354	if (!banner_printed) {
355		printf("Netmasks:\n");
356		banner_printed = 1;
357	}
358	if (masks_done == 0) {
359		if (rtm->rtm_addrs != RTA_DST ) {
360			masks_done = 1;
361			af = sa->sa_family;
362		}
363	} else
364#endif
365		af = sa->sa_family;
366	if (af != old_af) {
367		pr_family(af);
368		old_af = af;
369	}
370	if (rtm->rtm_addrs == RTA_DST)
371		p_sockaddr(sa, NULL, 0, 36);
372	else {
373		p_sockaddr(sa, NULL, rtm->rtm_flags, 16);
374		if (sa->sa_len == 0)
375			sa->sa_len = sizeof(long);
376		sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
377		p_sockaddr(sa, NULL, 0, 18);
378	}
379	p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
380	putchar('\n');
381}
382
383static void
384p_sockaddr(sa, mask, flags, width)
385	struct sockaddr *sa, *mask;
386	int flags, width;
387{
388	char workbuf[128], *cplim;
389	register char *cp = workbuf;
390
391	switch(sa->sa_family) {
392	case AF_INET:
393	    {
394		register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
395
396		if (sin->sin_addr.s_addr == INADDR_ANY)
397			cp = "default";
398		else if (flags & RTF_HOST)
399			cp = routename(sin->sin_addr.s_addr);
400		else if (mask)
401			cp = netname(sin->sin_addr.s_addr,
402				     ntohl(((struct sockaddr_in *)mask)
403					   ->sin_addr.s_addr));
404		else
405			cp = netname(sin->sin_addr.s_addr, 0L);
406		break;
407	    }
408
409	case AF_IPX:
410	    {
411		struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
412		if (ipx_nullnet(satoipx_addr(work)))
413			cp = "default";
414		else
415			cp = ipx_print(sa);
416		break;
417	    }
418	case AF_APPLETALK:
419	    {
420		if (!(flags & RTF_HOST) && mask)
421			cp = atalk_print2(sa,mask,9);
422		else
423			cp = atalk_print(sa,11);
424		break;
425	    }
426#ifdef NS
427	case AF_NS:
428		cp = ns_print(sa);
429		break;
430#endif
431
432	case AF_LINK:
433	    {
434		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
435
436		if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
437		    sdl->sdl_slen == 0)
438			(void) sprintf(workbuf, "link#%d", sdl->sdl_index);
439		else switch (sdl->sdl_type) {
440		case IFT_ETHER:
441		    {
442			register int i;
443			register u_char *lla = (u_char *)sdl->sdl_data +
444			    sdl->sdl_nlen;
445
446			cplim = "";
447			for (i = 0; i < sdl->sdl_alen; i++, lla++) {
448				cp += sprintf(cp, "%s%x", cplim, *lla);
449				cplim = ":";
450			}
451			cp = workbuf;
452			break;
453		    }
454		default:
455			cp = link_ntoa(sdl);
456			break;
457		}
458		break;
459	    }
460
461	default:
462	    {
463		register u_char *s = (u_char *)sa->sa_data, *slim;
464
465		slim =  sa->sa_len + (u_char *) sa;
466		cplim = cp + sizeof(workbuf) - 6;
467		cp += sprintf(cp, "(%d)", sa->sa_family);
468		while (s < slim && cp < cplim) {
469			cp += sprintf(cp, " %02x", *s++);
470			if (s < slim)
471			    cp += sprintf(cp, "%02x", *s++);
472		}
473		cp = workbuf;
474	    }
475	}
476	if (width < 0 )
477		printf("%s ", cp);
478	else {
479		if (nflag)
480			printf("%-*s ", width, cp);
481		else
482			printf("%-*.*s ", width, width, cp);
483	}
484}
485
486static void
487p_flags(f, format)
488	register int f;
489	char *format;
490{
491	char name[33], *flags;
492	register struct bits *p = bits;
493
494	for (flags = name; p->b_mask; p++)
495		if (p->b_mask & f)
496			*flags++ = p->b_val;
497	*flags = '\0';
498	printf(format, name);
499}
500
501static void
502p_rtentry(rt)
503	register struct rtentry *rt;
504{
505	static struct ifnet ifnet, *lastif;
506	static char name[16];
507	static char prettyname[9];
508	struct sockaddr *sa;
509	struct sockaddr addr, mask;
510
511	/*
512	 * Don't print protocol-cloned routes unless -a.
513	 */
514	if(rt->rt_parent && !aflag)
515		return;
516
517	if (!(sa = kgetsa(rt_key(rt))))
518		bzero(&addr, sizeof addr);
519	else
520		addr = *sa;
521	if (!rt_mask(rt) || !(sa = kgetsa(rt_mask(rt))))
522		bzero(&mask, sizeof mask);
523	else
524		mask = *sa;
525	p_sockaddr(&addr, &mask, rt->rt_flags, WID_DST);
526	p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW);
527	p_flags(rt->rt_flags, "%-6.6s ");
528	printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use);
529	if (rt->rt_ifp) {
530		if (rt->rt_ifp != lastif) {
531			kget(rt->rt_ifp, ifnet);
532			kread((u_long)ifnet.if_name, name, 16);
533			lastif = rt->rt_ifp;
534			snprintf(prettyname, sizeof prettyname,
535				 "%.6s%d", name, ifnet.if_unit);
536		}
537		if(rt->rt_rmx.rmx_expire) {
538			time_t expire_time;
539
540		        if ((expire_time
541			       =rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
542			    printf(" %8.8s %6d%s", prettyname,
543				   (int)expire_time,
544				   rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
545		} else {
546			printf(" %8.8s%s", prettyname,
547			       rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
548		}
549
550	}
551	putchar('\n');
552}
553
554char *
555routename(in)
556	u_long in;
557{
558	register char *cp;
559	static char line[MAXHOSTNAMELEN + 1];
560	struct hostent *hp;
561
562	cp = 0;
563	if (!nflag) {
564		hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
565			AF_INET);
566		if (hp) {
567			cp = hp->h_name;
568			trimdomain(cp);
569		}
570	}
571	if (cp)
572		strncpy(line, cp, sizeof(line) - 1);
573	else {
574#define C(x)	((x) & 0xff)
575		in = ntohl(in);
576		sprintf(line, "%lu.%lu.%lu.%lu",
577		    C(in >> 24), C(in >> 16), C(in >> 8), C(in));
578	}
579	return (line);
580}
581
582static u_long
583forgemask(a)
584	u_long a;
585{
586	u_long m;
587
588	if (IN_CLASSA(a))
589		m = IN_CLASSA_NET;
590	else if (IN_CLASSB(a))
591		m = IN_CLASSB_NET;
592	else
593		m = IN_CLASSC_NET;
594	return (m);
595}
596
597static void
598domask(dst, addr, mask)
599	char *dst;
600	u_long addr, mask;
601{
602	register int b, i;
603
604	if (!mask || (forgemask(addr) == mask)) {
605		*dst = '\0';
606		return;
607	}
608	i = 0;
609	for (b = 0; b < 32; b++)
610		if (mask & (1 << b)) {
611			register int bb;
612
613			i = b;
614			for (bb = b+1; bb < 32; bb++)
615				if (!(mask & (1 << bb))) {
616					i = -1;	/* noncontig */
617					break;
618				}
619			break;
620		}
621	if (i == -1)
622		sprintf(dst, "&0x%lx", mask);
623	else
624		sprintf(dst, "/%d", 32-i);
625}
626
627/*
628 * Return the name of the network whose address is given.
629 * The address is assumed to be that of a net or subnet, not a host.
630 */
631char *
632netname(in, mask)
633	u_long in, mask;
634{
635	char *cp = 0;
636	static char line[MAXHOSTNAMELEN + 1];
637	struct netent *np = 0;
638	u_long net, omask;
639	register u_long i;
640	int subnetshift;
641
642	i = ntohl(in);
643	omask = mask;
644	if (!nflag && i) {
645		if (mask == 0) {
646			switch (mask = forgemask(i)) {
647			case IN_CLASSA_NET:
648				subnetshift = 8;
649				break;
650			case IN_CLASSB_NET:
651				subnetshift = 8;
652				break;
653			case IN_CLASSC_NET:
654				subnetshift = 4;
655				break;
656			default:
657				abort();
658			}
659			/*
660			 * If there are more bits than the standard mask
661			 * would suggest, subnets must be in use.
662			 * Guess at the subnet mask, assuming reasonable
663			 * width subnet fields.
664			 */
665			while (i &~ mask)
666				mask = (long)mask >> subnetshift;
667		}
668		net = i & mask;
669		while ((mask & 1) == 0)
670			mask >>= 1, net >>= 1;
671		if (!(np = getnetbyaddr(i, AF_INET)))
672			np = getnetbyaddr(net, AF_INET);
673		if (np) {
674			cp = np->n_name;
675			trimdomain(cp);
676		}
677	}
678	if (cp)
679		strncpy(line, cp, sizeof(line) - 1);
680	else if ((i & 0xffffff) == 0)
681		sprintf(line, "%lu", C(i >> 24));
682	else if ((i & 0xffff) == 0)
683		sprintf(line, "%lu.%lu", C(i >> 24) , C(i >> 16));
684	else if ((i & 0xff) == 0)
685		sprintf(line, "%lu.%lu.%lu", C(i >> 24), C(i >> 16), C(i >> 8));
686	else
687		sprintf(line, "%lu.%lu.%lu.%lu", C(i >> 24),
688			C(i >> 16), C(i >> 8), C(i));
689	domask(line+strlen(line), i, omask);
690	return (line);
691}
692
693/*
694 * Print routing statistics
695 */
696void
697rt_stats(off)
698	u_long off;
699{
700	struct rtstat rtstat;
701
702	if (off == 0) {
703		printf("rtstat: symbol not in namelist\n");
704		return;
705	}
706	kread(off, (char *)&rtstat, sizeof (rtstat));
707	printf("routing:\n");
708	printf("\t%u bad routing redirect%s\n",
709		rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
710	printf("\t%u dynamically created route%s\n",
711		rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
712	printf("\t%u new gateway%s due to redirects\n",
713		rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
714	printf("\t%u destination%s found unreachable\n",
715		rtstat.rts_unreach, plural(rtstat.rts_unreach));
716	printf("\t%u use%s of a wildcard route\n",
717		rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
718}
719
720char *
721ipx_print(sa)
722	register struct sockaddr *sa;
723{
724	u_short port;
725	struct netent *np = 0;
726	struct hostent *hp = 0;
727	struct servent *sp = 0;
728	char *net = "", *host = "";
729	register char *p; register u_char *q;
730	struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
731static	char mybuf[50];
732	char cport[10], chost[15], cnet[15];
733
734	if(!nflag)
735		sp = getservbyport(work.x_port, "ipx");
736	port = ntohs(work.x_port);
737
738	if (ipx_nullnet(work) && ipx_nullhost(work)) {
739
740		if (port) {
741			if (sp)	sprintf(mybuf, "*.%s", sp->s_name);
742			else	sprintf(mybuf, "*.%x", port);
743		} else
744			sprintf(mybuf, "*.*");
745
746		return (mybuf);
747	}
748
749	if (!nflag && (np = getnetbyaddr(*(u_long *)&work.x_net, AF_IPX)))
750		net = np->n_name;
751	else if (ipx_wildnet(work))
752		net = "any";
753	else if (ipx_nullnet(work))
754		net = "*";
755	else {
756		q = work.x_net.c_net;
757		sprintf(cnet, "%02x%02x%02x%02x",
758			q[0], q[1], q[2], q[3]);
759		for (p = cnet; *p == '0' && p < cnet + 8; p++)
760			continue;
761		net = p;
762	}
763
764	if (!nflag && (hp = gethostbyaddr((char *)&work.x_host, 6, AF_IPX)))
765		host = hp->h_name;
766	else if (ipx_wildhost(work))
767		host = "any";
768	else if (ipx_nullhost(work))
769		host = "*";
770	else {
771		q = work.x_host.c_host;
772		sprintf(chost, "%02x%02x%02x%02x%02x%02x",
773			q[0], q[1], q[2], q[3], q[4], q[5]);
774		for (p = chost; *p == '0' && p < chost + 12; p++)
775			continue;
776		host = p;
777	}
778
779	if (port) {
780		if (strcmp(host, "*") == 0) host = "";
781		if (sp)	sprintf(cport, "%s%s", *host ? "." : "", sp->s_name);
782		else	sprintf(cport, "%s%x", *host ? "." : "", port);
783	} else
784		*cport = 0;
785
786	sprintf(mybuf,"%s.%s%s", net, host, cport);
787	return(mybuf);
788}
789
790char *
791ipx_phost(sa)
792	struct sockaddr *sa;
793{
794	register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa;
795	struct sockaddr_ipx work;
796static	union ipx_net ipx_zeronet;
797	char *p;
798	struct ipx_addr in;
799	struct hostent *hp;
800
801	work = *sipx;
802	in = work.sipx_addr;
803
804	hp = gethostbyaddr((char *)&in, sizeof(struct ipx_addr), AF_IPX);
805	if (hp)	return (hp->h_name);
806
807	work.sipx_addr.x_port = 0;
808	work.sipx_addr.x_net = ipx_zeronet;
809	p = ipx_print((struct sockaddr *)&work);
810	if (strncmp("*.", p, 2) == 0) p += 2;
811
812	return(p);
813}
814
815#ifdef NS
816short ns_nullh[] = {0,0,0};
817short ns_bh[] = {-1,-1,-1};
818
819char *
820ns_print(sa)
821	register struct sockaddr *sa;
822{
823	register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa;
824	struct ns_addr work;
825	union { union ns_net net_e; u_long long_e; } net;
826	u_short port;
827	static char mybuf[50], cport[10], chost[25];
828	char *host = "";
829	register char *p; register u_char *q;
830
831	work = sns->sns_addr;
832	port = ntohs(work.x_port);
833	work.x_port = 0;
834	net.net_e  = work.x_net;
835	if (ns_nullhost(work) && net.long_e == 0) {
836		if (port ) {
837			sprintf(mybuf, "*.%xH", port);
838			upHex(mybuf);
839		} else
840			sprintf(mybuf, "*.*");
841		return (mybuf);
842	}
843
844	if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
845		host = "any";
846	} else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
847		host = "*";
848	} else {
849		q = work.x_host.c_host;
850		sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
851			q[0], q[1], q[2], q[3], q[4], q[5]);
852		for (p = chost; *p == '0' && p < chost + 12; p++)
853			continue;
854		host = p;
855	}
856	if (port)
857		sprintf(cport, ".%xH", htons(port));
858	else
859		*cport = 0;
860
861	sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
862	upHex(mybuf);
863	return(mybuf);
864}
865
866char *
867ns_phost(sa)
868	struct sockaddr *sa;
869{
870	register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa;
871	struct sockaddr_ns work;
872	static union ns_net ns_zeronet;
873	char *p;
874
875	work = *sns;
876	work.sns_addr.x_port = 0;
877	work.sns_addr.x_net = ns_zeronet;
878
879	p = ns_print((struct sockaddr *)&work);
880	if (strncmp("0H.", p, 3) == 0) p += 3;
881	return(p);
882}
883#endif
884
885void
886upHex(p0)
887	char *p0;
888{
889	register char *p = p0;
890	for (; *p; p++) switch (*p) {
891
892	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
893		*p += ('A' - 'a');
894	}
895}
896