1 /*
2 Copyright 2021 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25
26 #include <platform.h>
27 #include <communication.h>
28
29 #include <connection_info.h>
30 #include <stat_cache.h> /* Stat */
31 #include <alloc.h> /* xmalloc,... */
32 #include <logging.h> /* Log */
33 #include <misc_lib.h> /* ProgrammingError */
34 #include <buffer.h> /* Buffer */
35 #include <ip_address.h> /* IPAddress */
36
37
NewAgentConn(const char * server,const char * port,ConnectionFlags flags)38 AgentConnection *NewAgentConn(const char *server, const char *port,
39 ConnectionFlags flags)
40 {
41 AgentConnection *conn = xcalloc(1, sizeof(AgentConnection));
42 conn->conn_info = ConnectionInfoNew();
43 conn->this_server = xstrdup(server);
44 conn->this_port = (port == NULL) ? NULL : xstrdup(port);
45 conn->flags = flags;
46 conn->encryption_type = 'c';
47 conn->authenticated = false;
48 return conn;
49 }
50
DeleteAgentConn(AgentConnection * conn)51 void DeleteAgentConn(AgentConnection *conn)
52 {
53 Stat *sp = conn->cache;
54
55 while (sp != NULL)
56 {
57 Stat *previous = sp;
58 sp = sp->next;
59 DestroyStatCache(previous);
60 }
61
62 ConnectionInfoDestroy(&conn->conn_info);
63 free(conn->this_server);
64 free(conn->this_port);
65 free(conn->session_key);
66 *conn = (AgentConnection) {0};
67 free(conn);
68 }
69
IsIPV6Address(char * name)70 bool IsIPV6Address(char *name)
71 {
72 if (!name)
73 {
74 return false;
75 }
76 Buffer *buffer = BufferNewFrom(name, strlen(name));
77 if (!buffer)
78 {
79 return false;
80 }
81 IPAddress *ip_address = NULL;
82 bool is_ip = false;
83 is_ip = IPAddressIsIPAddress(buffer, &ip_address);
84 if (!is_ip)
85 {
86 BufferDestroy(buffer);
87 return false;
88 }
89 if (IPAddressType(ip_address) != IP_ADDRESS_TYPE_IPV6)
90 {
91 BufferDestroy(buffer);
92 IPAddressDestroy(&ip_address);
93 return false;
94 }
95 BufferDestroy(buffer);
96 IPAddressDestroy(&ip_address);
97 return true;
98 }
99
100 /*******************************************************************/
101
IsIPV4Address(char * name)102 bool IsIPV4Address(char *name)
103 {
104 if (!name)
105 {
106 return false;
107 }
108 Buffer *buffer = BufferNewFrom(name, strlen(name));
109 if (!buffer)
110 {
111 return false;
112 }
113 IPAddress *ip_address = NULL;
114 bool is_ip = false;
115 is_ip = IPAddressIsIPAddress(buffer, &ip_address);
116 if (!is_ip)
117 {
118 BufferDestroy(buffer);
119 return false;
120 }
121 if (IPAddressType(ip_address) != IP_ADDRESS_TYPE_IPV4)
122 {
123 BufferDestroy(buffer);
124 IPAddressDestroy(&ip_address);
125 return false;
126 }
127 BufferDestroy(buffer);
128 IPAddressDestroy(&ip_address);
129 return true;
130 }
131
132 /*****************************************************************************/
133
134 /**
135 * @brief DNS lookup of hostname, store the address as string into dst of size
136 * dst_size.
137 * @return -1 in case of unresolvable hostname or other error.
138 */
Hostname2IPString(char * dst,const char * hostname,size_t dst_size)139 int Hostname2IPString(char *dst, const char *hostname, size_t dst_size)
140 {
141 int ret;
142 struct addrinfo *response = NULL, *ap;
143 struct addrinfo query = {
144 .ai_family = AF_UNSPEC,
145 .ai_socktype = SOCK_STREAM
146 };
147
148 if (dst_size < CF_MAX_IP_LEN)
149 {
150 ProgrammingError("Hostname2IPString got %zu, needs at least"
151 " %d length buffer for IPv6 portability!",
152 dst_size, CF_MAX_IP_LEN);
153 }
154
155 ret = getaddrinfo(hostname, NULL, &query, &response);
156 if (ret != 0)
157 {
158 Log(LOG_LEVEL_INFO,
159 "Unable to lookup hostname '%s' or cfengine service. (getaddrinfo: %s)",
160 hostname, gai_strerror(ret));
161 if (response != NULL)
162 {
163 freeaddrinfo(response);
164 }
165 return -1;
166 }
167
168 for (ap = response; ap != NULL; ap = ap->ai_next)
169 {
170 /* No lookup, just convert numeric IP to string. */
171 int ret2 = getnameinfo(ap->ai_addr, ap->ai_addrlen,
172 dst, dst_size, NULL, 0, NI_NUMERICHOST);
173 if (ret2 == 0)
174 {
175 freeaddrinfo(response);
176 return 0; /* Success */
177 }
178 }
179
180 assert(response != NULL); /* getaddrinfo() was successful */
181 freeaddrinfo(response);
182
183 Log(LOG_LEVEL_ERR,
184 "Hostname2IPString: ERROR even though getaddrinfo returned success!");
185 return -1;
186 }
187
188 /*****************************************************************************/
189
190 /**
191 * @brief Reverse DNS lookup of ipaddr, store the address as string into dst
192 * of size dst_size.
193 * @return -1 in case of unresolvable IP address or other error.
194 */
IPString2Hostname(char * dst,const char * ipaddr,size_t dst_size)195 int IPString2Hostname(char *dst, const char *ipaddr, size_t dst_size)
196 {
197 int ret;
198 struct addrinfo *response = NULL;
199
200 /* First convert ipaddr string to struct sockaddr, with no DNS query. */
201 struct addrinfo query = {
202 .ai_flags = AI_NUMERICHOST
203 };
204
205 ret = getaddrinfo(ipaddr, NULL, &query, &response);
206 if (ret != 0)
207 {
208 Log(LOG_LEVEL_ERR,
209 "Unable to convert IP address '%s'. (getaddrinfo: %s)",
210 ipaddr, gai_strerror(ret));
211 if (response != NULL)
212 {
213 freeaddrinfo(response);
214 }
215 return -1;
216 }
217
218 /* response should only have one reply, so no need to iterate over the
219 * response struct addrinfo. */
220
221 /* Reverse DNS lookup. NI_NAMEREQD forces an error if not resolvable. */
222 ret = getnameinfo(response->ai_addr, response->ai_addrlen,
223 dst, dst_size, NULL, 0, NI_NAMEREQD);
224 if (ret != 0)
225 {
226 Log(LOG_LEVEL_INFO,
227 "Couldn't reverse resolve '%s'. (getaddrinfo: %s)",
228 ipaddr, gai_strerror(ret));
229 freeaddrinfo(response);
230 return -1;
231 }
232
233 assert(response != NULL); /* getaddrinfo() was successful */
234 freeaddrinfo(response);
235 return 0; /* Success */
236 }
237
238 /*****************************************************************************/
239
SocketFamily(int sd)240 unsigned short SocketFamily(int sd)
241 {
242 struct sockaddr_storage ss = {0};
243 socklen_t len = sizeof(ss);
244
245 if (getsockname(sd, (struct sockaddr *) &ss, &len) == -1)
246 {
247 Log(LOG_LEVEL_ERR, "Could not get socket family. (getsockname: %s)", GetErrorStr());
248 }
249
250 return ss.ss_family;
251 }
252