2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Network utility functions
12 * Parsing NetRestrict file and filtering IP addresses
15 #include <afsconfig.h>
17 #include "afs/param.h"
19 #include <afs/param.h>
35 #include "afs/sysincludes.h"
36 #include "afsincludes.h"
39 #include <sys/types.h>
41 #include <netinet/in.h>
43 #include <sys/errno.h>
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 */
56 * The line parameter is a pointer to a buffer containing a string of
58 ** w.x.y.z # machineName
59 * returns the network interface IP Address in NBO
61 afs_uint32 extract_Addr(char *line, int maxSize)
69 /* skip empty spaces */
70 while ( isspace(*line) && maxSize ) {
74 /* skip empty lines */
75 if ( !maxSize || !*line ) return AFS_IPINVALIDIGNORE;
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++;
84 if ( !maxSize ) return AFS_IPINVALID;
88 val[n] = strtol(bytes[n], &endPtr, 10);
89 if (( val[n]== 0 ) && ( errno != 0 || bytes[n] == endPtr)) /* no conversion */
93 retval = ( val[0] << 24 ) | ( val[1] << 16 ) | ( val[2] << 8 ) | val[3];
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.
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).
112 * All addresses should be in NBO (as returned by rx_getAllAddr() and
113 * parsed by extract_Addr().
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 *
124 int parseNetRestrictFile(afs_uint32 outAddrs[], afs_uint32 *mask, afs_uint32 *mtu,
125 afs_uint32 maxAddrs, afs_uint32 *nAddrs, char reason[], const char *fileName)
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];
137 if (mask) assert(mtu);
141 for (i=0; i<maxAddrs; i++) outAddrs[i] = 0;
144 /* get all network interfaces from the kernel */
145 neaddrs = rxi_getAllAddrMaskMtu(eAddrs, eMask, eMtu, MAXIPADDRS);
147 sprintf(reason,"No existing IP interfaces found");
151 if ( (fp = fopen(fileName, "r")) == 0 ) {
152 sprintf(reason, "Could not open file %s for reading:%s",
153 fileName, strerror(errno));
157 /* For each line in the NetRestrict file */
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);
167 if (addr == AFS_IPINVALIDIGNORE) { /* ignore error */
168 fprintf(stderr, "%s : line %d : invalid address ... ignoring\n",fileName, lineNo);
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 */
184 sprintf(reason,"No valid IP addresses in %s\n",fileName);
189 /* Collect the addresses we have left to return */
191 for (i=0; i<neaddrs; i++) {
192 if (!eAddrs[i]) continue;
193 outAddrs[nOutaddrs] = eAddrs[i];
195 mask[nOutaddrs] = eMask[i];
196 mtu[nOutaddrs] = eMtu[i];
198 if (++nOutaddrs >= maxAddrs) break;
200 if (nOutaddrs == 0) {
201 sprintf(reason, "No addresses to use after parsing %s",fileName);
205 return (usedfile ? 0 : 1); /* 0=>used the file. 1=>didn't use file */
211 * this function reads in stuff from InterfaceAddr file in
212 * /usr/vice/etc ( if it exists ) and verifies the addresses
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
218 int ParseNetInfoFile(afs_uint32 *final, afs_uint32 *mask, afs_uint32 *mtu,
219 int max, char reason[], const char *fileName)
222 afs_uint32 existingAddr[MAXIPADDRS], existingMask[MAXIPADDRS], existingMtu[MAXIPADDRS];
223 char line[MAX_NETFILE_LINE];
225 int i, existNu, count = 0;
236 /* get all network interfaces from the kernel */
237 existNu = rxi_getAllAddrMaskMtu(existingAddr,existingMask,existingMtu,MAXIPADDRS);
241 if ( (fp = fopen(fileName, "r")) == 0 ) {
242 /* If file does not exist or is not readable, then
243 * use all interface addresses.
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];
255 /* For each line in the NetInfo file */
256 while ( fgets(line, MAX_NETFILE_LINE, fp) != NULL ) {
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'))) {
269 lineNo++; /* input line number */
270 addr = extract_Addr(&line[fake], strlen(&line[fake]));
272 if (addr == AFS_IPINVALID) { /* syntactically invalid */
273 fprintf(stderr,"afs:%s : line %d : parse error\n", fileName, lineNo);
276 if (addr == AFS_IPINVALIDIGNORE) { /* ignore error */
280 /* See if it is an address that really exists */
281 for (i=0; i < existNu; i++) {
282 if (existingAddr[i] == addr) break;
284 if ((i >= existNu) && (!fake)) continue; /* not found/fake - ignore */
286 /* Check if it is a duplicate address we alread have */
287 for (l=0; l < count; l++) {
288 if ( final[l] == addr ) break;
291 fprintf(stderr,"afs:%x specified twice in NetInfo file\n", ntohl(addr));
292 continue; /* duplicate addr - ignore */
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);
298 fprintf(stderr, "Client (2) also has address %s\n", line);
300 mask[count] = 0xffffffff;
301 mtu[count] = htonl(1500);
304 final[count] = existingAddr[i];
305 mask[count] = existingMask[i];
306 mtu[count] = existingMtu[i];
311 /* in case of any error, we use all the interfaces present */
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];
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
331 int filterAddrs(afs_uint32 addr1[], afs_uint32 addr2[],
332 afs_uint32 mask1[], afs_uint32 mask2[],
333 afs_uint32 mtu1[], afs_uint32 mtu2[],
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;
351 if(addr1[i]==addr2[j]) {
357 taddr[count]=addr1[i];
358 tmask[count]=mask1[i];
363 /* copy everything into addr1, mask1 and mtu1 */
364 for(i=0;i<count;i++) {
371 /* and zero out the rest */
372 for(i=count;i<n1;i++) {
383 * parse both netinfo and netrerstrict files and return the final
384 * set of IP addresses to use
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)
390 afs_uint32 addrbuf1[MAXIPADDRS],maskbuf1[MAXIPADDRS], mtubuf1[MAXIPADDRS];
391 afs_uint32 addrbuf2[MAXIPADDRS],maskbuf2[MAXIPADDRS], mtubuf2[MAXIPADDRS];
393 afs_uint32 nAddrs2=0;
396 nAddrs1 = ParseNetInfoFile(addrbuf1, maskbuf1, mtubuf1, MAXIPADDRS,reason,
398 code = parseNetRestrictFile(addrbuf2,maskbuf2,mtubuf2,
399 MAXIPADDRS,&nAddrs2,reason,
401 if ((nAddrs1 < 0) && (code)) {
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];
410 maskbuf[i]=maskbuf1[i];
411 mtubuf[i]=mtubuf1[i];
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];
421 maskbuf[i]=maskbuf2[i];
422 mtubuf[i]=mtubuf2[i];
427 else if ((!code) && (nAddrs1 >= 0)) {
429 /* take the intersection of addrbuf1 and addrbuf2 */
430 code=filterAddrs(addrbuf1,addrbuf2,maskbuf1,maskbuf2,mtubuf1,mtubuf2,
432 for(i=0;((i<code)&&(i<max));i++) {
433 addrbuf[i]=addrbuf1[i];
435 maskbuf[i]=maskbuf1[i];
436 mtubuf[i]=mtubuf1[i];