Consolidate loopback address tests
[openafs.git] / src / util / netutils.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Network utility functions
12  * Parsing NetRestrict file and filtering IP addresses
13  */
14
15 #include <afsconfig.h>
16 #ifdef KERNEL
17 #include "afs/param.h"
18 #else
19 #include <afs/param.h>
20 #endif
21
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 #ifdef KERNEL
28 #include "afs/sysincludes.h"
29 #include "afsincludes.h"
30 #else
31 #ifdef AFS_NT40_ENV
32 #include <winsock2.h>
33 #else 
34 #ifdef __FreeBSD__
35 #include <sys/types.h>
36 #endif
37 #include <netinet/in.h>
38 #include <sys/errno.h>
39 #endif
40 #include <errno.h>
41 #endif
42
43 #include <rx/rx.h>
44
45 #include "assert.h"
46 #include "afsutil.h"
47 #include "dirpath.h"
48
49 #define AFS_IPINVALID        0xffffffff /* invalid IP address */
50 #define AFS_IPINVALIDIGNORE  0xfffffffe /* no input given to extractAddr */
51 #define MAX_NETFILE_LINE       2048     /* length of a line in the netrestrict file */
52 #define MAXIPADDRS             1024     /* from afsd.c */
53
54 int ParseNetInfoFile_int(afs_uint32 *, afs_uint32 *, afs_uint32 *,
55                          int, char reason[], const char *,
56                          int);
57 /* 
58  * The line parameter is a pointer to a buffer containing a string of 
59  * bytes of the form 
60 ** w.x.y.z      # machineName
61  * returns the network interface IP Address in NBO
62  */
63 afs_uint32
64 extract_Addr(char *line, int maxSize)
65 {
66     char bytes[4][32];
67     int i = 0, n = 0;
68     char *endPtr;
69     afs_uint32 val[4];
70     afs_uint32 retval = 0;
71
72     /* skip empty spaces */
73     while (isspace(*line) && maxSize) {
74         line++;
75         maxSize--;
76     }
77     /* skip empty lines */
78     if (!maxSize || !*line)
79         return AFS_IPINVALIDIGNORE;
80
81     for (n = 0; n < 4; n++) {
82         while ((*line != '.') && !isspace(*line) && maxSize) {  /* extract nth byte */
83             if (!isdigit(*line))
84                 return AFS_IPINVALID;
85             if (i > 31)
86                 return AFS_IPINVALID;   /* no space */
87             bytes[n][i++] = *line++;
88             maxSize--;
89         }                       /* while */
90         if (!maxSize)
91             return AFS_IPINVALID;
92         bytes[n][i] = 0;
93         i = 0, line++;
94         errno = 0;
95         val[n] = strtol(bytes[n], &endPtr, 10);
96         if ((val[n] == 0) && (errno != 0 || bytes[n] == endPtr))        /* no conversion */
97             return AFS_IPINVALID;
98     }                           /* for */
99
100     retval = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3];
101     return htonl(retval);
102 }
103
104
105
106
107 /* parseNetRestrictFile()
108  * Get a list of IP addresses for this host removing any address found
109  * in the config file (fileName parameter): /usr/vice/etc/NetRestrict
110  * for clients and /usr/afs/local/NetRestrict for servers.  
111  *
112  * Returns the number of valid addresses in outAddrs[] and count in
113  * nAddrs.  Returns 0 on success; or 1 if the config file was not
114  * there or empty (we still return the host's IP addresses). Returns
115  * -1 on fatal failure with reason in the reason argument (so the
116  * caller can choose to ignore the entire file but should write
117  * something to a log file).
118  *
119  * All addresses should be in NBO (as returned by rx_getAllAddrMaskMtu() and
120  * parsed by extract_Addr().
121  */
122 /*
123   afs_uint32  outAddrs[];          * output address array *
124   afs_uint32  *mask, *mtu;         * optional mask and mtu *
125   afs_uint32 maxAddrs;             * max number of addresses *
126   afs_uint32 *nAddrs;              * number of Addresses in output array *
127   char       reason[];             * reason for failure *
128   const char *fileName;            * filename to parse *
129 */
130
131 int
132 parseNetRestrictFile_int(afs_uint32 outAddrs[], afs_uint32 * mask,
133                          afs_uint32 * mtu, afs_uint32 maxAddrs,
134                          afs_uint32 * nAddrs, char reason[], 
135                          const char *fileName, const char *fileName_ni)
136 {
137     FILE *fp;
138     char line[MAX_NETFILE_LINE];
139     int lineNo, usedfile = 0;
140     afs_uint32 i, neaddrs, nOutaddrs;
141     afs_uint32 addr, eAddrs[MAXIPADDRS], eMask[MAXIPADDRS], eMtu[MAXIPADDRS];
142
143     assert(outAddrs);
144     assert(reason);
145     assert(fileName);
146     assert(nAddrs);
147     if (mask)
148         assert(mtu);
149
150     /* Initialize */
151     *nAddrs = 0;
152     for (i = 0; i < maxAddrs; i++)
153         outAddrs[i] = 0;
154     strcpy(reason, "");
155
156     /* get all network interfaces from the kernel */
157     neaddrs = rx_getAllAddrMaskMtu(eAddrs, eMask, eMtu, MAXIPADDRS);
158     if (neaddrs <= 0) {
159         sprintf(reason, "No existing IP interfaces found");
160         return -1;
161     }
162     i = 0;
163     if ((neaddrs < MAXIPADDRS) && fileName_ni) 
164         i = ParseNetInfoFile_int(&(eAddrs[neaddrs]), &(eMask[neaddrs]), 
165                                  &(eMtu[neaddrs]), MAXIPADDRS-neaddrs, reason,
166                                  fileName_ni, 1);
167
168     if (i > 0)
169         neaddrs += i;
170
171     if ((fp = fopen(fileName, "r")) == 0) {
172         sprintf(reason, "Could not open file %s for reading:%s", fileName,
173                 strerror(errno));
174         goto done;
175     }
176
177     /* For each line in the NetRestrict file */
178     lineNo = 0;
179     usedfile = 0;
180     while (fgets(line, MAX_NETFILE_LINE, fp) != NULL) {
181         lineNo++;               /* input line number */
182         addr = extract_Addr(line, strlen(line));
183         if (addr == AFS_IPINVALID) {    /* syntactically invalid */
184             fprintf(stderr, "%s : line %d : parse error - invalid IP\n",
185                     fileName, lineNo);
186             continue;
187         }
188         if (addr == AFS_IPINVALIDIGNORE) {      /* ignore error */
189             fprintf(stderr, "%s : line %d : invalid address ... ignoring\n",
190                     fileName, lineNo);
191             continue;
192         }
193         usedfile = 1;
194
195         /* Check if we need to exclude this address */
196         for (i = 0; i < neaddrs; i++) {
197             if (eAddrs[i] && (eAddrs[i] == addr)) {
198                 eAddrs[i] = 0;  /* Yes - exclude it by zeroing it for now */
199             }
200         }
201     }                           /* while */
202
203     fclose(fp);
204
205     if (!usedfile) {
206         sprintf(reason, "No valid IP addresses in %s\n", fileName);
207         goto done;
208     }
209
210   done:
211     /* Collect the addresses we have left to return */
212     nOutaddrs = 0;
213     for (i = 0; i < neaddrs; i++) {
214         if (!eAddrs[i])
215             continue;
216         outAddrs[nOutaddrs] = eAddrs[i];
217         if (mask) {
218             mask[nOutaddrs] = eMask[i];
219             mtu[nOutaddrs] = eMtu[i];
220         }
221         if (++nOutaddrs >= maxAddrs)
222             break;
223     }
224     if (nOutaddrs == 0) {
225         sprintf(reason, "No addresses to use after parsing %s", fileName);
226         return -1;
227     }
228     *nAddrs = nOutaddrs;
229     return (usedfile ? 0 : 1);  /* 0=>used the file.  1=>didn't use file */
230 }
231
232 int
233 parseNetRestrictFile(afs_uint32 outAddrs[], afs_uint32 * mask,
234                          afs_uint32 * mtu, afs_uint32 maxAddrs,
235                          afs_uint32 * nAddrs, char reason[], 
236                          const char *fileName)
237 {
238     return parseNetRestrictFile_int(outAddrs, mask, mtu, maxAddrs, nAddrs, reason, fileName, NULL);
239 }
240
241 /*
242  * this function reads in stuff from InterfaceAddr file in
243  * /usr/vice/etc ( if it exists ) and verifies the addresses
244  * specified. 
245  * 'final' contains all those addresses that are found to 
246  * be valid. This function returns the number of valid
247  * interface addresses. Pulled out from afsd.c
248  */
249 int
250 ParseNetInfoFile_int(afs_uint32 * final, afs_uint32 * mask, afs_uint32 * mtu,
251                      int max, char reason[], const char *fileName, 
252                      int fakeonly)
253 {
254
255     afs_uint32 existingAddr[MAXIPADDRS], existingMask[MAXIPADDRS],
256         existingMtu[MAXIPADDRS];
257     char line[MAX_NETFILE_LINE];
258     FILE *fp;
259     int i, existNu, count = 0;
260     afs_uint32 addr;
261     int lineNo = 0;
262     int l;
263
264     assert(fileName);
265     assert(final);
266     assert(mask);
267     assert(mtu);
268     assert(reason);
269
270     /* get all network interfaces from the kernel */
271     existNu =
272         rx_getAllAddrMaskMtu(existingAddr, existingMask, existingMtu,
273                               MAXIPADDRS);
274     if (existNu < 0)
275         return existNu;
276
277     if ((fp = fopen(fileName, "r")) == 0) {
278         /* If file does not exist or is not readable, then
279          * use all interface addresses.
280          */
281         sprintf(reason,
282                 "Failed to open %s(%s)\nUsing all configured addresses\n",
283                 fileName, strerror(errno));
284         for (i = 0; i < existNu; i++) {
285             final[i] = existingAddr[i];
286             mask[i] = existingMask[i];
287             mtu[i] = existingMtu[i];
288         }
289         return existNu;
290     }
291
292     /* For each line in the NetInfo file */
293     while (fgets(line, MAX_NETFILE_LINE, fp) != NULL) {
294         int fake = 0;
295
296         /* See if first char is an 'F' for fake */
297         /* Added to allow the fileserver to advertise fake IPS for use with
298          * the translation tables for NAT-like firewalls - defect 12462 */
299         for (fake = 0; ((fake < strlen(line)) && isspace(line[fake]));
300              fake++);
301         if ((fake < strlen(line))
302             && ((line[fake] == 'f') || (line[fake] == 'F'))) {
303             fake++;
304         } else {
305             fake = 0;
306         }
307
308         lineNo++;               /* input line number */
309         addr = extract_Addr(&line[fake], strlen(&line[fake]));
310
311         if (addr == AFS_IPINVALID) {    /* syntactically invalid */
312             fprintf(stderr, "afs:%s : line %d : parse error\n", fileName,
313                     lineNo);
314             continue;
315         }
316         if (addr == AFS_IPINVALIDIGNORE) {      /* ignore error */
317             continue;
318         }
319
320         /* See if it is an address that really exists */
321         for (i = 0; i < existNu; i++) {
322             if (existingAddr[i] == addr)
323                 break;
324         }
325         if ((i >= existNu) && (!fake))
326             continue;           /* not found/fake - ignore */
327
328         /* Check if it is a duplicate address we alread have */
329         for (l = 0; l < count; l++) {
330             if (final[l] == addr)
331                 break;
332         }
333         if (l < count) {
334             fprintf(stderr, "afs:%x specified twice in NetInfo file\n",
335                     ntohl(addr));
336             continue;           /* duplicate addr - ignore */
337         }
338
339         if (count > max) {      /* no more space */
340             fprintf(stderr,
341                     "afs:Too many interfaces. The current kernel configuration supports a maximum of %d interfaces\n",
342                     max);
343         } else if (fake) {
344             if (!fake) 
345                 fprintf(stderr, "Client (2) also has address %s\n", line);
346             final[count] = addr;
347             mask[count] = 0xffffffff;
348             mtu[count] = htonl(1500);
349             count++;
350         } else if (!fakeonly) {
351             final[count] = existingAddr[i];
352             mask[count] = existingMask[i];
353             mtu[count] = existingMtu[i];
354             count++;
355         }
356     }                           /* while */
357
358     /* in case of any error, we use all the interfaces present */
359     if (count <= 0) {
360         sprintf(reason,
361                 "Error in reading/parsing Interface file\nUsing all configured interface addresses \n");
362         for (i = 0; i < existNu; i++) {
363             final[i] = existingAddr[i];
364             mask[i] = existingMask[i];
365             mtu[i] = existingMtu[i];
366         }
367         return existNu;
368     }
369     return count;
370 }
371
372 int
373 ParseNetInfoFile(afs_uint32 * final, afs_uint32 * mask, afs_uint32 * mtu,
374                  int max, char reason[], const char *fileName)
375 {
376     return ParseNetInfoFile_int(final, mask, mtu, max, reason, fileName, 0);
377 }
378
379 /*
380  * Given two arrays of addresses, masks and mtus find the common ones
381  * and return them in the first buffer. Return number of common
382  * entries.
383  */
384 int
385 filterAddrs(afs_uint32 addr1[], afs_uint32 addr2[], afs_uint32 mask1[],
386             afs_uint32 mask2[], afs_uint32 mtu1[], afs_uint32 mtu2[], int n1,
387             int n2)
388 {
389     afs_uint32 taddr[MAXIPADDRS];
390     afs_uint32 tmask[MAXIPADDRS];
391     afs_uint32 tmtu[MAXIPADDRS];
392     int count = 0, i = 0, j = 0, found = 0;
393
394     assert(addr1);
395     assert(addr2);
396     assert(mask1);
397     assert(mask2);
398     assert(mtu1);
399     assert(mtu2);
400
401     for (i = 0; i < n1; i++) {
402         found = 0;
403         for (j = 0; j < n2; j++) {
404             if (addr1[i] == addr2[j]) {
405                 found = 1;
406                 break;
407             }
408         }
409
410         /* Always mask loopback address */
411         if (found && rx_IsLoopbackAddr(addr1[i]))
412             found = 0;
413
414         if (found) {
415             taddr[count] = addr1[i];
416             tmask[count] = mask1[i];
417             tmtu[count] = mtu1[i];
418             count++;
419         }
420     }
421     /* copy everything into addr1, mask1 and mtu1 */
422     for (i = 0; i < count; i++) {
423         addr1[i] = taddr[i];
424         if (mask1) {
425             mask1[i] = tmask[i];
426             mtu1[i] = tmtu[i];
427         }
428     }
429     /* and zero out the rest */
430     for (i = count; i < n1; i++) {
431         addr1[i] = 0;
432         if (mask1) {
433             mask1[i] = 0;
434             mtu1[i] = 0;
435         }
436     }
437     return count;
438 }
439
440 /*
441  * parse both netinfo and netrerstrict files and return the final
442  * set of IP addresses to use
443  */
444 /* max - Entries in addrbuf, maskbuf and mtubuf */
445 int
446 parseNetFiles(afs_uint32 addrbuf[], afs_uint32 maskbuf[], afs_uint32 mtubuf[],
447               afs_uint32 max, char reason[], const char *niFileName,
448               const char *nrFileName)
449 {
450     afs_uint32 addrbuf1[MAXIPADDRS], maskbuf1[MAXIPADDRS],
451         mtubuf1[MAXIPADDRS];
452     afs_uint32 addrbuf2[MAXIPADDRS], maskbuf2[MAXIPADDRS],
453         mtubuf2[MAXIPADDRS];
454     int nAddrs1 = 0;
455     afs_uint32 nAddrs2 = 0;
456     int code, i;
457
458     nAddrs1 =
459         ParseNetInfoFile(addrbuf1, maskbuf1, mtubuf1, MAXIPADDRS, reason,
460                          niFileName);
461     code =
462         parseNetRestrictFile_int(addrbuf2, maskbuf2, mtubuf2, MAXIPADDRS,
463                              &nAddrs2, reason, nrFileName, niFileName);
464     if ((nAddrs1 < 0) && (code)) {
465         /* both failed */
466         return -1;
467     } else if ((nAddrs1 > 0) && (code)) {
468         /* netinfo succeeded and netrestrict failed */
469         for (i = 0; ((i < nAddrs1) && (i < max)); i++) {
470             addrbuf[i] = addrbuf1[i];
471             if (maskbuf) {
472                 maskbuf[i] = maskbuf1[i];
473                 mtubuf[i] = mtubuf1[i];
474             }
475         }
476         return i;
477     } else if ((!code) && (nAddrs1 < 0)) {
478         /* netrestrict succeeded and netinfo failed */
479         for (i = 0; ((i < nAddrs2) && (i < max)); i++) {
480             addrbuf[i] = addrbuf2[i];
481             if (maskbuf) {
482                 maskbuf[i] = maskbuf2[i];
483                 mtubuf[i] = mtubuf2[i];
484             }
485         }
486         return i;
487     } else if ((!code) && (nAddrs1 >= 0)) {
488         /* both succeeded */
489         /* take the intersection of addrbuf1 and addrbuf2 */
490         code =
491             filterAddrs(addrbuf1, addrbuf2, maskbuf1, maskbuf2, mtubuf1,
492                         mtubuf2, nAddrs1, nAddrs2);
493         for (i = 0; ((i < code) && (i < max)); i++) {
494             addrbuf[i] = addrbuf1[i];
495             if (maskbuf) {
496                 maskbuf[i] = maskbuf1[i];
497                 mtubuf[i] = mtubuf1[i];
498             }
499         }
500         return i;
501     }
502     return 0;
503 }