comparison lib/socket-connect.c @ 952:a490d94a5b8e

2008-03-28 Brian Masney <masneyb@gftp.org> * lib/Makefile.am lib/misc.c lib/socket-connect.c lib/socket-connect-getaddrinfo.c lib/socket-connect-gethostbyname.c lib/sockutils.c lib/gftp.h - cleaned up more of the socket functions and split them up into their own files. Cleanups and bug fixes to the DNS lookup code.
author masneyb
date Fri, 28 Mar 2008 11:44:36 +0000
parents c7d7a081cd9c
children
comparison
equal deleted inserted replaced
951:99f8858bbf02 952:a490d94a5b8e
18 /*****************************************************************************/ 18 /*****************************************************************************/
19 19
20 #include "gftp.h" 20 #include "gftp.h"
21 static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $"; 21 static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $";
22 22
23 /* FIXME - clean up this function */
24 static int 23 static int
25 gftp_need_proxy (gftp_request * request, char *service, char *proxy_hostname, 24 gftp_need_proxy (gftp_request * request, char *service, char *proxy_hostname,
26 unsigned int proxy_port) 25 unsigned int proxy_port, void **connect_data)
27 { 26 {
28 gftp_config_list_vars * proxy_hosts; 27 gftp_config_list_vars * proxy_hosts;
29 gftp_proxy_hosts * hostname; 28 gftp_proxy_hosts * hostname;
30 size_t hostlen, domlen; 29 size_t hostlen, domlen;
31 unsigned char addy[4]; 30 unsigned char addy[4];
32 struct sockaddr *addr;
33 GList * templist; 31 GList * templist;
34 gint32 netaddr; 32 gint32 netaddr;
35 char *pos; 33 char *pos;
36 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) 34
37 struct addrinfo hints, *hostp; 35 #if !defined (HAVE_GETADDRINFO) || !defined (HAVE_GAI_STRERROR)
38 unsigned int port; 36 struct hostent host;
39 int errnum; 37 int ret;
40 char serv[8];
41 #else
42 struct hostent host, *hostp;
43 #endif 38 #endif
44 39
45 gftp_lookup_global_option ("dont_use_proxy", &proxy_hosts); 40 gftp_lookup_global_option ("dont_use_proxy", &proxy_hosts);
46 41
47 if (proxy_hostname == NULL || *proxy_hostname == '\0') 42 if (proxy_hostname == NULL || *proxy_hostname == '\0')
48 return (0); 43 return (0);
49 else if (proxy_hosts->list == NULL) 44 else if (proxy_hosts->list == NULL)
50 return (proxy_hostname != NULL && 45 return (proxy_hostname != NULL &&
51 *proxy_hostname != '\0'); 46 *proxy_hostname != '\0');
52 47
53 hostp = NULL;
54 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) 48 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
55 memset (&hints, 0, sizeof (hints));
56 hints.ai_flags = AI_CANONNAME;
57 hints.ai_family = PF_UNSPEC;
58 hints.ai_socktype = SOCK_STREAM;
59 49
60 port = request->use_proxy ? proxy_port : request->port; 50 *connect_data = lookup_host_with_getaddrinfo (request, service,
61 if (port == 0) 51 proxy_hostname, proxy_port);
62 strcpy (serv, service); 52 if (*connect_data == NULL)
63 else 53 return (GFTP_ERETRYABLE);
64 snprintf (serv, sizeof (serv), "%d", port);
65
66 request->logging_function (gftp_logging_misc, request,
67 _("Looking up %s\n"), request->hostname);
68
69 if ((errnum = getaddrinfo (request->hostname, serv, &hints,
70 &hostp)) != 0)
71 {
72 request->logging_function (gftp_logging_error, request,
73 _("Cannot look up hostname %s: %s\n"),
74 request->hostname, gai_strerror (errnum));
75 return (GFTP_ERETRYABLE);
76 }
77
78 addr = hostp->ai_addr;
79 54
80 #else /* !HAVE_GETADDRINFO */ 55 #else /* !HAVE_GETADDRINFO */
81 request->logging_function (gftp_logging_misc, request,
82 _("Looking up %s\n"), request->hostname);
83 56
84 if (!(hostp = r_gethostbyname (request->hostname, &host, NULL))) 57 ret = lookup_host_with_gethostbyname (request, proxy_hostname, &host);
85 { 58 if (ret != 0)
86 request->logging_function (gftp_logging_error, request, 59 return (ret);
87 _("Cannot look up hostname %s: %s\n"),
88 request->hostname, g_strerror (errno));
89 return (GFTP_ERETRYABLE);
90 }
91 60
92 addr = (struct sockaddr *) host.h_addr_list[0]; 61 connect_data = NULL; /* FIXME */
93 62
94 #endif /* HAVE_GETADDRINFO */ 63 #endif
95 64
96 templist = proxy_hosts->list; 65 templist = proxy_hosts->list;
97 while (templist != NULL) 66 while (templist != NULL)
98 { 67 {
99 hostname = templist->data; 68 hostname = templist->data;
109 } 78 }
110 } 79 }
111 80
112 if (hostname->ipv4_network_address != 0) 81 if (hostname->ipv4_network_address != 0)
113 { 82 {
114 memcpy (addy, addr, sizeof (*addy)); 83 memcpy (addy, request->remote_addr, sizeof (*addy));
115 netaddr = 84 netaddr =
116 (((addy[0] & 0xff) << 24) | ((addy[1] & 0xff) << 16) | 85 (((addy[0] & 0xff) << 24) | ((addy[1] & 0xff) << 16) |
117 ((addy[2] & 0xff) << 8) | (addy[3] & 0xff)) & 86 ((addy[2] & 0xff) << 8) | (addy[3] & 0xff)) &
118 hostname->ipv4_netmask; 87 hostname->ipv4_netmask;
119 if (netaddr == hostname->ipv4_network_address) 88 if (netaddr == hostname->ipv4_network_address)
124 93
125 return (proxy_hostname != NULL && *proxy_hostname != '\0'); 94 return (proxy_hostname != NULL && *proxy_hostname != '\0');
126 } 95 }
127 96
128 97
129 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
130 static int
131 get_port (struct addrinfo *addr)
132 {
133 struct sockaddr_in * saddr;
134 int port;
135
136 if (addr->ai_family == AF_INET)
137 {
138 saddr = (struct sockaddr_in *) addr->ai_addr;
139 port = ntohs (saddr->sin_port);
140 }
141 else
142 port = 0;
143
144 return (port);
145 }
146
147
148 static int
149 gftp_connect_server_with_getaddr (gftp_request * request, char *service,
150 char *proxy_hostname, unsigned int proxy_port)
151 {
152 struct addrinfo *hostp, *current_hostp;
153 char *connect_host, *disphost;
154 struct addrinfo hints, *res;
155 intptr_t enable_ipv6;
156 unsigned int port;
157 int ret, sock = -1;
158 char serv[8];
159
160 if ((ret = gftp_need_proxy (request, service, proxy_hostname,
161 proxy_port)) < 0)
162 return (ret);
163 else
164 request->use_proxy = ret;
165
166 gftp_lookup_request_option (request, "enable_ipv6", &enable_ipv6);
167
168 memset (&hints, 0, sizeof (hints));
169 hints.ai_flags = AI_CANONNAME;
170
171 hints.ai_family = enable_ipv6 ? PF_UNSPEC : AF_INET;
172 hints.ai_socktype = SOCK_STREAM;
173
174 if (request->use_proxy)
175 {
176 connect_host = proxy_hostname;
177 port = proxy_port;
178 }
179 else
180 {
181 connect_host = request->hostname;
182 port = request->port;
183 }
184
185 if (port == 0)
186 strcpy (serv, service);
187 else
188 snprintf (serv, sizeof (serv), "%d", port);
189
190 request->logging_function (gftp_logging_misc, request,
191 _("Looking up %s\n"), connect_host);
192 if ((ret = getaddrinfo (connect_host, serv, &hints,
193 &hostp)) != 0)
194 {
195 request->logging_function (gftp_logging_error, request,
196 _("Cannot look up hostname %s: %s\n"),
197 connect_host, gai_strerror (ret));
198 return (GFTP_ERETRYABLE);
199 }
200
201 disphost = connect_host;
202 for (res = hostp; res != NULL; res = res->ai_next)
203 {
204 disphost = res->ai_canonname ? res->ai_canonname : connect_host;
205 port = get_port (res);
206 if (!request->use_proxy)
207 request->port = port;
208
209 if ((sock = socket (res->ai_family, res->ai_socktype,
210 res->ai_protocol)) < 0)
211 {
212 request->logging_function (gftp_logging_error, request,
213 _("Failed to create a socket: %s\n"),
214 g_strerror (errno));
215 continue;
216 }
217
218 request->logging_function (gftp_logging_misc, request,
219 _("Trying %s:%d\n"), disphost, port);
220
221 if (connect (sock, res->ai_addr, res->ai_addrlen) == -1)
222 {
223 request->logging_function (gftp_logging_error, request,
224 _("Cannot connect to %s: %s\n"),
225 disphost, g_strerror (errno));
226 close (sock);
227 continue;
228 }
229
230 current_hostp = res;
231 request->ai_family = res->ai_family;
232 break;
233 }
234
235 if (res == NULL)
236 {
237 if (hostp != NULL)
238 freeaddrinfo (hostp);
239
240 return (GFTP_ERETRYABLE);
241 }
242
243 request->remote_addr_len = current_hostp->ai_addrlen;
244 request->remote_addr = g_malloc0 (request->remote_addr_len);
245 memcpy (request->remote_addr, &((struct sockaddr_in *) current_hostp->ai_addr)->sin_addr,
246 request->remote_addr_len);
247
248 request->logging_function (gftp_logging_misc, request,
249 _("Connected to %s:%d\n"), connect_host, port);
250
251 return (sock);
252 }
253 #endif
254
255
256 static int
257 gftp_connect_server_legacy (gftp_request * request, char *service,
258 char *proxy_hostname, unsigned int proxy_port)
259 {
260 struct sockaddr_in remote_address;
261 char *connect_host, *disphost;
262 struct hostent host, *hostp;
263 struct servent serv_struct;
264 int ret, sock, curhost;
265 unsigned int port;
266
267 if ((ret = gftp_need_proxy (request, service, proxy_hostname,
268 proxy_port)) < 0)
269 return (ret);
270
271 request->use_proxy = ret;
272 if (request->use_proxy == 1)
273 hostp = NULL;
274
275 request->ai_family = AF_INET;
276 if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
277 {
278 request->logging_function (gftp_logging_error, request,
279 _("Failed to create a IPv4 socket: %s\n"),
280 g_strerror (errno));
281 return (GFTP_ERETRYABLE);
282 }
283
284 memset (&remote_address, 0, sizeof (remote_address));
285 remote_address.sin_family = AF_INET;
286
287 if (request->use_proxy)
288 {
289 connect_host = proxy_hostname;
290 port = proxy_port;
291 }
292 else
293 {
294 connect_host = request->hostname;
295 port = request->port;
296 }
297
298 if (port == 0)
299 {
300 if (!r_getservbyname (service, "tcp", &serv_struct, NULL))
301 {
302 request->logging_function (gftp_logging_error, request,
303 _("Cannot look up service name %s/tcp. Please check your services file\n"),
304 service);
305 close (sock);
306 return (GFTP_EFATAL);
307 }
308
309 port = ntohs (serv_struct.s_port);
310
311 if (!request->use_proxy)
312 request->port = port;
313 }
314
315 remote_address.sin_port = htons (port);
316
317 request->logging_function (gftp_logging_misc, request,
318 _("Looking up %s\n"), connect_host);
319
320 if (!(hostp = r_gethostbyname (connect_host, &host, NULL)))
321 {
322 request->logging_function (gftp_logging_error, request,
323 _("Cannot look up hostname %s: %s\n"),
324 connect_host, g_strerror (errno));
325 close (sock);
326 return (GFTP_ERETRYABLE);
327 }
328
329 disphost = NULL;
330 for (curhost = 0;
331 host.h_addr_list[curhost] != NULL;
332 curhost++)
333 {
334 disphost = host.h_name;
335 memcpy (&remote_address.sin_addr,
336 host.h_addr_list[curhost],
337 host.h_length);
338 request->logging_function (gftp_logging_misc, request,
339 _("Trying %s:%d\n"),
340 host.h_name, port);
341
342 if (connect (sock, (struct sockaddr *) &remote_address,
343 sizeof (remote_address)) == -1)
344 {
345 request->logging_function (gftp_logging_error, request,
346 _("Cannot connect to %s: %s\n"),
347 connect_host, g_strerror (errno));
348 }
349 break;
350 }
351
352 if (host.h_addr_list[curhost] == NULL)
353 {
354 close (sock);
355 return (GFTP_ERETRYABLE);
356 }
357
358 return (sock);
359 }
360
361
362 int 98 int
363 gftp_connect_server (gftp_request * request, char *service, 99 gftp_connect_server (gftp_request * request, char *service,
364 char *proxy_hostname, unsigned int proxy_port) 100 char *proxy_hostname, unsigned int proxy_port)
365 { 101 {
366 int sock; 102 void *connect_data;
103 int sock, ret;
367 104
105 if ((ret = gftp_need_proxy (request, service, proxy_hostname,
106 proxy_port, &connect_data)) < 0)
107 return (ret);
108 request->use_proxy = ret;
109
110 /* FIXME - pass connect_data to these functions. This is to bypass a
111 second DNS lookup */
368 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) 112 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
369 sock = gftp_connect_server_with_getaddr (request, service, proxy_hostname, 113 sock = gftp_connect_server_with_getaddrinfo (request, service, proxy_hostname,
370 proxy_port); 114 proxy_port);
371 #else 115 #else
372 sock = gftp_connect_server_legacy (request, service, proxy_hostname, 116 sock = gftp_connect_server_legacy (request, service, proxy_hostname,
373 proxy_port); 117 proxy_port);
374 #endif 118 #endif
375 119