1 /* Copyright (C) 2009 Trend Micro Inc.
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
11 * APIs for many network operations
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);
28 /* Unix socket -- not for windows */
30 static struct sockaddr_un n_us;
31 static socklen_t us_l = sizeof(n_us);
35 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
36 + strlen ((ptr)->sun_path))
48 /* Bind all relevant ports */
49 OSNetInfo *OS_Bindport(char *_port, unsigned int _proto, const char *_ip)
52 struct addrinfo hints, *result, *rp;
53 OSNetInfo *ni; /* return data */
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));
64 /* init hints for getaddrinfo() */
65 memset(&hints, 0, sizeof(struct addrinfo));
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.
75 * d. stoddard - 4/19/2018
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;
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 */
88 /* FreeBSD, OpenBSD, NetBSD, and others */
89 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
90 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
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;
100 ni->retval = OS_INVALID;
104 /* get linked list of adresses */
105 s = getaddrinfo(_ip, _port, &hints, &result);
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);
115 verbose("getaddrinfo: %s", gai_strerror(s));
117 ni->retval = OS_INVALID;
121 /* log the list of connections available */
122 OS_DecodeAddrinfo (result);
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.
131 for (rp = result; rp != NULL; rp = rp->ai_next) {
132 ossock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
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),
142 if (_proto == IPPROTO_TCP) {
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));
149 OS_CloseSocket(ossock);
155 if (bind(ossock, rp->ai_addr, rp->ai_addrlen) == -1) {
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.
161 if (errno == EADDRINUSE) {
166 /* tell them why this address failed */
167 verbose ("Bind failed on socket for %s: %s",
168 OS_DecodeSockaddr (rp->ai_addr), strerror (errno));
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));
180 verbose ("Request for TCP listen() succeeded.");
183 /* success - accumulate data for select call */
184 verbose ("Socket bound for %s", OS_DecodeSockaddr (rp->ai_addr));
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) {
194 /* check to see if at least one address succeeded */
195 if (ni->fdcnt == 0) {
196 verbose ("Request to allocate and bind sockets failed.");
198 ni->retval = OS_SOCKTERR;
200 freeaddrinfo(result);
205 freeaddrinfo(result); /* No longer needed */
206 ni->fdmax += 1; /* prep for use with select() */
211 /* Bind a TCP port, using the OS_Bindport */
212 OSNetInfo *OS_Bindporttcp(char *_port, const char *_ip)
214 return (OS_Bindport(_port, IPPROTO_TCP, _ip));
217 /* Bind a UDP port, using the OS_Bindport */
218 OSNetInfo *OS_Bindportudp(char *_port, const char *_ip)
220 return (OS_Bindport(_port, IPPROTO_UDP, _ip));
224 /* Bind to a Unix domain, using DGRAM sockets */
225 int OS_BindUnixDomain(const char *path, mode_t mode, int max_msg_size)
229 socklen_t optlen = sizeof(len);
231 /* Make sure the path isn't there */
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);
238 if ((ossock = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
239 return (OS_SOCKTERR);
242 if (bind(ossock, (struct sockaddr *)&n_us, SUN_LEN(&n_us)) < 0) {
243 OS_CloseSocket(ossock);
244 return (OS_SOCKTERR);
247 /* Change permissions */
248 if (chmod(path, mode) < 0) {
249 OS_CloseSocket(ossock);
250 return (OS_SOCKTERR);
253 /* Get current maximum size */
254 if (getsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1) {
255 OS_CloseSocket(ossock);
256 return (OS_SOCKTERR);
260 if (len < max_msg_size) {
262 if (setsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, optlen) < 0) {
263 OS_CloseSocket(ossock);
264 return (OS_SOCKTERR);
271 /* Open a client Unix domain socket
272 * ("/tmp/lala-socket",0666));
274 int OS_ConnectUnixDomain(const char *path, int max_msg_size)
278 socklen_t optlen = sizeof(len);
280 memset(&n_us, 0, sizeof(n_us));
282 n_us.sun_family = AF_UNIX;
285 strncpy(n_us.sun_path, path, sizeof(n_us.sun_path) - 1);
287 if ((ossock = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
288 return (OS_SOCKTERR);
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);
297 /* Get current maximum size */
298 if (getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1) {
299 OS_CloseSocket(ossock);
300 return (OS_SOCKTERR);
303 /* Set maximum message size */
304 if (len < max_msg_size) {
306 if (setsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, optlen) < 0) {
307 OS_CloseSocket(ossock);
308 return (OS_SOCKTERR);
315 int OS_getsocketsize(int ossock)
318 socklen_t optlen = sizeof(len);
320 /* Get current maximum size */
321 if (getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1) {
322 OS_CloseSocket(ossock);
331 /* Open a TCP/UDP client socket */
332 int OS_Connect(char *_port, unsigned int protocol, const char *_ip)
335 struct addrinfo hints, *result, *rp, *local_ai = NULL;
336 char tempaddr[INET6_ADDRSTRLEN];
338 if ((_ip == NULL)||(_ip[0] == '\0')) {
339 OS_CloseSocket(ossock);
345 memset(&hints, 0, sizeof(struct addrinfo));
346 hints.ai_flags = AI_NUMERICHOST;
347 s = getaddrinfo(agt->lip, NULL, &hints, &result);
349 verbose("getaddrinfo: %s", gai_strerror(s));
357 memset(&hints, 0, sizeof(struct addrinfo));
358 /* Allow IPv4 or IPv6 if local_ip isn't specified */
359 hints.ai_family = AF_UNSPEC;
362 hints.ai_family = local_ai->ai_family;
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;
375 s = getaddrinfo(_ip, _port, &hints, &result);
377 verbose("getaddrinfo: %s", gai_strerror(s));
379 freeaddrinfo(result);
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. */
389 for (rp = result; rp != NULL; rp = rp->ai_next) {
390 ossock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
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));
401 else verbose("Connecting from local address %s", agt->lip);
405 if (connect(ossock, rp->ai_addr, rp->ai_addrlen) != -1) {
409 if (rp == NULL) { /* No address succeeded */
411 OS_CloseSocket(ossock);
414 freeaddrinfo(result);
418 satop(rp->ai_addr, tempaddr, sizeof tempaddr);
419 verbose("INFO: Connected to %s at address %s, port %s", _ip,
422 freeaddrinfo(result); /* No longer needed */
427 flags = fcntl(ossock,F_GETFL,0);
428 fcntl(ossock, F_SETFL, flags | O_NONBLOCK);
436 /* Open a TCP socket */
437 int OS_ConnectTCP(char *_port, const char *_ip)
439 return (OS_Connect(_port, IPPROTO_TCP, _ip));
442 /* Open a UDP socket */
443 int OS_ConnectUDP(char *_port, const char *_ip)
445 return (OS_Connect(_port, IPPROTO_UDP, _ip));
448 /* Send a TCP packet (through an open socket) */
449 int OS_SendTCP(int socket, const char *msg)
451 if ((send(socket, msg, strlen(msg), 0)) <= 0) {
452 return (OS_SOCKTERR);
458 /* Send a TCP packet of a specific size (through a open socket) */
459 int OS_SendTCPbySize(int socket, int size, const char *msg)
461 if ((send(socket, msg, size, 0)) < size) {
462 return (OS_SOCKTERR);
468 /* Send a UDP packet of a specific size (through an open socket) */
469 int OS_SendUDPbySize(int socket, int size, const char *msg)
473 /* Maximum attempts is 5 */
474 while ((send(socket, msg, size, 0)) < 0) {
475 if ((errno != ENOBUFS) || (i >= 5)) {
476 return (OS_SOCKTERR);
480 merror("%s: INFO: Remote socket busy, waiting %d s.", __local_name, i);
487 /* Accept a TCP connection */
488 int OS_AcceptTCP(int socket, char *srcip, size_t addrsize)
491 struct sockaddr_storage _nc;
494 memset(&_nc, 0, sizeof(_nc));
497 if ((clientsocket = accept(socket, (struct sockaddr *) &_nc,
502 satop((struct sockaddr *) &_nc, srcip, addrsize -1);
503 srcip[addrsize -1] = '\0';
505 return (clientsocket);
508 /* Receive a TCP packet (from an open socket) */
509 char *OS_RecvTCP(int socket, int sizet)
513 ret = (char *) calloc((sizet), sizeof(char));
518 if (recv(socket, ret, sizet - 1, 0) <= 0) {
526 /* Receive a TCP packet (from an open socket) */
527 int OS_RecvTCPBuffer(int socket, char *buffer, int sizet)
531 if ((retsize = recv(socket, buffer, sizet - 1, 0)) > 0) {
532 buffer[retsize] = '\0';
538 /* Receive a UDP packet */
539 char *OS_RecvUDP(int socket, int sizet)
543 ret = (char *) calloc((sizet), sizeof(char));
548 if ((recv(socket, ret, sizet - 1, 0)) < 0) {
556 /* Receives a message from a connected UDP socket */
557 int OS_RecvConnUDP(int socket, char *buffer, int buffer_size)
561 recv_b = recv(socket, buffer, buffer_size, 0);
566 buffer[recv_b] = '\0';
572 /* Receive a message from a Unix socket */
573 int OS_RecvUnix(int socket, int sizet, char *ret)
576 if ((recvd = recvfrom(socket, ret, sizet - 1, 0,
577 (struct sockaddr *)&n_us, &us_l)) < 0) {
585 /* Send a message using a Unix socket
586 * Returns the OS_SOCKETERR if it fails
588 int OS_SendUnix(int socket, const char *msg, int size)
591 size = strlen(msg) + 1;
594 if (send(socket, msg, size, 0) < size) {
595 if (errno == ENOBUFS) {
596 return (OS_SOCKBUSY);
599 return (OS_SOCKTERR);
606 /* Calls getaddrinfo (tries x attempts) */
607 char *OS_GetHost(const char *host, unsigned int attempts)
613 struct addrinfo *hai, *result;
619 while (i <= attempts) {
620 if ((error = getaddrinfo(host, NULL, NULL, &result)) != 0) {
625 if ((ip = (char *) calloc(IPSIZE, sizeof(char))) == NULL) {
627 freeaddrinfo(result);
633 satop(hai->ai_addr, ip, IPSIZE);
635 freeaddrinfo(result);
642 /* satop(struct sockaddr *sa, char *dst, socklen_t size)
643 * Convert a sockaddr to a printable address.
645 int satop(struct sockaddr *sa, char *dst, socklen_t size)
648 struct sockaddr_in *sa4;
649 struct sockaddr_in6 *sa6;
659 sa4 = (struct sockaddr_in *) sa;
662 WSAAddressToString((LPSOCKADDR) sa4, sizeof(struct sockaddr_in),
663 NULL, dst, (LPDWORD) &newlength);
665 inet_ntop(af, (const void *) &(sa4->sin_addr), dst, size);
669 sa6 = (struct sockaddr_in6 *) sa;
672 WSAAddressToString((LPSOCKADDR) sa6, sizeof(struct sockaddr_in6),
673 NULL, dst, (LPDWORD) &newlength);
675 inet_ntop(af, (const void *) &(sa6->sin6_addr), dst, size);
677 if (IN6_IS_ADDR_V4MAPPED(&(sa6->sin6_addr)))
678 { /* extract the embedded IPv4 address */
679 memmove(dst, dst+7, size-7);
688 int OS_CloseSocket(int socket)
691 return (closesocket(socket));
693 return (close(socket));
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.
704 int OS_DecodeAddrinfo (struct addrinfo *res) {
705 struct addrinfo *p; /* pointer to addrinfo structs */
707 for (p = res; p != NULL; p = p->ai_next)
708 verbose ("%s",OS_DecodeSockaddr (p->ai_addr));
714 * OS_DecodeSockaddr() will decode a socket address and return a string with
715 * the IP version, address, and port number.
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 */
724 #if defined(__linux__) || defined (WIN32)
725 /* most Linux systems do not have sa_len in the sockaddr struct */
727 switch(sa->sa_family) {
729 slen = sizeof(struct sockaddr_in);
732 slen = sizeof(struct sockaddr_in6);
738 rc = getnameinfo ((struct sockaddr *) sa, slen, ipaddr,
739 sizeof (ipaddr), ipport, sizeof (ipport),
740 NI_NUMERICHOST | NI_NUMERICSERV);
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);
749 sprintf (buf, "Error %d on getnameinfo: %s", rc, gai_strerror (rc));
753 sprintf (buf, "%s: %s on port %s",
754 DecodeFamily (sa->sa_family), ipaddr, ipport);
760 * DecodeFamily() is used to convert the IP family into a string for info
761 * and debugging purposes.
764 char *DecodeFamily (int val) {
765 static char buf[32]; /* response */
775 sprintf (buf, "Unknown Family %d", val);
784 * DecodeSocktype() is used to convert the IP socket type into a string for
785 * info and debugging purposes.
788 char *DecodeSocktype (int val) {
789 static char buf[32]; /* response */
793 strcpy (buf,"STREAM");
796 strcpy (buf,"DGRAM");
802 sprintf (buf, "Unknown Sock Type %d", val);
811 * DecodeProtocol() is used to convert the IP protocol into a string for info
812 * and debugging purposes.
815 char *DecodeProtocol (int val) {
816 static char buf[32]; /* response */
832 sprintf (buf, "Unknown Protocol %d", val);