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