]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/network.c
mount.nfs: fix hang when getport() uses TCP against unavailable servers
[nfs-utils.git] / utils / mount / network.c
1 /*
2  * network.c -- Provide common network functions for NFS mount/umount
3  *
4  * Copyright (C) 2007 Oracle.  All rights reserved.
5  * Copyright (C) 2007 Chuck Lever <chuck.lever@oracle.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 021110-1307, USA.
21  *
22  */
23
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <netdb.h>
31 #include <time.h>
32 #include <rpc/rpc.h>
33 #include <rpc/pmap_prot.h>
34 #include <rpc/pmap_clnt.h>
35 #include <sys/socket.h>
36
37 #include "conn.h"
38 #include "xcommon.h"
39 #include "mount.h"
40 #include "nls.h"
41 #include "nfs_mount.h"
42 #include "mount_constants.h"
43 #include "network.h"
44
45 #ifdef HAVE_RPCSVC_NFS_PROT_H
46 #include <rpcsvc/nfs_prot.h>
47 #else
48 #include <linux/nfs.h>
49 #define nfsstat nfs_stat
50 #endif
51
52 #ifndef NFS_PORT
53 #define NFS_PORT 2049
54 #endif
55
56 extern int nfs_mount_data_version;
57 extern char *progname;
58 extern int verbose;
59
60 static const unsigned int probe_udp_only[] = {
61         IPPROTO_UDP,
62         0,
63 };
64
65 static const unsigned int probe_udp_first[] = {
66         IPPROTO_UDP,
67         IPPROTO_TCP,
68         0,
69 };
70
71 static const unsigned int probe_tcp_first[] = {
72         IPPROTO_TCP,
73         IPPROTO_UDP,
74         0,
75 };
76
77 static const unsigned long probe_nfs2_only[] = {
78         2,
79         0,
80 };
81
82 static const unsigned long probe_nfs3_first[] = {
83         3,
84         2,
85         0,
86 };
87
88 static const unsigned long probe_mnt1_first[] = {
89         1,
90         2,
91         0,
92 };
93
94 static const unsigned long probe_mnt3_first[] = {
95         3,
96         1,
97         2,
98         0,
99 };
100
101 int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
102 {
103         struct hostent *hp;
104
105         saddr->sin_family = AF_INET;
106         if (!inet_aton(hostname, &saddr->sin_addr)) {
107                 if ((hp = gethostbyname(hostname)) == NULL) {
108                         nfs_error(_("%s: can't get address for %s\n"),
109                                         progname, hostname);
110                         return 0;
111                 } else {
112                         if (hp->h_length > sizeof(*saddr)) {
113                                 nfs_error(_("%s: got bad hp->h_length\n"),
114                                                 progname);
115                                 hp->h_length = sizeof(*saddr);
116                         }
117                         memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
118                 }
119         }
120         return 1;
121 }
122
123 /*
124  * getport() is very similar to pmap_getport() with
125  * the exception this version uses a non-reserve ports
126  * instead of reserve ports since reserve ports
127  * are not needed for pmap requests.
128  */
129 unsigned short getport(struct sockaddr_in *saddr, unsigned long prog,
130                         unsigned long vers, unsigned int prot)
131 {
132         unsigned short port = 0;
133         int socket;
134         CLIENT *clnt = NULL;
135         struct pmap parms;
136         enum clnt_stat stat;
137
138         saddr->sin_port = htons(PMAPPORT);
139
140         /*
141          * Try to get a socket with a non-privileged port.
142          * clnt*create() will create one anyway if this
143          * fails.
144          */
145         socket = get_socket(saddr, proto, FALSE, FALSE);
146         if (socket == RPC_ANYSOCK) {
147                 if (proto == IPPROTO_TCP && errno == ETIMEDOUT) {
148                         /*
149                          * TCP SYN timed out, so exit now.
150                          */
151                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
152                 }
153                 return 0;
154         }
155
156         switch (prot) {
157         case IPPROTO_UDP:
158                 clnt = clntudp_bufcreate(saddr,
159                                          PMAPPROG, PMAPVERS, TIMEOUT, &socket,
160                                          UDPMSGSIZE, UDPMSGSIZE);
161                 break;
162         case IPPROTO_TCP:
163                 clnt = clnttcp_create(saddr,
164                         PMAPPROG, PMAPVERS, &socket, 50, 500);
165                 break;
166         }
167         if (clnt != NULL) {
168                 parms.pm_prog = prog;
169                 parms.pm_vers = vers;
170                 parms.pm_prot = prot;
171                 parms.pm_port = 0;    /* not needed or used */
172
173                 stat = clnt_call(clnt, PMAPPROC_GETPORT, (xdrproc_t)xdr_pmap,
174                         (caddr_t)&parms, (xdrproc_t)xdr_u_short, (caddr_t)&port, TIMEOUT);
175                 if (stat) {
176                         clnt_geterr(clnt, &rpc_createerr.cf_error);
177                         rpc_createerr.cf_stat = stat;
178                 }
179                 clnt_destroy(clnt);
180                 if (stat != RPC_SUCCESS)
181                         port = 0;
182                 else if (port == 0)
183                         rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
184         }
185         if (socket != 1)
186                 close(socket);
187
188         return port;
189 }
190
191 /*
192  * Use the portmapper to discover whether or not the service we want is
193  * available. The lists 'versions' and 'protos' define ordered sequences
194  * of service versions and udp/tcp protocols to probe for.
195  */
196 static int probe_port(clnt_addr_t *server, const unsigned long *versions,
197                         const unsigned int *protos)
198 {
199         struct sockaddr_in *saddr = &server->saddr;
200         struct pmap *pmap = &server->pmap;
201         const unsigned long prog = pmap->pm_prog, *p_vers;
202         const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
203         const u_short port = (u_short) pmap->pm_port;
204         unsigned long vers = pmap->pm_vers;
205         unsigned short p_port;
206
207         p_prot = prot ? &prot : protos;
208         p_vers = vers ? &vers : versions;
209         rpc_createerr.cf_stat = 0;
210         for (;;) {
211                 saddr->sin_port = htons(PMAPPORT);
212                 p_port = getport(saddr, prog, *p_vers, *p_prot);
213                 if (p_port) {
214                         if (!port || port == p_port) {
215                                 saddr->sin_port = htons(p_port);
216                                 if (verbose) {
217                                         printf(_("%s: trying %s prog %ld vers "
218                                                 "%ld prot %s port %d\n"),
219                                                 progname,
220                                                 inet_ntoa(saddr->sin_addr),
221                                                 prog, *p_vers,
222                                                 *p_prot == IPPROTO_UDP ?
223                                                         "udp" : "tcp",
224                                                 p_port);
225                                 }
226                                 if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
227                                         goto out_ok;
228                                 if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
229                                         goto out_bad;
230                         }
231                 }
232                 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
233                         goto out_bad;
234
235                 if (!prot) {
236                         if (*++p_prot)
237                                 continue;
238                         p_prot = protos;
239                 }
240                 if (vers == pmap->pm_vers) {
241                         p_vers = versions;
242                         vers = 0;
243                 }
244                 if (vers || !*++p_vers)
245                         break;
246         }
247
248 out_bad:
249         return 0;
250
251 out_ok:
252         if (!vers)
253                 pmap->pm_vers = *p_vers;
254         if (!prot)
255                 pmap->pm_prot = *p_prot;
256         if (!port)
257                 pmap->pm_port = p_port;
258         rpc_createerr.cf_stat = 0;
259         return 1;
260 }
261
262 static int probe_nfsport(clnt_addr_t *nfs_server)
263 {
264         struct pmap *pmap = &nfs_server->pmap;
265
266         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
267                 return 1;
268
269         if (nfs_mount_data_version >= 4)
270                 return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first);
271         else
272                 return probe_port(nfs_server, probe_nfs2_only, probe_udp_only);
273 }
274
275 static int probe_mntport(clnt_addr_t *mnt_server)
276 {
277         struct pmap *pmap = &mnt_server->pmap;
278
279         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
280                 return 1;
281
282         if (nfs_mount_data_version >= 4)
283                 return probe_port(mnt_server, probe_mnt3_first, probe_udp_first);
284         else
285                 return probe_port(mnt_server, probe_mnt1_first, probe_udp_only);
286 }
287
288 int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
289 {
290         struct pmap *nfs_pmap = &nfs_server->pmap;
291         struct pmap *mnt_pmap = &mnt_server->pmap;
292         struct pmap save_nfs, save_mnt;
293         int res;
294         const unsigned long *probe_vers;
295
296         if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
297                 nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
298         else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
299                 mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
300         if (nfs_pmap->pm_vers)
301                 goto version_fixed;
302
303         memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
304         memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
305         probe_vers = (nfs_mount_data_version >= 4) ?
306                         probe_mnt3_first : probe_mnt1_first;
307
308         for (; *probe_vers; probe_vers++) {
309                 nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
310                 if ((res = probe_nfsport(nfs_server) != 0)) {
311                         mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
312                         if ((res = probe_mntport(mnt_server)) != 0)
313                                 return 1;
314                         memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
315                 }
316                 switch (rpc_createerr.cf_stat) {
317                 case RPC_PROGVERSMISMATCH:
318                 case RPC_PROGNOTREGISTERED:
319                         break;
320                 default:
321                         goto out_bad;
322                 }
323                 memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
324         }
325
326 out_bad:
327         return 0;
328
329 version_fixed:
330         if (!probe_nfsport(nfs_server))
331                 goto out_bad;
332         return probe_mntport(mnt_server);
333 }
334
335 static int probe_statd(void)
336 {
337         struct sockaddr_in addr;
338         unsigned short port;
339
340         memset(&addr, 0, sizeof(addr));
341         addr.sin_family = AF_INET;
342         addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
343         port = getport(&addr, 100024, 1, IPPROTO_UDP);
344
345         if (port == 0)
346                 return 0;
347         addr.sin_port = htons(port);
348
349         if (clnt_ping(&addr, 100024, 1, IPPROTO_UDP, NULL) <= 0)
350                 return 0;
351
352         return 1;
353 }
354
355 /*
356  * Attempt to start rpc.statd
357  */
358 int start_statd(void)
359 {
360 #ifdef START_STATD
361         struct stat stb;
362 #endif
363
364         if (probe_statd())
365                 return 1;
366
367 #ifdef START_STATD
368         if (stat(START_STATD, &stb) == 0) {
369                 if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
370                         system(START_STATD);
371                         if (probe_statd())
372                                 return 1;
373                 }
374         }
375 #endif
376
377         return 0;
378 }
379
380 /*
381  * nfs_call_umount - ask the server to remove a share from it's rmtab
382  * @mnt_server: address of RPC MNT program server
383  * @argp: directory path of share to "unmount"
384  *
385  * Returns one if the unmount call succeeded; zero if the unmount
386  * failed for any reason.
387  *
388  * Note that a side effect of calling this function is that rpccreateerr
389  * is set.
390  */
391 int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
392 {
393         CLIENT *clnt;
394         enum clnt_stat res = 0;
395         int msock;
396
397         switch (mnt_server->pmap.pm_vers) {
398         case 3:
399         case 2:
400         case 1:
401                 if (!probe_mntport(mnt_server))
402                         return 0;
403                 clnt = mnt_openclnt(mnt_server, &msock);
404                 if (!clnt)
405                         return 0;
406                 res = clnt_call(clnt, MOUNTPROC_UMNT,
407                                 (xdrproc_t)xdr_dirpath, (caddr_t)argp,
408                                 (xdrproc_t)xdr_void, NULL,
409                                 TIMEOUT);
410                 mnt_closeclnt(clnt, msock);
411                 if (res == RPC_SUCCESS)
412                         return 1;
413                 break;
414         default:
415                 res = RPC_SUCCESS;
416                 break;
417         }
418
419         if (res == RPC_SUCCESS)
420                 return 1;
421         return 0;
422 }