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