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