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>
36 #include "afs/sysincludes.h"
37 #include "afsincludes.h"
40 #include <sys/types.h>
42 #include <netinet/in.h>
44 #include <sys/errno.h>
51 #define AFS_IPINVALID 0xffffffff /* invalid IP address */
52 #define AFS_IPINVALIDIGNORE 0xfffffffe /* no input given to extractAddr */
53 #define MAX_NETFILE_LINE 2048 /* length of a line in the netrestrict file */
54 #define MAXIPADDRS 1024 /* from afsd.c */
56 #ifndef INADDR_LOOPBACK
57 #define INADDR_LOOPBACK (afs_uint32)0x7f000001
61 * The line parameter is a pointer to a buffer containing a string of
63 ** w.x.y.z # machineName
64 * returns the network interface IP Address in NBO
67 extract_Addr(char *line, int maxSize)
73 afs_uint32 retval = 0;
75 /* skip empty spaces */
76 while (isspace(*line) && maxSize) {
80 /* skip empty lines */
81 if (!maxSize || !*line)
82 return AFS_IPINVALIDIGNORE;
84 for (n = 0; n < 4; n++) {
85 while ((*line != '.') && !isspace(*line) && maxSize) { /* extract nth byte */
89 return AFS_IPINVALID; /* no space */
90 bytes[n][i++] = *line++;
98 val[n] = strtol(bytes[n], &endPtr, 10);
99 if ((val[n] == 0) && (errno != 0 || bytes[n] == endPtr)) /* no conversion */
100 return AFS_IPINVALID;
103 retval = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3];
104 return htonl(retval);
110 /* parseNetRestrictFile()
111 * Get a list of IP addresses for this host removing any address found
112 * in the config file (fileName parameter): /usr/vice/etc/NetRestrict
113 * for clients and /usr/afs/local/NetRestrict for servers.
115 * Returns the number of valid addresses in outAddrs[] and count in
116 * nAddrs. Returns 0 on success; or 1 if the config file was not
117 * there or empty (we still return the host's IP addresses). Returns
118 * -1 on fatal failure with reason in the reason argument (so the
119 * caller can choose to ignore the entire file but should write
120 * something to a log file).
122 * All addresses should be in NBO (as returned by rx_getAllAddr() and
123 * parsed by extract_Addr().
126 afs_uint32 outAddrs[]; * output address array *
127 afs_uint32 *mask, *mtu; * optional mask and mtu *
128 afs_uint32 maxAddrs; * max number of addresses *
129 afs_uint32 *nAddrs; * number of Addresses in output array *
130 char reason[]; * reason for failure *
131 const char *fileName; * filename to parse *
135 parseNetRestrictFile_int(afs_uint32 outAddrs[], afs_uint32 * mask,
136 afs_uint32 * mtu, afs_uint32 maxAddrs,
137 afs_uint32 * nAddrs, char reason[],
138 const char *fileName, const char *fileName_ni)
141 char line[MAX_NETFILE_LINE];
142 int lineNo, usedfile = 0;
143 afs_uint32 i, neaddrs, nOutaddrs;
144 afs_uint32 addr, eAddrs[MAXIPADDRS], eMask[MAXIPADDRS], eMtu[MAXIPADDRS];
155 for (i = 0; i < maxAddrs; i++)
159 /* get all network interfaces from the kernel */
160 neaddrs = rxi_getAllAddrMaskMtu(eAddrs, eMask, eMtu, MAXIPADDRS);
162 sprintf(reason, "No existing IP interfaces found");
166 if ((neaddrs < MAXIPADDRS) && fileName_ni)
167 i = ParseNetInfoFile_int(&(eAddrs[neaddrs]), &(eMask[neaddrs]),
168 &(eMtu[neaddrs]), MAXIPADDRS-neaddrs, reason,
174 if ((fp = fopen(fileName, "r")) == 0) {
175 sprintf(reason, "Could not open file %s for reading:%s", fileName,
180 /* For each line in the NetRestrict file */
183 while (fgets(line, MAX_NETFILE_LINE, fp) != NULL) {
184 lineNo++; /* input line number */
185 addr = extract_Addr(line, strlen(line));
186 if (addr == AFS_IPINVALID) { /* syntactically invalid */
187 fprintf(stderr, "%s : line %d : parse error - invalid IP\n",
191 if (addr == AFS_IPINVALIDIGNORE) { /* ignore error */
192 fprintf(stderr, "%s : line %d : invalid address ... ignoring\n",
198 /* Check if we need to exclude this address */
199 for (i = 0; i < neaddrs; i++) {
200 if (eAddrs[i] && (eAddrs[i] == addr)) {
201 eAddrs[i] = 0; /* Yes - exclude it by zeroing it for now */
209 sprintf(reason, "No valid IP addresses in %s\n", fileName);
214 /* Collect the addresses we have left to return */
216 for (i = 0; i < neaddrs; i++) {
219 outAddrs[nOutaddrs] = eAddrs[i];
221 mask[nOutaddrs] = eMask[i];
222 mtu[nOutaddrs] = eMtu[i];
224 if (++nOutaddrs >= maxAddrs)
227 if (nOutaddrs == 0) {
228 sprintf(reason, "No addresses to use after parsing %s", fileName);
232 return (usedfile ? 0 : 1); /* 0=>used the file. 1=>didn't use file */
236 parseNetRestrictFile(afs_uint32 outAddrs[], afs_uint32 * mask,
237 afs_uint32 * mtu, afs_uint32 maxAddrs,
238 afs_uint32 * nAddrs, char reason[],
239 const char *fileName)
241 return parseNetRestrictFile_int(outAddrs, mask, mtu, maxAddrs, nAddrs, reason, fileName, NULL);
245 * this function reads in stuff from InterfaceAddr file in
246 * /usr/vice/etc ( if it exists ) and verifies the addresses
248 * 'final' contains all those addresses that are found to
249 * be valid. This function returns the number of valid
250 * interface addresses. Pulled out from afsd.c
253 ParseNetInfoFile_int(afs_uint32 * final, afs_uint32 * mask, afs_uint32 * mtu,
254 int max, char reason[], const char *fileName,
258 afs_uint32 existingAddr[MAXIPADDRS], existingMask[MAXIPADDRS],
259 existingMtu[MAXIPADDRS];
260 char line[MAX_NETFILE_LINE];
262 int i, existNu, count = 0;
273 /* get all network interfaces from the kernel */
275 rxi_getAllAddrMaskMtu(existingAddr, existingMask, existingMtu,
280 if ((fp = fopen(fileName, "r")) == 0) {
281 /* If file does not exist or is not readable, then
282 * use all interface addresses.
285 "Failed to open %s(%s)\nUsing all configured addresses\n",
286 fileName, strerror(errno));
287 for (i = 0; i < existNu; i++) {
288 final[i] = existingAddr[i];
289 mask[i] = existingMask[i];
290 mtu[i] = existingMtu[i];
295 /* For each line in the NetInfo file */
296 while (fgets(line, MAX_NETFILE_LINE, fp) != NULL) {
299 /* See if first char is an 'F' for fake */
300 /* Added to allow the fileserver to advertise fake IPS for use with
301 * the translation tables for NAT-like firewalls - defect 12462 */
302 for (fake = 0; ((fake < strlen(line)) && isspace(line[fake]));
304 if ((fake < strlen(line))
305 && ((line[fake] == 'f') || (line[fake] == 'F'))) {
311 lineNo++; /* input line number */
312 addr = extract_Addr(&line[fake], strlen(&line[fake]));
314 if (addr == AFS_IPINVALID) { /* syntactically invalid */
315 fprintf(stderr, "afs:%s : line %d : parse error\n", fileName,
319 if (addr == AFS_IPINVALIDIGNORE) { /* ignore error */
323 /* See if it is an address that really exists */
324 for (i = 0; i < existNu; i++) {
325 if (existingAddr[i] == addr)
328 if ((i >= existNu) && (!fake))
329 continue; /* not found/fake - ignore */
331 /* Check if it is a duplicate address we alread have */
332 for (l = 0; l < count; l++) {
333 if (final[l] == addr)
337 fprintf(stderr, "afs:%x specified twice in NetInfo file\n",
339 continue; /* duplicate addr - ignore */
342 if (count > max) { /* no more space */
344 "afs:Too many interfaces. The current kernel configuration supports a maximum of %d interfaces\n",
348 fprintf(stderr, "Client (2) also has address %s\n", line);
350 mask[count] = 0xffffffff;
351 mtu[count] = htonl(1500);
353 } else if (!fakeonly) {
354 final[count] = existingAddr[i];
355 mask[count] = existingMask[i];
356 mtu[count] = existingMtu[i];
361 /* in case of any error, we use all the interfaces present */
364 "Error in reading/parsing Interface file\nUsing all configured interface addresses \n");
365 for (i = 0; i < existNu; i++) {
366 final[i] = existingAddr[i];
367 mask[i] = existingMask[i];
368 mtu[i] = existingMtu[i];
376 ParseNetInfoFile(afs_uint32 * final, afs_uint32 * mask, afs_uint32 * mtu,
377 int max, char reason[], const char *fileName)
379 return ParseNetInfoFile_int(final, mask, mtu, max, reason, fileName, 0);
383 * Given two arrays of addresses, masks and mtus find the common ones
384 * and return them in the first buffer. Return number of common
388 filterAddrs(afs_uint32 addr1[], afs_uint32 addr2[], afs_uint32 mask1[],
389 afs_uint32 mask2[], afs_uint32 mtu1[], afs_uint32 mtu2[], int n1,
392 afs_uint32 taddr[MAXIPADDRS];
393 afs_uint32 tmask[MAXIPADDRS];
394 afs_uint32 tmtu[MAXIPADDRS];
395 int count = 0, i = 0, j = 0, found = 0;
404 for (i = 0; i < n1; i++) {
406 for (j = 0; j < n2; j++) {
407 if (addr1[i] == addr2[j]) {
413 /* Always mask loopback address */
414 if (found && addr1[i] == INADDR_LOOPBACK)
418 taddr[count] = addr1[i];
419 tmask[count] = mask1[i];
420 tmtu[count] = mtu1[i];
424 /* copy everything into addr1, mask1 and mtu1 */
425 for (i = 0; i < count; i++) {
432 /* and zero out the rest */
433 for (i = count; i < n1; i++) {
444 * parse both netinfo and netrerstrict files and return the final
445 * set of IP addresses to use
447 /* max - Entries in addrbuf, maskbuf and mtubuf */
449 parseNetFiles(afs_uint32 addrbuf[], afs_uint32 maskbuf[], afs_uint32 mtubuf[],
450 afs_uint32 max, char reason[], const char *niFileName,
451 const char *nrFileName)
453 afs_uint32 addrbuf1[MAXIPADDRS], maskbuf1[MAXIPADDRS],
455 afs_uint32 addrbuf2[MAXIPADDRS], maskbuf2[MAXIPADDRS],
458 afs_uint32 nAddrs2 = 0;
462 ParseNetInfoFile(addrbuf1, maskbuf1, mtubuf1, MAXIPADDRS, reason,
465 parseNetRestrictFile_int(addrbuf2, maskbuf2, mtubuf2, MAXIPADDRS,
466 &nAddrs2, reason, nrFileName, niFileName);
467 if ((nAddrs1 < 0) && (code)) {
470 } else if ((nAddrs1 > 0) && (code)) {
471 /* netinfo succeeded and netrestrict failed */
472 for (i = 0; ((i < nAddrs1) && (i < max)); i++) {
473 addrbuf[i] = addrbuf1[i];
475 maskbuf[i] = maskbuf1[i];
476 mtubuf[i] = mtubuf1[i];
480 } else if ((!code) && (nAddrs1 < 0)) {
481 /* netrestrict succeeded and netinfo failed */
482 for (i = 0; ((i < nAddrs2) && (i < max)); i++) {
483 addrbuf[i] = addrbuf2[i];
485 maskbuf[i] = maskbuf2[i];
486 mtubuf[i] = mtubuf2[i];
490 } else if ((!code) && (nAddrs1 >= 0)) {
492 /* take the intersection of addrbuf1 and addrbuf2 */
494 filterAddrs(addrbuf1, addrbuf2, maskbuf1, maskbuf2, mtubuf1,
495 mtubuf2, nAddrs1, nAddrs2);
496 for (i = 0; ((i < code) && (i < max)); i++) {
497 addrbuf[i] = addrbuf1[i];
499 maskbuf[i] = maskbuf1[i];
500 mtubuf[i] = mtubuf1[i];