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