]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/network.c
libnfs.a: eliminate conn.c and conn.h
[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                 saddr->sin_port = htons(PMAPPORT);
337                 p_port = getport(saddr, prog, *p_vers, *p_prot);
338                 if (p_port) {
339                         if (!port || port == p_port) {
340                                 saddr->sin_port = htons(p_port);
341                                 if (verbose) {
342                                         printf(_("%s: trying %s prog %ld vers "
343                                                 "%ld prot %s port %d\n"),
344                                                 progname,
345                                                 inet_ntoa(saddr->sin_addr),
346                                                 prog, *p_vers,
347                                                 *p_prot == IPPROTO_UDP ?
348                                                         "udp" : "tcp",
349                                                 p_port);
350                                 }
351                                 if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
352                                         goto out_ok;
353                                 if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
354                                         goto out_bad;
355                         }
356                 }
357                 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
358                         goto out_bad;
359
360                 if (!prot) {
361                         if (*++p_prot)
362                                 continue;
363                         p_prot = protos;
364                 }
365                 if (vers == pmap->pm_vers) {
366                         p_vers = versions;
367                         vers = 0;
368                 }
369                 if (vers || !*++p_vers)
370                         break;
371         }
372
373 out_bad:
374         return 0;
375
376 out_ok:
377         if (!vers)
378                 pmap->pm_vers = *p_vers;
379         if (!prot)
380                 pmap->pm_prot = *p_prot;
381         if (!port)
382                 pmap->pm_port = p_port;
383         rpc_createerr.cf_stat = 0;
384         return 1;
385 }
386
387 static int probe_nfsport(clnt_addr_t *nfs_server)
388 {
389         struct pmap *pmap = &nfs_server->pmap;
390
391         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
392                 return 1;
393
394         if (nfs_mount_data_version >= 4)
395                 return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first);
396         else
397                 return probe_port(nfs_server, probe_nfs2_only, probe_udp_only);
398 }
399
400 static int probe_mntport(clnt_addr_t *mnt_server)
401 {
402         struct pmap *pmap = &mnt_server->pmap;
403
404         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
405                 return 1;
406
407         if (nfs_mount_data_version >= 4)
408                 return probe_port(mnt_server, probe_mnt3_first, probe_udp_first);
409         else
410                 return probe_port(mnt_server, probe_mnt1_first, probe_udp_only);
411 }
412
413 int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
414 {
415         struct pmap *nfs_pmap = &nfs_server->pmap;
416         struct pmap *mnt_pmap = &mnt_server->pmap;
417         struct pmap save_nfs, save_mnt;
418         int res;
419         const unsigned long *probe_vers;
420
421         if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
422                 nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
423         else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
424                 mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
425         if (nfs_pmap->pm_vers)
426                 goto version_fixed;
427
428         memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
429         memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
430         probe_vers = (nfs_mount_data_version >= 4) ?
431                         probe_mnt3_first : probe_mnt1_first;
432
433         for (; *probe_vers; probe_vers++) {
434                 nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
435                 if ((res = probe_nfsport(nfs_server) != 0)) {
436                         mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
437                         if ((res = probe_mntport(mnt_server)) != 0)
438                                 return 1;
439                         memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
440                 }
441                 switch (rpc_createerr.cf_stat) {
442                 case RPC_PROGVERSMISMATCH:
443                 case RPC_PROGNOTREGISTERED:
444                         break;
445                 default:
446                         goto out_bad;
447                 }
448                 memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
449         }
450
451 out_bad:
452         return 0;
453
454 version_fixed:
455         if (!probe_nfsport(nfs_server))
456                 goto out_bad;
457         return probe_mntport(mnt_server);
458 }
459
460 static int probe_statd(void)
461 {
462         struct sockaddr_in addr;
463         unsigned short port;
464
465         memset(&addr, 0, sizeof(addr));
466         addr.sin_family = AF_INET;
467         addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
468         port = getport(&addr, 100024, 1, IPPROTO_UDP);
469
470         if (port == 0)
471                 return 0;
472         addr.sin_port = htons(port);
473
474         if (clnt_ping(&addr, 100024, 1, IPPROTO_UDP, NULL) <= 0)
475                 return 0;
476
477         return 1;
478 }
479
480 /*
481  * Attempt to start rpc.statd
482  */
483 int start_statd(void)
484 {
485 #ifdef START_STATD
486         struct stat stb;
487 #endif
488
489         if (probe_statd())
490                 return 1;
491
492 #ifdef START_STATD
493         if (stat(START_STATD, &stb) == 0) {
494                 if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
495                         system(START_STATD);
496                         if (probe_statd())
497                                 return 1;
498                 }
499         }
500 #endif
501
502         return 0;
503 }
504
505 /*
506  * nfs_call_umount - ask the server to remove a share from it's rmtab
507  * @mnt_server: address of RPC MNT program server
508  * @argp: directory path of share to "unmount"
509  *
510  * Returns one if the unmount call succeeded; zero if the unmount
511  * failed for any reason.
512  *
513  * Note that a side effect of calling this function is that rpccreateerr
514  * is set.
515  */
516 int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
517 {
518         CLIENT *clnt;
519         enum clnt_stat res = 0;
520         int msock;
521
522         switch (mnt_server->pmap.pm_vers) {
523         case 3:
524         case 2:
525         case 1:
526                 if (!probe_mntport(mnt_server))
527                         return 0;
528                 clnt = mnt_openclnt(mnt_server, &msock);
529                 if (!clnt)
530                         return 0;
531                 res = clnt_call(clnt, MOUNTPROC_UMNT,
532                                 (xdrproc_t)xdr_dirpath, (caddr_t)argp,
533                                 (xdrproc_t)xdr_void, NULL,
534                                 TIMEOUT);
535                 mnt_closeclnt(clnt, msock);
536                 if (res == RPC_SUCCESS)
537                         return 1;
538                 break;
539         default:
540                 res = RPC_SUCCESS;
541                 break;
542         }
543
544         if (res == RPC_SUCCESS)
545                 return 1;
546         return 0;
547 }
548
549 CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
550 {
551         struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
552         struct pmap *mnt_pmap = &mnt_server->pmap;
553         CLIENT *clnt = NULL;
554
555         mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
556         *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, TRUE, FALSE);
557         if (*msock == RPC_ANYSOCK) {
558                 if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
559                         /*
560                          * Probably in-use by a TIME_WAIT connection,
561                          * It is worth waiting a while and trying again.
562                          */
563                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
564                 return NULL;
565         }
566
567         switch (mnt_pmap->pm_prot) {
568         case IPPROTO_UDP:
569                 clnt = clntudp_bufcreate(mnt_saddr,
570                                          mnt_pmap->pm_prog, mnt_pmap->pm_vers,
571                                          RETRY_TIMEOUT, msock,
572                                          MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
573                 break;
574         case IPPROTO_TCP:
575                 clnt = clnttcp_create(mnt_saddr,
576                                       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
577                                       msock,
578                                       MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
579                 break;
580         }
581         if (clnt) {
582                 /* try to mount hostname:dirname */
583                 clnt->cl_auth = authunix_create_default();
584                 return clnt;
585         }
586         return NULL;
587 }
588
589 void mnt_closeclnt(CLIENT *clnt, int msock)
590 {
591         auth_destroy(clnt->cl_auth);
592         clnt_destroy(clnt);
593         close(msock);
594 }
595
596 /*
597  * Sigh... getport() doesn't actually check the version number.
598  * In order to make sure that the server actually supports the service
599  * we're requesting, we open and RPC client, and fire off a NULL
600  * RPC call.
601  */
602 int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
603                 const unsigned long vers, const unsigned int prot,
604                 struct sockaddr_in *caddr)
605 {
606         CLIENT *clnt = NULL;
607         int sock, stat;
608         static char clnt_res;
609         struct sockaddr dissolve;
610
611         rpc_createerr.cf_stat = stat = errno = 0;
612         sock = get_socket(saddr, prot, FALSE, TRUE);
613         if (sock == RPC_ANYSOCK) {
614                 if (errno == ETIMEDOUT) {
615                         /*
616                          * TCP timeout. Bubble up the error to see 
617                          * how it should be handled.
618                          */
619                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
620                 }
621                 return 0;
622         }
623
624         if (caddr) {
625                 /* Get the address of our end of this connection */
626                 socklen_t len = sizeof(*caddr);
627                 if (getsockname(sock, caddr, &len) != 0)
628                         caddr->sin_family = 0;
629         }
630
631         switch(prot) {
632         case IPPROTO_UDP:
633                 /* The socket is connected (so we could getsockname successfully),
634                  * but some servers on multi-homed hosts reply from
635                  * the wrong address, so if we stay connected, we lose the reply.
636                  */
637                 dissolve.sa_family = AF_UNSPEC;
638                 connect(sock, &dissolve, sizeof(dissolve));
639
640                 clnt = clntudp_bufcreate(saddr, prog, vers,
641                                          RETRY_TIMEOUT, &sock,
642                                          RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
643                 break;
644         case IPPROTO_TCP:
645                 clnt = clnttcp_create(saddr, prog, vers, &sock,
646                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
647                 break;
648         }
649         if (!clnt) {
650                 close(sock);
651                 return 0;
652         }
653         memset(&clnt_res, 0, sizeof(clnt_res));
654         stat = clnt_call(clnt, NULLPROC,
655                          (xdrproc_t)xdr_void, (caddr_t)NULL,
656                          (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
657                          TIMEOUT);
658         if (stat) {
659                 clnt_geterr(clnt, &rpc_createerr.cf_error);
660                 rpc_createerr.cf_stat = stat;
661         }
662         clnt_destroy(clnt);
663         close(sock);
664
665         if (stat == RPC_SUCCESS)
666                 return 1;
667         else
668                 return 0;
669 }