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