new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_net / os_net.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights reserved.
3  *
4  * This program is a free software; you can redistribute it
5  * and/or modify it under the terms of the GNU General Public
6  * License (version 2) as published by the FSF - Free Software
7  * Foundation
8  */
9
10 /* OS_net Library
11  * APIs for many network operations
12  */
13
14 #include <errno.h>
15 #include "shared.h"
16 #include "os_net.h"
17 agent *agt;
18
19 /* Prototypes */
20 static OSNetInfo *OS_Bindport(char *_port, unsigned int _proto, const char *_ip);
21 static int OS_Connect(char *_port, unsigned int protocol, const char *_ip);
22 static int OS_DecodeAddrinfo (struct addrinfo *res);
23 static char *OS_DecodeSockaddr (struct sockaddr *sa);
24 static char *DecodeFamily (int val);
25 static char *DecodeSocktype (int val);
26 static char *DecodeProtocol (int val);
27
28 /* Unix socket -- not for windows */
29 #ifndef WIN32
30 static struct sockaddr_un n_us;
31 static socklen_t us_l = sizeof(n_us);
32
33 /* UNIX SOCKET */
34 #ifndef SUN_LEN
35 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)        \
36                      + strlen ((ptr)->sun_path))
37 #endif /* Sun_LEN */
38
39 #else /* WIN32 */
40 /*int ENOBUFS = 0;*/
41 #ifndef ENOBUFS
42 #define ENOBUFS 0
43 #endif
44
45 #endif /* WIN32*/
46
47
48 /* Bind all relevant ports */
49 OSNetInfo *OS_Bindport(char *_port, unsigned int _proto, const char *_ip)
50 {
51     int ossock = 0, s;
52     struct addrinfo hints, *result, *rp;
53     OSNetInfo *ni;                      /* return data */
54
55     /* Allocate the return data structure and initialize it. */
56     ni = malloc (sizeof (OSNetInfo));
57     memset(ni, 0, sizeof (OSNetInfo));
58     FD_ZERO (&(ni->fdset));
59     ni->fdmax  = 0;
60     ni->fdcnt  = 0;
61     ni->status = 0;
62     ni->retval = 0;
63
64     /* init hints for getaddrinfo() */
65     memset(&hints, 0, sizeof(struct addrinfo));
66
67    /*
68     * If you cannot bind both IPv4 and IPv6, the problem is likely due to the
69     * AF_INET6 family with the AI_V4MAPPED flag. Alter your Makefile to use the
70     * NOV4MAP define and it should work like a breeze. All of the *BSDs fall
71     * into this category even though AI_V4MAPPED exists in netdb.h (true for
72     * all modern OS's). This should work with all Linux versions too, but the
73     * original code for AF_INET6 was left for Linux because it works.
74     *
75     * d. stoddard - 4/19/2018
76     */
77
78 #if defined(__linux__) && !defined(NOV4MAP)
79 #if defined (AI_V4MAPPED)
80     hints.ai_family = AF_INET6;         /* Allow IPv4 and IPv6 */
81     hints.ai_flags  = AI_PASSIVE | AI_ADDRCONFIG | AI_V4MAPPED;
82 #else
83     /* handle as normal IPv4 and IPv6 multi request */
84     hints.ai_family = AF_UNSPEC;        /* Allow IPv4 or IPv6 */
85     hints.ai_flags  = AI_PASSIVE | AI_ADDRCONFIG;
86 #endif /* AI_V4MAPPED */
87 #else
88     /* FreeBSD, OpenBSD, NetBSD, and others */
89     hints.ai_family = AF_UNSPEC;        /* Allow IPv4 or IPv6 */
90     hints.ai_flags  = AI_PASSIVE | AI_ADDRCONFIG;
91 #endif
92
93     hints.ai_protocol = _proto;
94     if (_proto == IPPROTO_UDP) {
95         hints.ai_socktype = SOCK_DGRAM;
96     } else if (_proto == IPPROTO_TCP) {
97         hints.ai_socktype = SOCK_STREAM;
98     } else {
99         ni->status = -1;
100         ni->retval = OS_INVALID;
101         return(ni);
102     }
103
104     /* get linked list of adresses */
105     s = getaddrinfo(_ip, _port, &hints, &result);
106
107     /* Try to support legacy ipv4 only hosts */
108     if((s == EAI_FAMILY) || (s == EAI_NONAME)) {
109         hints.ai_family = AF_INET;
110         hints.ai_flags  = AI_PASSIVE | AI_ADDRCONFIG;
111         s = getaddrinfo(_ip, _port, &hints, &result);
112     }
113
114     if (s != 0) {
115         verbose("getaddrinfo: %s", gai_strerror(s));
116         ni->status = -1;
117         ni->retval = OS_INVALID;
118         return(ni);
119     }
120
121     /* log the list of connections available */
122     OS_DecodeAddrinfo (result);
123
124    /*
125     * getaddrinfo() returns a list of address structures.  We try each
126     * address and attempt to connect to it.  If a socket(2) or bind(2) fails,
127     * we close the socket and try the next address. We repeat this for every
128     * address getaddrinfo() returns in the addrinfo linked list.
129     */
130
131     for (rp = result; rp != NULL; rp = rp->ai_next) {
132         ossock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
133         if (ossock == -1) {
134             verbose ("socket error: family %s type %s protocol %s: %s",
135                      DecodeFamily (rp->ai_family),
136                      DecodeSocktype (rp->ai_socktype),
137                      DecodeProtocol (rp->ai_protocol),
138                      strerror(errno));
139             continue;
140         }
141
142         if (_proto == IPPROTO_TCP) {
143             int flag = 1;
144             if (setsockopt(ossock, SOL_SOCKET, SO_REUSEADDR,
145                           (char *)&flag, sizeof(flag)) < 0) {
146                 verbose ("setsockopt error: SO_REUSEADDR %d: %s",
147                          errno, strerror(errno));
148                 if(ossock > 0) {
149                     OS_CloseSocket(ossock);
150                 }
151                 continue;
152             }
153         }
154
155         if (bind(ossock, rp->ai_addr, rp->ai_addrlen) == -1) {
156            /*
157             * Don't issue an error message if the address and port is already
158             * bound.  This can happen when 0.0.0.0 or :: are bound in a
159             * previous iteration of this loop.
160             */
161             if (errno == EADDRINUSE) {
162                 close (ossock);
163                 continue;
164             }
165
166             /* tell them why this address failed */
167             verbose ("Bind failed on socket for %s: %s",
168                      OS_DecodeSockaddr (rp->ai_addr), strerror (errno));
169             close (ossock);
170             continue;
171         }
172
173         if (_proto == IPPROTO_TCP) {
174             if (listen(ossock, 32) < 0) {
175                 verbose ("Request to listen() failed on socket for %s: %s",
176                           OS_DecodeSockaddr (rp->ai_addr), strerror (errno));
177                 close (ossock);
178                 continue;
179             }
180             verbose ("Request for TCP listen() succeeded.");
181         }
182
183         /* success - accumulate data for select call */
184         verbose ("Socket bound for %s", OS_DecodeSockaddr (rp->ai_addr));
185
186         /* save bound socket info for select() */
187         ni->fds[ni->fdcnt++] = ossock;  /* increment after use! */
188         FD_SET (ossock, &(ni->fdset));
189         if (ossock > ni->fdmax) {
190           ni->fdmax = ossock;
191         }
192     }
193
194     /* check to see if at least one address succeeded */
195     if (ni->fdcnt == 0) {
196         verbose ("Request to allocate and bind sockets failed.");
197         ni->status = -1;
198         ni->retval = OS_SOCKTERR;
199         if(result) {
200             freeaddrinfo(result);
201         }
202         return(ni);
203     }
204
205     freeaddrinfo(result);               /* No longer needed */
206     ni->fdmax += 1;                     /* prep for use with select() */
207     return (ni);
208 }
209
210
211 /* Bind a TCP port, using the OS_Bindport */
212 OSNetInfo *OS_Bindporttcp(char *_port, const char *_ip)
213 {
214     return (OS_Bindport(_port, IPPROTO_TCP, _ip));
215 }
216
217 /* Bind a UDP port, using the OS_Bindport */
218 OSNetInfo *OS_Bindportudp(char *_port, const char *_ip)
219 {
220     return (OS_Bindport(_port, IPPROTO_UDP, _ip));
221 }
222
223 #ifndef WIN32
224 /* Bind to a Unix domain, using DGRAM sockets */
225 int OS_BindUnixDomain(const char *path, mode_t mode, int max_msg_size)
226 {
227     int len;
228     int ossock = 0;
229     socklen_t optlen = sizeof(len);
230
231     /* Make sure the path isn't there */
232     unlink(path);
233
234     memset(&n_us, 0, sizeof(n_us));
235     n_us.sun_family = AF_UNIX;
236     strncpy(n_us.sun_path, path, sizeof(n_us.sun_path) - 1);
237
238     if ((ossock = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
239         return (OS_SOCKTERR);
240     }
241
242     if (bind(ossock, (struct sockaddr *)&n_us, SUN_LEN(&n_us)) < 0) {
243         OS_CloseSocket(ossock);
244         return (OS_SOCKTERR);
245     }
246
247     /* Change permissions */
248     if (chmod(path, mode) < 0) {
249         OS_CloseSocket(ossock);
250         return (OS_SOCKTERR);
251     }
252
253     /* Get current maximum size */
254     if (getsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1) {
255         OS_CloseSocket(ossock);
256         return (OS_SOCKTERR);
257     }
258
259     /* Set socket opt */
260     if (len < max_msg_size) {
261         len = max_msg_size;
262         if (setsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, optlen) < 0) {
263             OS_CloseSocket(ossock);
264             return (OS_SOCKTERR);
265         }
266     }
267
268     return (ossock);
269 }
270
271 /* Open a client Unix domain socket
272  * ("/tmp/lala-socket",0666));
273  */
274 int OS_ConnectUnixDomain(const char *path, int max_msg_size)
275 {
276     int len;
277     int ossock = 0;
278     socklen_t optlen = sizeof(len);
279
280     memset(&n_us, 0, sizeof(n_us));
281
282     n_us.sun_family = AF_UNIX;
283
284     /* Set up path */
285     strncpy(n_us.sun_path, path, sizeof(n_us.sun_path) - 1);
286
287     if ((ossock = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
288         return (OS_SOCKTERR);
289     }
290
291     /* Connect to the UNIX domain */
292     if (connect(ossock, (struct sockaddr *)&n_us, SUN_LEN(&n_us)) < 0) {
293         OS_CloseSocket(ossock);
294         return (OS_SOCKTERR);
295     }
296
297     /* Get current maximum size */
298     if (getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1) {
299         OS_CloseSocket(ossock);
300         return (OS_SOCKTERR);
301     }
302
303     /* Set maximum message size */
304     if (len < max_msg_size) {
305         len = max_msg_size;
306         if (setsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, optlen) < 0) {
307             OS_CloseSocket(ossock);
308             return (OS_SOCKTERR);
309         }
310     }
311
312     return (ossock);
313 }
314
315 int OS_getsocketsize(int ossock)
316 {
317     int len = 0;
318     socklen_t optlen = sizeof(len);
319
320     /* Get current maximum size */
321     if (getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1) {
322         OS_CloseSocket(ossock);
323         return(OS_SOCKTERR);
324     }
325
326     return (len);
327 }
328
329 #endif
330
331 /* Open a TCP/UDP client socket */
332 int OS_Connect(char *_port, unsigned int protocol, const char *_ip)
333 {
334     int ossock = 0, s;
335     struct addrinfo hints, *result, *rp, *local_ai = NULL;
336     char tempaddr[INET6_ADDRSTRLEN];
337
338     if ((_ip == NULL)||(_ip[0] == '\0')) {
339         OS_CloseSocket(ossock);
340         return(OS_INVALID);
341     }
342
343     if (agt) {
344         if (agt->lip) {
345             memset(&hints, 0, sizeof(struct addrinfo));
346             hints.ai_flags = AI_NUMERICHOST;
347             s = getaddrinfo(agt->lip, NULL, &hints, &result);
348             if (s != 0) {
349                 verbose("getaddrinfo: %s", gai_strerror(s));
350             }
351             else {
352                 local_ai = result;
353             }
354         }
355     }
356
357     memset(&hints, 0, sizeof(struct addrinfo));
358     /* Allow IPv4 or IPv6 if local_ip isn't specified */
359     hints.ai_family = AF_UNSPEC;
360     if (agt) {
361         if (agt->lip) {
362             hints.ai_family = local_ai->ai_family;
363         }
364     }
365     hints.ai_protocol = protocol;
366     if (protocol == IPPROTO_TCP) {
367         hints.ai_socktype = SOCK_STREAM;
368     } else if (protocol == IPPROTO_UDP) {
369         hints.ai_socktype = SOCK_DGRAM;
370     } else {
371         return(OS_INVALID);
372     }
373     hints.ai_flags = 0;
374
375     s = getaddrinfo(_ip, _port, &hints, &result);
376     if (s != 0) {
377         verbose("getaddrinfo: %s", gai_strerror(s));
378         if(result) {
379             freeaddrinfo(result);
380         }
381         return(OS_INVALID);
382     }
383
384            /* getaddrinfo() returns a list of address structures.
385               Try each address until we successfully connect(2).
386               If socket(2) (or connect(2)) fails, we (close the socket
387               and) try the next address. */
388
389     for (rp = result; rp != NULL; rp = rp->ai_next) {
390         ossock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
391         if (ossock == -1) {
392             continue;
393         }
394
395         if (agt) {
396             if (agt->lip) {
397                 if (bind(ossock, local_ai->ai_addr, local_ai->ai_addrlen)) {
398                     verbose("Unable to bind to local address %s.  Ignoring. (%s)",
399                             agt->lip, strerror(errno));
400                 }
401                 else verbose("Connecting from local address %s", agt->lip);
402             }
403         }
404
405         if (connect(ossock, rp->ai_addr, rp->ai_addrlen) != -1) {
406             break;                  /* Success */
407         }
408     }
409     if (rp == NULL) {               /* No address succeeded */
410         if (ossock > 0) {
411             OS_CloseSocket(ossock);
412         }
413         if(result) {
414             freeaddrinfo(result);
415         }
416         return(OS_SOCKTERR);
417     }
418     satop(rp->ai_addr, tempaddr, sizeof tempaddr);
419     verbose("INFO: Connected to %s at address %s, port %s", _ip,
420             tempaddr, _port);
421
422     freeaddrinfo(result);           /* No longer needed */
423
424     #ifdef HPUX
425     {
426     int flags;
427     flags = fcntl(ossock,F_GETFL,0);
428     fcntl(ossock, F_SETFL, flags | O_NONBLOCK);
429     }
430     #endif
431
432     return(ossock);
433 }
434
435
436 /* Open a TCP socket */
437 int OS_ConnectTCP(char *_port, const char *_ip)
438 {
439     return (OS_Connect(_port, IPPROTO_TCP, _ip));
440 }
441
442 /* Open a UDP socket */
443 int OS_ConnectUDP(char *_port, const char *_ip)
444 {
445     return (OS_Connect(_port, IPPROTO_UDP, _ip));
446 }
447
448 /* Send a TCP packet (through an open socket) */
449 int OS_SendTCP(int socket, const char *msg)
450 {
451     if ((send(socket, msg, strlen(msg), 0)) <= 0) {
452         return (OS_SOCKTERR);
453     }
454
455     return (0);
456 }
457
458 /* Send a TCP packet of a specific size (through a open socket) */
459 int OS_SendTCPbySize(int socket, int size, const char *msg)
460 {
461     if ((send(socket, msg, size, 0)) < size) {
462         return (OS_SOCKTERR);
463     }
464
465     return (0);
466 }
467
468 /* Send a UDP packet of a specific size (through an open socket) */
469 int OS_SendUDPbySize(int socket, int size, const char *msg)
470 {
471     unsigned int i = 0;
472
473     /* Maximum attempts is 5 */
474     while ((send(socket, msg, size, 0)) < 0) {
475         if ((errno != ENOBUFS) || (i >= 5)) {
476             return (OS_SOCKTERR);
477         }
478
479         i++;
480         merror("%s: INFO: Remote socket busy, waiting %d s.", __local_name, i);
481         sleep(i);
482     }
483
484     return (0);
485 }
486
487 /* Accept a TCP connection */
488 int OS_AcceptTCP(int socket, char *srcip, size_t addrsize)
489 {
490     int clientsocket;
491     struct sockaddr_storage _nc;
492     socklen_t _ncl;
493
494     memset(&_nc, 0, sizeof(_nc));
495     _ncl = sizeof(_nc);
496
497     if ((clientsocket = accept(socket, (struct sockaddr *) &_nc,
498                                &_ncl)) < 0) {
499         return (-1);
500     }
501
502     satop((struct sockaddr *) &_nc, srcip, addrsize -1);
503     srcip[addrsize -1] = '\0';
504
505     return (clientsocket);
506 }
507
508 /* Receive a TCP packet (from an open socket) */
509 char *OS_RecvTCP(int socket, int sizet)
510 {
511     char *ret;
512
513     ret = (char *) calloc((sizet), sizeof(char));
514     if (ret == NULL) {
515         return (NULL);
516     }
517
518     if (recv(socket, ret, sizet - 1, 0) <= 0) {
519         free(ret);
520         return (NULL);
521     }
522
523     return (ret);
524 }
525
526 /* Receive a TCP packet (from an open socket) */
527 int OS_RecvTCPBuffer(int socket, char *buffer, int sizet)
528 {
529     int retsize;
530
531     if ((retsize = recv(socket, buffer, sizet - 1, 0)) > 0) {
532         buffer[retsize] = '\0';
533         return (retsize);
534     }
535     return (-1);
536 }
537
538 /* Receive a UDP packet */
539 char *OS_RecvUDP(int socket, int sizet)
540 {
541     char *ret;
542
543     ret = (char *) calloc((sizet), sizeof(char));
544     if (ret == NULL) {
545         return (NULL);
546     }
547
548     if ((recv(socket, ret, sizet - 1, 0)) < 0) {
549         free(ret);
550         return (NULL);
551     }
552
553     return (ret);
554 }
555
556 /* Receives a message from a connected UDP socket */
557 int OS_RecvConnUDP(int socket, char *buffer, int buffer_size)
558 {
559     int recv_b;
560
561     recv_b = recv(socket, buffer, buffer_size, 0);
562     if (recv_b < 0) {
563         return (0);
564     }
565
566     buffer[recv_b] = '\0';
567
568     return (recv_b);
569 }
570
571 #ifndef WIN32
572 /* Receive a message from a Unix socket */
573 int OS_RecvUnix(int socket, int sizet, char *ret)
574 {
575     ssize_t recvd;
576     if ((recvd = recvfrom(socket, ret, sizet - 1, 0,
577                           (struct sockaddr *)&n_us, &us_l)) < 0) {
578         return (0);
579     }
580
581     ret[recvd] = '\0';
582     return ((int)recvd);
583 }
584
585 /* Send a message using a Unix socket
586  * Returns the OS_SOCKETERR if it fails
587  */
588 int OS_SendUnix(int socket, const char *msg, int size)
589 {
590     if (size == 0) {
591         size = strlen(msg) + 1;
592     }
593
594     if (send(socket, msg, size, 0) < size) {
595         if (errno == ENOBUFS) {
596             return (OS_SOCKBUSY);
597         }
598
599         return (OS_SOCKTERR);
600     }
601
602     return (OS_SUCCESS);
603 }
604 #endif
605
606 /* Calls getaddrinfo (tries x attempts) */
607 char *OS_GetHost(const char *host, unsigned int attempts)
608 {
609     unsigned int i = 0;
610     int error;
611
612     char *ip;
613     struct addrinfo *hai, *result;
614
615     if (host == NULL) {
616         return (NULL);
617     }
618
619     while (i <= attempts) {
620         if ((error = getaddrinfo(host, NULL, NULL, &result)) != 0) {
621             sleep(i++);
622             continue;
623         }
624
625         if ((ip = (char *) calloc(IPSIZE, sizeof(char))) == NULL) {
626             if (result) {
627                 freeaddrinfo(result);
628             }
629             return (NULL);
630         }
631
632         hai = result;
633         satop(hai->ai_addr, ip, IPSIZE);
634
635         freeaddrinfo(result);
636         return (ip);
637     }
638
639     return (NULL);
640 }
641
642 /* satop(struct sockaddr *sa, char *dst, socklen_t size)
643  * Convert a sockaddr to a printable address.
644  */
645 int satop(struct sockaddr *sa, char *dst, socklen_t size)
646 {
647     sa_family_t af;
648     struct sockaddr_in *sa4;
649     struct sockaddr_in6 *sa6;
650 #ifdef WIN32
651     int newlength;
652 #endif
653
654     af = sa->sa_family;
655
656     switch (af)
657     {
658     case AF_INET:
659         sa4 = (struct sockaddr_in *) sa;
660 #ifdef WIN32
661         newlength = size;
662         WSAAddressToString((LPSOCKADDR) sa4, sizeof(struct sockaddr_in),
663                            NULL, dst, (LPDWORD) &newlength);
664 #else
665         inet_ntop(af, (const void *) &(sa4->sin_addr), dst, size);
666 #endif
667         return(0);
668     case AF_INET6:
669         sa6 = (struct sockaddr_in6 *) sa;
670 #ifdef WIN32
671         newlength = size;
672         WSAAddressToString((LPSOCKADDR) sa6, sizeof(struct sockaddr_in6),
673                            NULL, dst, (LPDWORD) &newlength);
674 #else
675         inet_ntop(af, (const void *) &(sa6->sin6_addr), dst, size);
676 #endif
677         if (IN6_IS_ADDR_V4MAPPED(&(sa6->sin6_addr)))
678         {  /* extract the embedded IPv4 address */
679             memmove(dst, dst+7, size-7);
680         }
681         return(0);
682     default:
683         *dst = '\0';
684         return(-1);
685     }
686 }
687
688 int OS_CloseSocket(int socket)
689 {
690 #ifdef WIN32
691     return (closesocket(socket));
692 #else
693     return (close(socket));
694 #endif /* WIN32 */
695 }
696
697
698 /*
699  * OS_DecodeAddrinfo() will decode the contents of an addrinfo structure and
700  * log the IP version, address, and port number for each item in the
701  * linked list of addrinfo structs.
702  */
703
704 int OS_DecodeAddrinfo (struct addrinfo *res) {
705     struct addrinfo *p;                 /* pointer to addrinfo structs */
706
707     for (p = res; p != NULL; p = p->ai_next)
708         verbose ("%s",OS_DecodeSockaddr (p->ai_addr));
709     return 0;
710 }
711
712
713 /*
714  * OS_DecodeSockaddr() will decode a socket address and return a string with
715  * the IP version, address, and port number.
716  */
717
718 char *OS_DecodeSockaddr (struct sockaddr *sa) {
719     int rc;                             /* return code */
720     char ipaddr[INET6_ADDRSTRLEN];      /* printed address */
721     char ipport[NI_MAXSERV];            /* printed port */
722     static char buf[256];               /* message buffer */
723
724 #if defined(__linux__) || defined (WIN32)
725     /* most Linux systems do not have sa_len in the sockaddr struct */
726     socklen_t slen = 0;
727     switch(sa->sa_family) {
728         case AF_INET:
729             slen = sizeof(struct sockaddr_in);
730             break;
731         case AF_INET6:
732             slen = sizeof(struct sockaddr_in6);
733             break;
734         default:
735             // XXX WTF
736             break;
737     }
738     rc = getnameinfo ((struct sockaddr *) sa, slen, ipaddr,
739                       sizeof (ipaddr), ipport, sizeof (ipport),
740                       NI_NUMERICHOST | NI_NUMERICSERV);
741 #else
742     /* BSD systems require the value in sa->sa_len or error 4 occurs */
743     rc = getnameinfo ((struct sockaddr *) sa, sa->sa_len, ipaddr,
744                       sizeof (ipaddr), ipport, sizeof (ipport),
745                       NI_NUMERICHOST | NI_NUMERICSERV);
746 #endif
747
748     if (rc) {
749         sprintf (buf, "Error %d on getnameinfo: %s", rc, gai_strerror (rc));
750         return (buf);
751     }
752
753     sprintf (buf, "%s: %s on port %s",
754              DecodeFamily (sa->sa_family), ipaddr, ipport);
755     return buf;
756 }
757
758
759 /*
760  * DecodeFamily() is used to convert the IP family into a string for info
761  * and debugging purposes.
762  */
763
764 char *DecodeFamily (int val) {
765     static char buf[32];                /* response */
766
767     switch (val) {
768         case AF_INET:
769             strcpy (buf,"IPv4");
770             break;
771         case AF_INET6:
772             strcpy (buf,"IPv6");
773             break;
774         default:
775             sprintf (buf, "Unknown Family %d", val);
776             break;
777     }
778
779     return (buf);
780 }
781
782
783 /*
784  * DecodeSocktype() is used to convert the IP socket type into a string for
785  * info and debugging purposes.
786  */
787
788 char *DecodeSocktype (int val) {
789     static char buf[32];                /* response */
790
791     switch (val) {
792         case SOCK_STREAM:
793             strcpy (buf,"STREAM");
794             break;
795         case SOCK_DGRAM:
796             strcpy (buf,"DGRAM");
797             break;
798         case SOCK_RAW:
799             strcpy (buf,"RAW");
800             break;
801         default:
802             sprintf (buf, "Unknown Sock Type %d", val);
803             break;
804     }
805
806     return (buf);
807 }
808
809
810 /*
811  * DecodeProtocol() is used to convert the IP protocol into a string for info
812  * and debugging purposes.
813  */
814
815 char *DecodeProtocol (int val) {
816     static char buf[32];                /* response */
817
818     switch (val) {
819         case IPPROTO_IP:
820             strcpy (buf,"IP");
821             break;
822         case IPPROTO_ICMP:
823             strcpy (buf,"ICMP");
824             break;
825         case IPPROTO_TCP:
826             strcpy (buf,"TCP");
827             break;
828         case IPPROTO_UDP:
829             strcpy (buf,"UDP");
830             break;
831         default:
832             sprintf (buf, "Unknown Protocol %d", val);
833             break;
834     }
835
836     return (buf);
837 }
838