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