Address code analysis issues
[ric-plt/lib/rmr.git] / src / rmr / si / src / si95 / siaddress.c
1 // vim: noet sw=4 ts=4:
2 /*
3 ==================================================================================
4     Copyright (c) 2020 Nokia
5     Copyright (c) 2020 AT&T Intellectual Property.
6
7    Licensed under the Apache License, Version 2.0 (the "License");
8    you may not use this file except in compliance with the License.
9    You may obtain a copy of the License at
10
11        http://www.apache.org/licenses/LICENSE-2.0
12
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18 ==================================================================================
19 */
20
21 /*
22 **************************************************************************
23 *
24 *  Mnemonic: SIaddress
25 *  Abstract: This routine will convert a sockaddr_in structure to a
26 *            dotted decimal address, or visa versa.
27 *            If type == AC_TOADDR the src string may be: 
28 *            xxx.xxx.xxx.xxx.portnumber or host-name.portnumber
29 *            xxx.xxx.xxx.xxx.service[.protocol] or hostname;service[;protocol]
30 *            if protocol is not supplied then tcp is assumed.
31 *            hostname may be something like godzilla.moviemania.com
32 *  Parms:    src - Pointer to source buffer
33 *            dest- Pointer to dest buffer pointer 
34 *            type- Type of conversion AC_TODOT converts sockaddr to human readable. AC_TOADDR 
35 *                               converts character buffer to sockaddr.
36 *  Returns:  Nothing.
37 *  Date:     19 January 1995
38 *  Author:   E. Scott Daniels
39 *
40 *  Modified: 22 Mar 1995 - To add support for ipx addresses.
41 *                       18 Oct 2020 - drop old port separator (;)
42 *
43 *  CAUTION: The netdb.h header file is a bit off when it sets up the 
44 *           hostent structure. It claims that h_addr_list is a pointer 
45 *           to character pointers, but it is really a pointer to a list 
46 *           of pointers to integers!!!
47 *       
48 ***************************************************************************
49 */
50 #include "sisetup.h"      //  get necessary defs and other stuff 
51 #include <netdb.h>
52 #include <stdio.h>
53 #include <ctype.h>
54
55 /* 
56         target: buffer with address  e.g.  192.168.0.1:4444  :4444 (listen) [::1]4444
57         family: PF_INET[6]  (let it be 0 to select based on addr in buffer 
58         proto: IPPROTO_TCP IPPROTO_UDP
59         type:   SOCK_STREAM SOCK_DGRAM
60
61         returns length of struct pointed to by rap (return addr blockpointer)
62 */
63 extern int SIgenaddr( char *target, int proto, int family, int socktype, struct sockaddr **rap ) {
64         struct addrinfo hint;                           //  hints to give getaddrinfo 
65         struct addrinfo *list = NULL;           //  list of what comes back 
66         int     ga_flags = 0;                                   //  flags to pass to getaddrinfo in hints 
67         int     error = 0;
68         int     rlen = 0;                                               //  length of the addr that rap points to on return 
69         char    *pstr;                                          //  port string 
70         char    *dstr;                                          //  a copy of the users target that we can destroy 
71         char*   fptr;                                           // ptr we allocated and need to free (we may adjust dstr)
72
73     fptr = dstr = strdup( (char *) target );    //  copy so we can destroy it with strtok 
74         *rap = NULL;                                            //  ensure null incase something breaks 
75
76         while( isspace( *dstr ) ) {
77                 dstr++;
78         }
79
80         if( *dstr == ':' ) {            //  user passed in :port -- so we assume this is for bind 
81                 pstr = dstr;
82                 *(pstr++) = 0;
83
84                 ga_flags = AI_PASSIVE;
85         } else {
86                 if( *dstr == '[' ) {                            // strip [ and ] from v6 and point pstring if port there
87                         dstr++;
88                         pstr = strchr( dstr, ']' );
89                         if( *pstr != ']' ) {
90                                 free( fptr );
91                                 return -1;
92                         }
93
94                         *(pstr++) = 0;
95                         if( *pstr == ':' ) {
96                                 *(pstr++) = 0;
97                         } else {
98                                 pstr = NULL;
99                         }
100                 } else {                                                        // assume name or v4; point at port if there
101                         pstr = strchr( dstr, ':' );
102                         if( pstr != NULL ) {
103                                 *(pstr++) = 0;
104                         }
105                 }
106                 ga_flags = AI_ADDRCONFIG;                       // don't return IPVx addresses unless one such address is configured
107         }
108
109         memset( &hint, 0, sizeof( hint  ) );
110         hint.ai_family = family;                        //  AF_INET AF_INET6...  let this be 0 to select best based on addr 
111         hint.ai_socktype = socktype;            //  SOCK_DGRAM SOCK_STREAM 
112         hint.ai_protocol = proto;                       //  IPPORTO_TCP IPPROTO_UDP 
113         hint.ai_flags = ga_flags;
114
115         if( DEBUG ) 
116                 rmr_vlog( RMR_VL_DEBUG, "siaddress: calling getaddrinfo flags=%x proto=%d family=%d target=%s host=%s port=%s\n", 
117                                 ga_flags, proto, family, target, dstr, pstr );
118
119         if( (error = getaddrinfo( dstr, pstr, &hint, &list )) ) {
120                 fprintf( stderr, "error from getaddrinfo: target=%s host=%s port=%s(port): error=(%d) %s\n", target, dstr, pstr, error, gai_strerror( error ) );
121         } else {
122                 *rap = (struct sockaddr *) malloc(  list->ai_addrlen );         //  alloc a buffer and give address to caller 
123                 memcpy( *rap, list->ai_addr, list->ai_addrlen  );
124
125                 rlen = list->ai_addrlen;
126                 
127                 freeaddrinfo( list );           //  ditch system allocated memory 
128         }
129
130         free( fptr );
131         return rlen;
132 }
133
134
135 /* 
136         Given a source address convert from one form to another based on type constant.
137         Type const == AC_TODOT   Convert source address structure to human readable string.
138         Type const == AC_TOADDR6 Convert source string (host:port or ipv6 address [n:n...:n]:port) to an address struct
139         Type const == AC_TOADDR  Convert source string (host:port or ipv4 dotted decimal address) to an address struct
140 */
141 extern int SIaddress( void *src, void **dest, int type ) {
142         struct sockaddr_in *addr;       //  pointer to the address 
143         struct sockaddr_in6 *addr6;             // ip6 has a different layout
144         unsigned char *num;             //  pointer at the address number 
145         uint8_t*        byte;                           //  pointer at the ipv6 address byte values
146         char wbuf[256];                 //  work buffer 
147         int i;         
148         int     rlen = 0;                                       //  return len - len of address struct or string
149
150         switch( type ) {
151                 case AC_TODOT:                                  //  convert from a struct to human readable "dotted decimal"
152                         addr = (struct sockaddr_in *) src;
153
154                         if( addr->sin_family == AF_INET6 ) {
155                                 addr6 = (struct sockaddr_in6 *) src;                            // really an ip6 struct
156                                 byte = (uint8_t *) &addr6->sin6_addr;
157                         sprintf( wbuf, "[%u:%u:%u:%u:%u:%u]:%d", 
158                                                 *(byte+0), *(byte+1), *(byte+2), 
159                                                 *(byte+3), *(byte+4), *(byte+5) , 
160                                                 (int) ntohs( addr6->sin6_port ) );
161                         } else {
162                                 num = (char *) &addr->sin_addr.s_addr;    //  point at the long 
163                                 sprintf( wbuf, "%u.%u.%u.%u;%d", *(num+0), *(num+1), *(num+2), *(num+3), (int) ntohs(addr->sin_port) );
164                         }
165
166                         *dest = (void *) strdup( wbuf );
167                         rlen = strlen( *dest );
168                         break;
169
170                 case AC_TOADDR6:                        //  from hostname;port string to address for send etc 
171                         return SIgenaddr( src, PF_INET6, IPPROTO_TCP, SOCK_STREAM, (struct sockaddr **) dest );
172
173                 case AC_TOADDR:                         //  from dotted decimal to address struct ip4 
174                         return SIgenaddr( src, PF_INET, IPPROTO_TCP, SOCK_STREAM, (struct sockaddr **) dest );
175         }
176
177         return rlen;
178 }
179