]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/network.c
mount.nfs: Remove a redundant port assignment
[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 "xcommon.h"
38 #include "mount.h"
39 #include "nls.h"
40 #include "nfs_mount.h"
41 #include "mount_constants.h"
42 #include "network.h"
43
44 #ifdef HAVE_RPCSVC_NFS_PROT_H
45 #include <rpcsvc/nfs_prot.h>
46 #else
47 #include <linux/nfs.h>
48 #define nfsstat nfs_stat
49 #endif
50
51 #ifndef NFS_PORT
52 #define NFS_PORT 2049
53 #endif
54
55 #if SIZEOF_SOCKLEN_T - 0 == 0
56 #define socklen_t unsigned int
57 #endif
58
59 extern int nfs_mount_data_version;
60 extern char *progname;
61 extern int verbose;
62
63 static const unsigned long nfs_to_mnt[] = {
64         0,
65         0,
66         1,
67         3,
68 };
69
70 static const unsigned long mnt_to_nfs[] = {
71         0,
72         2,
73         2,
74         3,
75 };
76
77 /*
78  * Map an NFS version into the corresponding Mountd version
79  */
80 unsigned long nfsvers_to_mnt(const unsigned long vers)
81 {
82         if (vers <= 3)
83                 return nfs_to_mnt[vers];
84         return 0;
85 }
86
87 /*
88  * Map a Mountd version into the corresponding NFS version
89  */
90 static unsigned long mntvers_to_nfs(const unsigned long vers)
91 {
92         if (vers <= 3)
93                 return mnt_to_nfs[vers];
94         return 0;
95 }
96
97 static const unsigned int probe_udp_only[] = {
98         IPPROTO_UDP,
99         0,
100 };
101
102 static const unsigned int probe_udp_first[] = {
103         IPPROTO_UDP,
104         IPPROTO_TCP,
105         0,
106 };
107
108 static const unsigned int probe_tcp_first[] = {
109         IPPROTO_TCP,
110         IPPROTO_UDP,
111         0,
112 };
113
114 static const unsigned long probe_nfs2_only[] = {
115         2,
116         0,
117 };
118
119 static const unsigned long probe_nfs3_first[] = {
120         3,
121         2,
122         0,
123 };
124
125 static const unsigned long probe_mnt1_first[] = {
126         1,
127         2,
128         0,
129 };
130
131 static const unsigned long probe_mnt3_first[] = {
132         3,
133         1,
134         2,
135         0,
136 };
137
138 int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
139 {
140         struct hostent *hp;
141
142         saddr->sin_family = AF_INET;
143         if (!inet_aton(hostname, &saddr->sin_addr)) {
144                 if ((hp = gethostbyname(hostname)) == NULL) {
145                         nfs_error(_("%s: can't get address for %s\n"),
146                                         progname, hostname);
147                         return 0;
148                 } else {
149                         if (hp->h_length > sizeof(*saddr)) {
150                                 nfs_error(_("%s: got bad hp->h_length\n"),
151                                                 progname);
152                                 hp->h_length = sizeof(*saddr);
153                         }
154                         memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
155                 }
156         }
157         return 1;
158 }
159
160 /*
161  * Create a socket that is locally bound to a reserved or non-reserved
162  * port. For any failures, RPC_ANYSOCK is returned which will cause 
163  * the RPC code to create the socket instead. 
164  */
165 static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot,
166                         int resvp, int conn)
167 {
168         int so, cc, type;
169         struct sockaddr_in laddr;
170         socklen_t namelen = sizeof(laddr);
171
172         type = (p_prot == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM);
173         if ((so = socket (AF_INET, type, p_prot)) < 0)
174                 goto err_socket;
175
176         laddr.sin_family = AF_INET;
177         laddr.sin_port = 0;
178         laddr.sin_addr.s_addr = htonl(INADDR_ANY);
179         if (resvp) {
180                 if (bindresvport(so, &laddr) < 0)
181                         goto err_bindresvport;
182         } else {
183                 cc = bind(so, (struct sockaddr *)&laddr, namelen);
184                 if (cc < 0)
185                         goto err_bind;
186         }
187         if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) {
188                 cc = connect(so, (struct sockaddr *)saddr, namelen);
189                 if (cc < 0)
190                         goto err_connect;
191         }
192         return so;
193
194 err_socket:
195         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
196         rpc_createerr.cf_error.re_errno = errno;
197         if (verbose) {
198                 nfs_error(_("%s: Unable to create %s socket: errno %d (%s)\n"),
199                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
200                         errno, strerror(errno));
201         }
202         return RPC_ANYSOCK;
203
204 err_bindresvport:
205         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
206         rpc_createerr.cf_error.re_errno = errno;
207         if (verbose) {
208                 nfs_error(_("%s: Unable to bindresvport %s socket: errno %d"
209                                 " (%s)\n"),
210                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
211                         errno, strerror(errno));
212         }
213         close(so);
214         return RPC_ANYSOCK;
215
216 err_bind:
217         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
218         rpc_createerr.cf_error.re_errno = errno;
219         if (verbose) {
220                 nfs_error(_("%s: Unable to bind to %s socket: errno %d (%s)\n"),
221                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
222                         errno, strerror(errno));
223         }
224         close(so);
225         return RPC_ANYSOCK;
226
227 err_connect:
228         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
229         rpc_createerr.cf_error.re_errno = errno;
230         if (verbose) {
231                 nfs_error(_("%s: Unable to connect to %s:%d, errno %d (%s)\n"),
232                         progname, inet_ntoa(saddr->sin_addr),
233                         ntohs(saddr->sin_port), errno, strerror(errno));
234         }
235         close(so);
236         return RPC_ANYSOCK;
237 }
238
239 /*
240  * getport() is very similar to pmap_getport() with the exception that
241  * this version tries to use an ephemeral port, since reserved ports are
242  * not needed for GETPORT queries.  This conserves the very limited
243  * reserved port space, which helps reduce failed socket binds
244  * during mount storms.
245  *
246  * A side effect of calling this function is that rpccreateerr is set.
247  */
248 static unsigned short getport(struct sockaddr_in *saddr,
249                                 unsigned long program,
250                                 unsigned long version,
251                                 unsigned int proto)
252 {
253         unsigned short port = 0;
254         int socket;
255         CLIENT *clnt = NULL;
256         enum clnt_stat stat;
257
258         saddr->sin_port = htons(PMAPPORT);
259
260         /*
261          * Try to get a socket with a non-privileged port.
262          * clnt*create() will create one anyway if this
263          * fails.
264          */
265         socket = get_socket(saddr, proto, FALSE, FALSE);
266         if (socket == RPC_ANYSOCK) {
267                 if (proto == IPPROTO_TCP && errno == ETIMEDOUT) {
268                         /*
269                          * TCP SYN timed out, so exit now.
270                          */
271                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
272                 }
273                 return 0;
274         }
275
276         switch (proto) {
277         case IPPROTO_UDP:
278                 clnt = clntudp_bufcreate(saddr,
279                                          PMAPPROG, PMAPVERS,
280                                          RETRY_TIMEOUT, &socket,
281                                          RPCSMALLMSGSIZE,
282                                          RPCSMALLMSGSIZE);
283                 break;
284         case IPPROTO_TCP:
285                 clnt = clnttcp_create(saddr, PMAPPROG, PMAPVERS, &socket,
286                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
287                 break;
288         }
289         if (clnt != NULL) {
290                 struct pmap parms = {
291                         .pm_prog        = program,
292                         .pm_vers        = version,
293                         .pm_prot        = proto,
294                 };
295
296                 stat = clnt_call(clnt, PMAPPROC_GETPORT,
297                                  (xdrproc_t)xdr_pmap, (caddr_t)&parms,
298                                  (xdrproc_t)xdr_u_short, (caddr_t)&port,
299                                  TIMEOUT);
300                 if (stat) {
301                         clnt_geterr(clnt, &rpc_createerr.cf_error);
302                         rpc_createerr.cf_stat = stat;
303                 }
304                 clnt_destroy(clnt);
305                 if (stat != RPC_SUCCESS)
306                         port = 0;
307                 else if (port == 0)
308                         rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
309         }
310         if (socket != 1)
311                 close(socket);
312
313         return port;
314 }
315
316 /*
317  * Use the portmapper to discover whether or not the service we want is
318  * available. The lists 'versions' and 'protos' define ordered sequences
319  * of service versions and udp/tcp protocols to probe for.
320  */
321 static int probe_port(clnt_addr_t *server, const unsigned long *versions,
322                         const unsigned int *protos)
323 {
324         struct sockaddr_in *saddr = &server->saddr;
325         struct pmap *pmap = &server->pmap;
326         const unsigned long prog = pmap->pm_prog, *p_vers;
327         const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
328         const u_short port = (u_short) pmap->pm_port;
329         unsigned long vers = pmap->pm_vers;
330         unsigned short p_port;
331
332         p_prot = prot ? &prot : protos;
333         p_vers = vers ? &vers : versions;
334         rpc_createerr.cf_stat = 0;
335         for (;;) {
336                 p_port = getport(saddr, prog, *p_vers, *p_prot);
337                 if (p_port) {
338                         if (!port || port == p_port) {
339                                 saddr->sin_port = htons(p_port);
340                                 if (verbose) {
341                                         printf(_("%s: trying %s prog %ld vers "
342                                                 "%ld prot %s port %d\n"),
343                                                 progname,
344                                                 inet_ntoa(saddr->sin_addr),
345                                                 prog, *p_vers,
346                                                 *p_prot == IPPROTO_UDP ?
347                                                         "udp" : "tcp",
348                                                 p_port);
349                                 }
350                                 if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
351                                         goto out_ok;
352                                 if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
353                                         goto out_bad;
354                         }
355                 }
356                 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
357                         goto out_bad;
358
359                 if (!prot) {
360                         if (*++p_prot)
361                                 continue;
362                         p_prot = protos;
363                 }
364                 if (vers == pmap->pm_vers) {
365                         p_vers = versions;
366                         vers = 0;
367                 }
368                 if (vers || !*++p_vers)
369                         break;
370         }
371
372 out_bad:
373         return 0;
374
375 out_ok:
376         if (!vers)
377                 pmap->pm_vers = *p_vers;
378         if (!prot)
379                 pmap->pm_prot = *p_prot;
380         if (!port)
381                 pmap->pm_port = p_port;
382         rpc_createerr.cf_stat = 0;
383         return 1;
384 }
385
386 static int probe_nfsport(clnt_addr_t *nfs_server)
387 {
388         struct pmap *pmap = &nfs_server->pmap;
389
390         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
391                 return 1;
392
393         if (nfs_mount_data_version >= 4)
394                 return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first);
395         else
396                 return probe_port(nfs_server, probe_nfs2_only, probe_udp_only);
397 }
398
399 static int probe_mntport(clnt_addr_t *mnt_server)
400 {
401         struct pmap *pmap = &mnt_server->pmap;
402
403         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
404                 return 1;
405
406         if (nfs_mount_data_version >= 4)
407                 return probe_port(mnt_server, probe_mnt3_first, probe_udp_first);
408         else
409                 return probe_port(mnt_server, probe_mnt1_first, probe_udp_only);
410 }
411
412 int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
413 {
414         struct pmap *nfs_pmap = &nfs_server->pmap;
415         struct pmap *mnt_pmap = &mnt_server->pmap;
416         struct pmap save_nfs, save_mnt;
417         int res;
418         const unsigned long *probe_vers;
419
420         if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
421                 nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
422         else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
423                 mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
424         if (nfs_pmap->pm_vers)
425                 goto version_fixed;
426
427         memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
428         memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
429         probe_vers = (nfs_mount_data_version >= 4) ?
430                         probe_mnt3_first : probe_mnt1_first;
431
432         for (; *probe_vers; probe_vers++) {
433                 nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
434                 if ((res = probe_nfsport(nfs_server) != 0)) {
435                         mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
436                         if ((res = probe_mntport(mnt_server)) != 0)
437                                 return 1;
438                         memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
439                 }
440                 switch (rpc_createerr.cf_stat) {
441                 case RPC_PROGVERSMISMATCH:
442                 case RPC_PROGNOTREGISTERED:
443                         break;
444                 default:
445                         goto out_bad;
446                 }
447                 memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
448         }
449
450 out_bad:
451         return 0;
452
453 version_fixed:
454         if (!probe_nfsport(nfs_server))
455                 goto out_bad;
456         return probe_mntport(mnt_server);
457 }
458
459 static int probe_statd(void)
460 {
461         struct sockaddr_in addr;
462         unsigned short port;
463
464         memset(&addr, 0, sizeof(addr));
465         addr.sin_family = AF_INET;
466         addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
467         port = getport(&addr, 100024, 1, IPPROTO_UDP);
468
469         if (port == 0)
470                 return 0;
471         addr.sin_port = htons(port);
472
473         if (clnt_ping(&addr, 100024, 1, IPPROTO_UDP, NULL) <= 0)
474                 return 0;
475
476         return 1;
477 }
478
479 /*
480  * Attempt to start rpc.statd
481  */
482 int start_statd(void)
483 {
484 #ifdef START_STATD
485         struct stat stb;
486 #endif
487
488         if (probe_statd())
489                 return 1;
490
491 #ifdef START_STATD
492         if (stat(START_STATD, &stb) == 0) {
493                 if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
494                         system(START_STATD);
495                         if (probe_statd())
496                                 return 1;
497                 }
498         }
499 #endif
500
501         return 0;
502 }
503
504 /*
505  * nfs_call_umount - ask the server to remove a share from it's rmtab
506  * @mnt_server: address of RPC MNT program server
507  * @argp: directory path of share to "unmount"
508  *
509  * Returns one if the unmount call succeeded; zero if the unmount
510  * failed for any reason.
511  *
512  * Note that a side effect of calling this function is that rpccreateerr
513  * is set.
514  */
515 int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
516 {
517         CLIENT *clnt;
518         enum clnt_stat res = 0;
519         int msock;
520
521         switch (mnt_server->pmap.pm_vers) {
522         case 3:
523         case 2:
524         case 1:
525                 if (!probe_mntport(mnt_server))
526                         return 0;
527                 clnt = mnt_openclnt(mnt_server, &msock);
528                 if (!clnt)
529                         return 0;
530                 res = clnt_call(clnt, MOUNTPROC_UMNT,
531                                 (xdrproc_t)xdr_dirpath, (caddr_t)argp,
532                                 (xdrproc_t)xdr_void, NULL,
533                                 TIMEOUT);
534                 mnt_closeclnt(clnt, msock);
535                 if (res == RPC_SUCCESS)
536                         return 1;
537                 break;
538         default:
539                 res = RPC_SUCCESS;
540                 break;
541         }
542
543         if (res == RPC_SUCCESS)
544                 return 1;
545         return 0;
546 }
547
548 CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
549 {
550         struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
551         struct pmap *mnt_pmap = &mnt_server->pmap;
552         CLIENT *clnt = NULL;
553
554         mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
555         *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, TRUE, FALSE);
556         if (*msock == RPC_ANYSOCK) {
557                 if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
558                         /*
559                          * Probably in-use by a TIME_WAIT connection,
560                          * It is worth waiting a while and trying again.
561                          */
562                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
563                 return NULL;
564         }
565
566         switch (mnt_pmap->pm_prot) {
567         case IPPROTO_UDP:
568                 clnt = clntudp_bufcreate(mnt_saddr,
569                                          mnt_pmap->pm_prog, mnt_pmap->pm_vers,
570                                          RETRY_TIMEOUT, msock,
571                                          MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
572                 break;
573         case IPPROTO_TCP:
574                 clnt = clnttcp_create(mnt_saddr,
575                                       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
576                                       msock,
577                                       MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
578                 break;
579         }
580         if (clnt) {
581                 /* try to mount hostname:dirname */
582                 clnt->cl_auth = authunix_create_default();
583                 return clnt;
584         }
585         return NULL;
586 }
587
588 void mnt_closeclnt(CLIENT *clnt, int msock)
589 {
590         auth_destroy(clnt->cl_auth);
591         clnt_destroy(clnt);
592         close(msock);
593 }
594
595 /*
596  * Sigh... getport() doesn't actually check the version number.
597  * In order to make sure that the server actually supports the service
598  * we're requesting, we open and RPC client, and fire off a NULL
599  * RPC call.
600  */
601 int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
602                 const unsigned long vers, const unsigned int prot,
603                 struct sockaddr_in *caddr)
604 {
605         CLIENT *clnt = NULL;
606         int sock, stat;
607         static char clnt_res;
608         struct sockaddr dissolve;
609
610         rpc_createerr.cf_stat = stat = errno = 0;
611         sock = get_socket(saddr, prot, FALSE, TRUE);
612         if (sock == RPC_ANYSOCK) {
613                 if (errno == ETIMEDOUT) {
614                         /*
615                          * TCP timeout. Bubble up the error to see 
616                          * how it should be handled.
617                          */
618                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
619                 }
620                 return 0;
621         }
622
623         if (caddr) {
624                 /* Get the address of our end of this connection */
625                 socklen_t len = sizeof(*caddr);
626                 if (getsockname(sock, caddr, &len) != 0)
627                         caddr->sin_family = 0;
628         }
629
630         switch(prot) {
631         case IPPROTO_UDP:
632                 /* The socket is connected (so we could getsockname successfully),
633                  * but some servers on multi-homed hosts reply from
634                  * the wrong address, so if we stay connected, we lose the reply.
635                  */
636                 dissolve.sa_family = AF_UNSPEC;
637                 connect(sock, &dissolve, sizeof(dissolve));
638
639                 clnt = clntudp_bufcreate(saddr, prog, vers,
640                                          RETRY_TIMEOUT, &sock,
641                                          RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
642                 break;
643         case IPPROTO_TCP:
644                 clnt = clnttcp_create(saddr, prog, vers, &sock,
645                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
646                 break;
647         }
648         if (!clnt) {
649                 close(sock);
650                 return 0;
651         }
652         memset(&clnt_res, 0, sizeof(clnt_res));
653         stat = clnt_call(clnt, NULLPROC,
654                          (xdrproc_t)xdr_void, (caddr_t)NULL,
655                          (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
656                          TIMEOUT);
657         if (stat) {
658                 clnt_geterr(clnt, &rpc_createerr.cf_error);
659                 rpc_createerr.cf_stat = stat;
660         }
661         clnt_destroy(clnt);
662         close(sock);
663
664         if (stat == RPC_SUCCESS)
665                 return 1;
666         else
667                 return 0;
668 }