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