]> git.saurik.com Git - apple/network_cmds.git/blob - tcpdump.tproj/addrtoname.c
network_cmds-77.tar.gz
[apple/network_cmds.git] / tcpdump.tproj / addrtoname.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that: (1) source code distributions
30 * retain the above copyright notice and this paragraph in its entirety, (2)
31 * distributions including binary code include the above copyright notice and
32 * this paragraph in its entirety in the documentation or other materials
33 * provided with the distribution, and (3) all advertising materials mentioning
34 * features or use of this software display the following acknowledgement:
35 * ``This product includes software developed by the University of California,
36 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
37 * the University nor the names of its contributors may be used to endorse
38 * or promote products derived from this software without specific prior
39 * written permission.
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
41 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
43 *
44 * Internet, ethernet, port, and protocol string to address
45 * and address to string conversion routines
46 */
47 #ifndef lint
48 static const char rcsid[] =
49 "@(#) $Header: /cvs/Darwin/Commands/NeXT/network_cmds/tcpdump.tproj/addrtoname.c,v 1.1.1.1 1999/05/02 03:58:31 wsanchez Exp $ (LBL)";
50 #endif
51
52 #include <sys/types.h>
53 #include <sys/socket.h>
54 #include <sys/time.h>
55
56 #if __STDC__
57 struct mbuf;
58 struct rtentry;
59 #endif
60 #include <net/if.h>
61
62 #include <netinet/in.h>
63 #include <netinet/if_ether.h>
64
65 #include <arpa/inet.h>
66
67 #include <ctype.h>
68 #include <netdb.h>
69 #include <pcap.h>
70 #include <pcap-namedb.h>
71 #include <signal.h>
72 #include <stdio.h>
73 #include <string.h>
74 #include <stdlib.h>
75 #include <unistd.h>
76
77 #include "interface.h"
78 #include "addrtoname.h"
79 #include "llc.h"
80
81 /* Forwards */
82 static RETSIGTYPE nohostname(int);
83
84 /*
85 * hash tables for whatever-to-name translations
86 */
87
88 #define HASHNAMESIZE 4096
89
90 struct hnamemem {
91 u_int32_t addr;
92 char *name;
93 struct hnamemem *nxt;
94 };
95
96 struct hnamemem hnametable[HASHNAMESIZE];
97 struct hnamemem tporttable[HASHNAMESIZE];
98 struct hnamemem uporttable[HASHNAMESIZE];
99 struct hnamemem eprototable[HASHNAMESIZE];
100 struct hnamemem dnaddrtable[HASHNAMESIZE];
101 struct hnamemem llcsaptable[HASHNAMESIZE];
102
103 struct enamemem {
104 u_short e_addr0;
105 u_short e_addr1;
106 u_short e_addr2;
107 char *e_name;
108 u_char *e_nsap; /* used only for nsaptable[] */
109 struct enamemem *e_nxt;
110 };
111
112 struct enamemem enametable[HASHNAMESIZE];
113 struct enamemem nsaptable[HASHNAMESIZE];
114
115 struct protoidmem {
116 u_int32_t p_oui;
117 u_short p_proto;
118 char *p_name;
119 struct protoidmem *p_nxt;
120 };
121
122 struct protoidmem protoidtable[HASHNAMESIZE];
123
124 /*
125 * A faster replacement for inet_ntoa().
126 */
127 char *
128 intoa(u_int32_t addr)
129 {
130 register char *cp;
131 register u_int byte;
132 register int n;
133 static char buf[sizeof(".xxx.xxx.xxx.xxx")];
134
135 NTOHL(addr);
136 cp = &buf[sizeof buf];
137 *--cp = '\0';
138
139 n = 4;
140 do {
141 byte = addr & 0xff;
142 *--cp = byte % 10 + '0';
143 byte /= 10;
144 if (byte > 0) {
145 *--cp = byte % 10 + '0';
146 byte /= 10;
147 if (byte > 0)
148 *--cp = byte + '0';
149 }
150 *--cp = '.';
151 addr >>= 8;
152 } while (--n > 0);
153
154 return cp + 1;
155 }
156
157 static u_int32_t f_netmask;
158 static u_int32_t f_localnet;
159 static u_int32_t netmask;
160
161 /*
162 * "getname" is written in this atrocious way to make sure we don't
163 * wait forever while trying to get hostnames from yp.
164 */
165 #include <setjmp.h>
166
167 jmp_buf getname_env;
168
169 static RETSIGTYPE
170 nohostname(int signo)
171 {
172 longjmp(getname_env, 1);
173 }
174
175 /*
176 * Return a name for the IP address pointed to by ap. This address
177 * is assumed to be in network byte order.
178 */
179 char *
180 getname(const u_char *ap)
181 {
182 register struct hostent *hp;
183 u_int32_t addr;
184 static struct hnamemem *p; /* static for longjmp() */
185
186 #ifndef LBL_ALIGN
187 addr = *(const u_int32_t *)ap;
188 #else
189 /*
190 * Extract 32 bits in network order, dealing with alignment.
191 */
192 switch ((long)ap & 3) {
193
194 case 0:
195 addr = *(u_int32_t *)ap;
196 break;
197
198 case 2:
199 #ifdef WORDS_BIGENDIAN
200 addr = ((u_int32_t)*(u_short *)ap << 16) |
201 (u_int32_t)*(u_short *)(ap + 2);
202 #else
203 addr = ((u_int32_t)*(u_short *)(ap + 2) << 16) |
204 (u_int32_t)*(u_short *)ap;
205 #endif
206 break;
207
208 default:
209 #ifdef WORDS_BIGENDIAN
210 addr = ((u_int32_t)ap[0] << 24) |
211 ((u_int32_t)ap[1] << 16) |
212 ((u_int32_t)ap[2] << 8) |
213 (u_int32_t)ap[3];
214 #else
215 addr = ((u_int32_t)ap[3] << 24) |
216 ((u_int32_t)ap[2] << 16) |
217 ((u_int32_t)ap[1] << 8) |
218 (u_int32_t)ap[0];
219 #endif
220 break;
221 }
222 #endif
223 p = &hnametable[addr & (HASHNAMESIZE-1)];
224 for (; p->nxt; p = p->nxt) {
225 if (p->addr == addr)
226 return (p->name);
227 }
228 p->addr = addr;
229 p->nxt = newhnamemem();
230
231 /*
232 * Only print names when:
233 * (1) -n was not given.
234 * (2) Address is foreign and -f was given. If -f was not
235 * present, f_netmask and f_local are 0 and the second
236 * test will succeed.
237 * (3) The host portion is not 0 (i.e., a network address).
238 * (4) The host portion is not broadcast.
239 */
240 if (!nflag && (addr & f_netmask) == f_localnet
241 && (addr &~ netmask) != 0 && (addr | netmask) != 0xffffffff) {
242 if (!setjmp(getname_env)) {
243 (void)signal(SIGALRM, nohostname);
244 (void)alarm(20);
245 hp = gethostbyaddr((char *)&addr, 4, AF_INET);
246 (void)alarm(0);
247 if (hp) {
248 char *dotp;
249
250 p->name = savestr(hp->h_name);
251 if (Nflag) {
252 /* Remove domain qualifications */
253 dotp = strchr(p->name, '.');
254 if (dotp)
255 *dotp = '\0';
256 }
257 return (p->name);
258 }
259 }
260 }
261 p->name = savestr(intoa(addr));
262 return (p->name);
263 }
264
265 static char hex[] = "0123456789abcdef";
266
267
268 /* Find the hash node that corresponds the ether address 'ep' */
269
270 static inline struct enamemem *
271 lookup_emem(const u_char *ep)
272 {
273 register u_int i, j, k;
274 struct enamemem *tp;
275
276 k = (ep[0] << 8) | ep[1];
277 j = (ep[2] << 8) | ep[3];
278 i = (ep[4] << 8) | ep[5];
279
280 tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
281 while (tp->e_nxt)
282 if (tp->e_addr0 == i &&
283 tp->e_addr1 == j &&
284 tp->e_addr2 == k)
285 return tp;
286 else
287 tp = tp->e_nxt;
288 tp->e_addr0 = i;
289 tp->e_addr1 = j;
290 tp->e_addr2 = k;
291 tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
292 if (tp->e_nxt == NULL)
293 error("lookup_emem: calloc");
294
295 return tp;
296 }
297
298 /* Find the hash node that corresponds the NSAP 'nsap' */
299
300 static inline struct enamemem *
301 lookup_nsap(register const u_char *nsap)
302 {
303 register u_int i, j, k;
304 int nlen = *nsap;
305 struct enamemem *tp;
306 const u_char *ensap = nsap + nlen - 6;
307
308 if (nlen > 6) {
309 k = (ensap[0] << 8) | ensap[1];
310 j = (ensap[2] << 8) | ensap[3];
311 i = (ensap[4] << 8) | ensap[5];
312 }
313 else
314 i = j = k = 0;
315
316 tp = &nsaptable[(i ^ j) & (HASHNAMESIZE-1)];
317 while (tp->e_nxt)
318 if (tp->e_addr0 == i &&
319 tp->e_addr1 == j &&
320 tp->e_addr2 == k &&
321 tp->e_nsap[0] == nlen &&
322 memcmp((char *)&(nsap[1]),
323 (char *)&(tp->e_nsap[1]), nlen) == 0)
324 return tp;
325 else
326 tp = tp->e_nxt;
327 tp->e_addr0 = i;
328 tp->e_addr1 = j;
329 tp->e_addr2 = k;
330 tp->e_nsap = (u_char *)malloc(nlen + 1);
331 if (tp->e_nsap == NULL)
332 error("lookup_nsap: malloc");
333 memcpy(tp->e_nsap, nsap, nlen + 1);
334 tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
335 if (tp->e_nxt == NULL)
336 error("lookup_nsap: calloc");
337
338 return tp;
339 }
340
341 /* Find the hash node that corresponds the protoid 'pi'. */
342
343 static inline struct protoidmem *
344 lookup_protoid(const u_char *pi)
345 {
346 register u_int i, j;
347 struct protoidmem *tp;
348
349 /* 5 octets won't be aligned */
350 i = (((pi[0] << 8) + pi[1]) << 8) + pi[2];
351 j = (pi[3] << 8) + pi[4];
352 /* XXX should be endian-insensitive, but do big-endian testing XXX */
353
354 tp = &protoidtable[(i ^ j) & (HASHNAMESIZE-1)];
355 while (tp->p_nxt)
356 if (tp->p_oui == i && tp->p_proto == j)
357 return tp;
358 else
359 tp = tp->p_nxt;
360 tp->p_oui = i;
361 tp->p_proto = j;
362 tp->p_nxt = (struct protoidmem *)calloc(1, sizeof(*tp));
363 if (tp->p_nxt == NULL)
364 error("lookup_protoid: calloc");
365
366 return tp;
367 }
368
369 char *
370 etheraddr_string(register const u_char *ep)
371 {
372 register u_int i, j;
373 register char *cp;
374 register struct enamemem *tp;
375 char buf[sizeof("00:00:00:00:00:00")];
376
377 tp = lookup_emem(ep);
378 if (tp->e_name)
379 return (tp->e_name);
380 #ifdef HAVE_ETHER_NTOHOST
381 if (!nflag) {
382 char buf[128];
383 if (ether_ntohost(buf, (struct ether_addr *)ep) == 0) {
384 tp->e_name = savestr(buf);
385 return (tp->e_name);
386 }
387 }
388 #endif
389 cp = buf;
390 if ((j = *ep >> 4) != 0)
391 *cp++ = hex[j];
392 *cp++ = hex[*ep++ & 0xf];
393 for (i = 5; (int)--i >= 0;) {
394 *cp++ = ':';
395 if ((j = *ep >> 4) != 0)
396 *cp++ = hex[j];
397 *cp++ = hex[*ep++ & 0xf];
398 }
399 *cp = '\0';
400 tp->e_name = savestr(buf);
401 return (tp->e_name);
402 }
403
404 char *
405 etherproto_string(u_short port)
406 {
407 register char *cp;
408 register struct hnamemem *tp;
409 register u_int32_t i = port;
410 char buf[sizeof("0000")];
411
412 for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
413 if (tp->addr == i)
414 return (tp->name);
415
416 tp->addr = i;
417 tp->nxt = newhnamemem();
418
419 cp = buf;
420 NTOHS(port);
421 *cp++ = hex[port >> 12 & 0xf];
422 *cp++ = hex[port >> 8 & 0xf];
423 *cp++ = hex[port >> 4 & 0xf];
424 *cp++ = hex[port & 0xf];
425 *cp++ = '\0';
426 tp->name = savestr(buf);
427 return (tp->name);
428 }
429
430 char *
431 protoid_string(register const u_char *pi)
432 {
433 register u_int i, j;
434 register char *cp;
435 register struct protoidmem *tp;
436 char buf[sizeof("00:00:00:00:00")];
437
438 tp = lookup_protoid(pi);
439 if (tp->p_name)
440 return tp->p_name;
441
442 cp = buf;
443 if ((j = *pi >> 4) != 0)
444 *cp++ = hex[j];
445 *cp++ = hex[*pi++ & 0xf];
446 for (i = 4; (int)--i >= 0;) {
447 *cp++ = ':';
448 if ((j = *pi >> 4) != 0)
449 *cp++ = hex[j];
450 *cp++ = hex[*pi++ & 0xf];
451 }
452 *cp = '\0';
453 tp->p_name = savestr(buf);
454 return (tp->p_name);
455 }
456
457 char *
458 llcsap_string(u_char sap)
459 {
460 register char *cp;
461 register struct hnamemem *tp;
462 register u_int32_t i = sap;
463 char buf[sizeof("sap 00")];
464
465 for (tp = &llcsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
466 if (tp->addr == i)
467 return (tp->name);
468
469 tp->addr = i;
470 tp->nxt = newhnamemem();
471
472 cp = buf;
473 (void)strcpy(cp, "sap ");
474 cp += strlen(cp);
475 *cp++ = hex[sap >> 4 & 0xf];
476 *cp++ = hex[sap & 0xf];
477 *cp++ = '\0';
478 tp->name = savestr(buf);
479 return (tp->name);
480 }
481
482 char *
483 isonsap_string(const u_char *nsap)
484 {
485 register u_int i, nlen = nsap[0];
486 register char *cp;
487 register struct enamemem *tp;
488
489 tp = lookup_nsap(nsap);
490 if (tp->e_name)
491 return tp->e_name;
492
493 tp->e_name = cp = (char *)malloc(nlen * 2 + 2);
494 if (cp == NULL)
495 error("isonsap_string: malloc");
496
497 nsap++;
498 *cp++ = '/';
499 for (i = nlen; (int)--i >= 0;) {
500 *cp++ = hex[*nsap >> 4];
501 *cp++ = hex[*nsap++ & 0xf];
502 }
503 *cp = '\0';
504 return (tp->e_name);
505 }
506
507 char *
508 tcpport_string(u_short port)
509 {
510 register struct hnamemem *tp;
511 register u_int32_t i = port;
512 char buf[sizeof("00000")];
513
514 for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
515 if (tp->addr == i)
516 return (tp->name);
517
518 tp->addr = i;
519 tp->nxt = newhnamemem();
520
521 (void)sprintf(buf, "%u", i);
522 tp->name = savestr(buf);
523 return (tp->name);
524 }
525
526 char *
527 udpport_string(register u_short port)
528 {
529 register struct hnamemem *tp;
530 register u_int32_t i = port;
531 char buf[sizeof("00000")];
532
533 for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
534 if (tp->addr == i)
535 return (tp->name);
536
537 tp->addr = i;
538 tp->nxt = newhnamemem();
539
540 (void)sprintf(buf, "%u", i);
541 tp->name = savestr(buf);
542 return (tp->name);
543 }
544
545 static void
546 init_servarray(void)
547 {
548 struct servent *sv;
549 register struct hnamemem *table;
550 register int i;
551 char buf[sizeof("0000000000")];
552
553 while ((sv = getservent()) != NULL) {
554 int port = ntohs(sv->s_port);
555 i = port & (HASHNAMESIZE-1);
556 if (strcmp(sv->s_proto, "tcp") == 0)
557 table = &tporttable[i];
558 else if (strcmp(sv->s_proto, "udp") == 0)
559 table = &uporttable[i];
560 else
561 continue;
562
563 while (table->name)
564 table = table->nxt;
565 if (nflag) {
566 (void)sprintf(buf, "%d", port);
567 table->name = savestr(buf);
568 } else
569 table->name = savestr(sv->s_name);
570 table->addr = port;
571 table->nxt = newhnamemem();
572 }
573 endservent();
574 }
575
576 /*XXX from libbpfc.a */
577 extern struct eproto {
578 char *s;
579 u_short p;
580 } eproto_db[];
581
582 static void
583 init_eprotoarray(void)
584 {
585 register int i;
586 register struct hnamemem *table;
587
588 for (i = 0; eproto_db[i].s; i++) {
589 int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1);
590 table = &eprototable[j];
591 while (table->name)
592 table = table->nxt;
593 table->name = eproto_db[i].s;
594 table->addr = ntohs(eproto_db[i].p);
595 table->nxt = newhnamemem();
596 }
597 }
598
599 /*
600 * SNAP proto IDs with org code 0:0:0 are actually encapsulated Ethernet
601 * types.
602 */
603 static void
604 init_protoidarray(void)
605 {
606 register int i;
607 register struct protoidmem *tp;
608 u_char protoid[5];
609
610 protoid[0] = 0;
611 protoid[1] = 0;
612 protoid[2] = 0;
613 for (i = 0; eproto_db[i].s; i++) {
614 u_short etype = htons(eproto_db[i].p);
615
616 memcpy((char *)&protoid[3], (char *)&etype, 2);
617 tp = lookup_protoid(protoid);
618 tp->p_name = savestr(eproto_db[i].s);
619 }
620 }
621
622 static struct etherlist {
623 u_char addr[6];
624 char *name;
625 } etherlist[] = {
626 {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, "Broadcast" },
627 {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
628 };
629
630 /*
631 * Initialize the ethers hash table. We take two different approaches
632 * depending on whether or not the system provides the ethers name
633 * service. If it does, we just wire in a few names at startup,
634 * and etheraddr_string() fills in the table on demand. If it doesn't,
635 * then we suck in the entire /etc/ethers file at startup. The idea
636 * is that parsing the local file will be fast, but spinning through
637 * all the ethers entries via NIS & next_etherent might be very slow.
638 *
639 * XXX pcap_next_etherent doesn't belong in the pcap interface, but
640 * since the pcap module already does name-to-address translation,
641 * it's already does most of the work for the ethernet address-to-name
642 * translation, so we just pcap_next_etherent as a convenience.
643 */
644 static void
645 init_etherarray(void)
646 {
647 register struct etherlist *el;
648 register struct enamemem *tp;
649 #ifdef HAVE_ETHER_NTOHOST
650 char name[256];
651 #else
652 register struct pcap_etherent *ep;
653 register FILE *fp;
654
655 /* Suck in entire ethers file */
656 fp = fopen(PCAP_ETHERS_FILE, "r");
657 if (fp != NULL) {
658 while ((ep = pcap_next_etherent(fp)) != NULL) {
659 tp = lookup_emem(ep->addr);
660 tp->e_name = savestr(ep->name);
661 }
662 (void)fclose(fp);
663 }
664 #endif
665
666 /* Hardwire some ethernet names */
667 for (el = etherlist; el->name != NULL; ++el) {
668 tp = lookup_emem(el->addr);
669 /* Don't override existing name */
670 if (tp->e_name != NULL)
671 continue;
672
673 #ifdef HAVE_ETHER_NTOHOST
674 /* Use yp/nis version of name if available */
675 if (ether_ntohost(name, (struct ether_addr *)el->addr) == 0) {
676 tp->e_name = savestr(name);
677 continue;
678 }
679 #endif
680 tp->e_name = el->name;
681 }
682 }
683
684 static struct tok llcsap_db[] = {
685 { LLCSAP_NULL, "null" },
686 { LLCSAP_8021B_I, "802.1b-gsap" },
687 { LLCSAP_8021B_G, "802.1b-isap" },
688 { LLCSAP_IP, "ip-sap" },
689 { LLCSAP_PROWAYNM, "proway-nm" },
690 { LLCSAP_8021D, "802.1d" },
691 { LLCSAP_RS511, "eia-rs511" },
692 { LLCSAP_ISO8208, "x.25/llc2" },
693 { LLCSAP_PROWAY, "proway" },
694 { LLCSAP_ISONS, "iso-clns" },
695 { LLCSAP_GLOBAL, "global" },
696 { 0, NULL }
697 };
698
699 static void
700 init_llcsaparray(void)
701 {
702 register int i;
703 register struct hnamemem *table;
704
705 for (i = 0; llcsap_db[i].s != NULL; i++) {
706 table = &llcsaptable[llcsap_db[i].v];
707 while (table->name)
708 table = table->nxt;
709 table->name = llcsap_db[i].s;
710 table->addr = llcsap_db[i].v;
711 table->nxt = newhnamemem();
712 }
713 }
714
715 /*
716 * Initialize the address to name translation machinery. We map all
717 * non-local IP addresses to numeric addresses if fflag is true (i.e.,
718 * to prevent blocking on the nameserver). localnet is the IP address
719 * of the local network. mask is its subnet mask.
720 */
721 void
722 init_addrtoname(int fflag, u_int32_t localnet, u_int32_t mask)
723 {
724 netmask = mask;
725 if (fflag) {
726 f_localnet = localnet;
727 f_netmask = mask;
728 }
729 if (nflag)
730 /*
731 * Simplest way to suppress names.
732 */
733 return;
734
735 init_etherarray();
736 init_servarray();
737 init_eprotoarray();
738 init_llcsaparray();
739 init_protoidarray();
740 }
741
742 char *
743 dnaddr_string(u_short dnaddr)
744 {
745 register struct hnamemem *tp;
746
747 for (tp = &dnaddrtable[dnaddr & (HASHNAMESIZE-1)]; tp->nxt != 0;
748 tp = tp->nxt)
749 if (tp->addr == dnaddr)
750 return (tp->name);
751
752 tp->addr = dnaddr;
753 tp->nxt = newhnamemem();
754 if (nflag)
755 tp->name = dnnum_string(dnaddr);
756 else
757 tp->name = dnname_string(dnaddr);
758
759 return(tp->name);
760 }
761
762 /* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */
763 struct hnamemem *
764 newhnamemem(void)
765 {
766 register struct hnamemem *p;
767 static struct hnamemem *ptr = NULL;
768 static u_int num = 0;
769
770 if (num <= 0) {
771 num = 64;
772 ptr = (struct hnamemem *)calloc(num, sizeof (*ptr));
773 if (ptr == NULL)
774 error("newhnamemem: calloc");
775 }
776 --num;
777 p = ptr++;
778 return (p);
779 }