950
|
1 /*****************************************************************************/
|
|
2 /* socket-connect.c - contains functions for connecting to a server */
|
|
3 /* Copyright (C) 1998-2008 Brian Masney <masneyb@gftp.org> */
|
|
4 /* */
|
|
5 /* This program is free software; you can redistribute it and/or modify */
|
|
6 /* it under the terms of the GNU General Public License as published by */
|
|
7 /* the Free Software Foundation; either version 2 of the License, or */
|
|
8 /* (at your option) any later version. */
|
|
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 USA */
|
|
18 /*****************************************************************************/
|
|
19
|
|
20 #include "gftp.h"
|
|
21 static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $";
|
|
22
|
|
23 /* FIXME - clean up this function */
|
|
24 static int
|
|
25 gftp_need_proxy (gftp_request * request, char *service, char *proxy_hostname,
|
|
26 unsigned int proxy_port)
|
|
27 {
|
|
28 gftp_config_list_vars * proxy_hosts;
|
|
29 gftp_proxy_hosts * hostname;
|
|
30 size_t hostlen, domlen;
|
|
31 unsigned char addy[4];
|
|
32 struct sockaddr *addr;
|
|
33 GList * templist;
|
|
34 gint32 netaddr;
|
|
35 char *pos;
|
|
36 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
|
|
37 struct addrinfo hints, *hostp;
|
|
38 unsigned int port;
|
|
39 int errnum;
|
|
40 char serv[8];
|
|
41 #else
|
|
42 struct hostent host, *hostp;
|
|
43 #endif
|
|
44
|
|
45 gftp_lookup_global_option ("dont_use_proxy", &proxy_hosts);
|
|
46
|
|
47 if (proxy_hostname == NULL || *proxy_hostname == '\0')
|
|
48 return (0);
|
|
49 else if (proxy_hosts->list == NULL)
|
|
50 return (proxy_hostname != NULL &&
|
|
51 *proxy_hostname != '\0');
|
|
52
|
|
53 hostp = NULL;
|
|
54 #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
|
|
60 port = request->use_proxy ? proxy_port : request->port;
|
|
61 if (port == 0)
|
|
62 strcpy (serv, service);
|
|
63 else
|
|
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
|
|
80 #else /* !HAVE_GETADDRINFO */
|
|
81 request->logging_function (gftp_logging_misc, request,
|
|
82 _("Looking up %s\n"), request->hostname);
|
|
83
|
|
84 if (!(hostp = r_gethostbyname (request->hostname, &host, NULL)))
|
|
85 {
|
|
86 request->logging_function (gftp_logging_error, request,
|
|
87 _("Cannot look up hostname %s: %s\n"),
|
|
88 request->hostname, g_strerror (errno));
|
|
89 return (GFTP_ERETRYABLE);
|
|
90 }
|
|
91
|
|
92 addr = (struct sockaddr *) host.h_addr_list[0];
|
|
93
|
|
94 #endif /* HAVE_GETADDRINFO */
|
|
95
|
|
96 templist = proxy_hosts->list;
|
|
97 while (templist != NULL)
|
|
98 {
|
|
99 hostname = templist->data;
|
|
100 if (hostname->domain != NULL)
|
|
101 {
|
|
102 hostlen = strlen (request->hostname);
|
|
103 domlen = strlen (hostname->domain);
|
|
104 if (hostlen > domlen)
|
|
105 {
|
|
106 pos = request->hostname + hostlen - domlen;
|
|
107 if (strcmp (hostname->domain, pos) == 0)
|
|
108 return (0);
|
|
109 }
|
|
110 }
|
|
111
|
|
112 if (hostname->ipv4_network_address != 0)
|
|
113 {
|
|
114 memcpy (addy, addr, sizeof (*addy));
|
|
115 netaddr =
|
|
116 (((addy[0] & 0xff) << 24) | ((addy[1] & 0xff) << 16) |
|
|
117 ((addy[2] & 0xff) << 8) | (addy[3] & 0xff)) &
|
|
118 hostname->ipv4_netmask;
|
|
119 if (netaddr == hostname->ipv4_network_address)
|
|
120 return (0);
|
|
121 }
|
|
122 templist = templist->next;
|
|
123 }
|
|
124
|
|
125 return (proxy_hostname != NULL && *proxy_hostname != '\0');
|
|
126 }
|
|
127
|
|
128
|
|
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
|
|
363 gftp_connect_server (gftp_request * request, char *service,
|
|
364 char *proxy_hostname, unsigned int proxy_port)
|
|
365 {
|
|
366 int sock;
|
|
367
|
|
368 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
|
|
369 sock = gftp_connect_server_with_getaddr (request, service, proxy_hostname,
|
|
370 proxy_port);
|
|
371 #else
|
|
372 sock = gftp_connect_server_legacy (request, service, proxy_hostname,
|
|
373 proxy_port);
|
|
374 #endif
|
|
375
|
|
376 if (sock < 0)
|
|
377 return (sock);
|
|
378
|
|
379 if (fcntl (sock, F_SETFD, 1) == -1)
|
|
380 {
|
|
381 request->logging_function (gftp_logging_error, request,
|
|
382 _("Error: Cannot set close on exec flag: %s\n"),
|
|
383 g_strerror (errno));
|
|
384 close (sock);
|
|
385 return (GFTP_ERETRYABLE);
|
|
386 }
|
|
387
|
|
388 if (gftp_fd_set_sockblocking (request, sock, 1) < 0)
|
|
389 {
|
|
390 close (sock);
|
|
391 return (GFTP_ERETRYABLE);
|
|
392 }
|
|
393
|
|
394 request->datafd = sock;
|
|
395
|
|
396 if (request->post_connect != NULL)
|
|
397 return (request->post_connect (request));
|
|
398
|
|
399 return (0);
|
|
400 }
|
|
401
|