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>
16 #include <afs/param.h>
24 #include <afs/dirpath.h>
26 #include "cellconfig.h"
28 #define AFS_IPINVALID -1 /* invalid IP address */
29 #define AFS_IPINVALIDIGNORE -2 /* no input given to extractAddr */
30 #define MAX_NETFILE_LINE 2048 /* length of a line in the NetRestrict file */
31 #define MAXIPADDRS 1024 /* from afsd.c */
33 static int ParseNetInfoFile_int(afs_uint32
*, afs_uint32
*, afs_uint32
*,
34 int, char reason
[], const char *,
38 * The line parameter is a pointer to a buffer containing a string of
41 * w.x.y.z[/n] # machineName
43 * Returns an IPv4 address and mask in network byte order. Optionally,
44 * a '/' may be used to specify a subnet mask length.
47 * Pointer to a string of bytes
49 * Length to search in line for addresses
51 * IPv4 address in network byte order
53 * IPv4 subnet mask in network byte order, default to 0xffffffff
57 * @retval AFS_IPINVALID the address is invalid or parsing failed
58 * @retval AFS_IPINVALIDIGNORE blank line that can be ignored
61 extract_Addr(char *line
, int maxSize
, afs_uint32
*addr
, afs_uint32
*mask
)
69 /* skip empty spaces */
70 while (isspace(*line
) && maxSize
) {
74 /* skip empty lines */
75 if (!maxSize
|| !*line
)
76 return AFS_IPINVALIDIGNORE
;
78 /* init to 0.0.0.0 for strtol() */
79 for (n
= 0; n
< 4; n
++) {
84 for (n
= 0; n
< 4; n
++) {
85 while ((*line
!= '.') && !isspace(*line
)
86 && (*line
!= '/') && maxSize
) { /* extract nth byte */
90 return AFS_IPINVALID
; /* no space */
91 bytes
[n
][i
++] = *line
++;
104 ++line
; /* single trailing . allowed */
106 if (*line
== '/') { /* have a subnet length */
109 while (isdigit(*line
)) {
110 subnet_len
= subnet_len
* 10 + (*line
- '0');
112 return AFS_IPINVALID
; /* subnet length too long */
116 return AFS_IPINVALID
; /* subnet length too short */
119 if (!isspace(*line
) && (*line
!= '\0'))
120 return AFS_IPINVALID
; /* improperly formed comment */
122 for (n
= 0; n
< 4; n
++) {
124 val
[n
] = strtol(bytes
[n
], &endPtr
, 10);
125 if ((val
[n
] == 0) && (errno
!= 0 || bytes
[n
] == endPtr
)) /* no conversion */
126 return AFS_IPINVALID
;
130 while (subnet_len
--) {
131 *mask
= (*mask
>> 1) | 0x80000000;
134 *mask
= htonl(*mask
);
135 *addr
= htonl((val
[0] << 24) | (val
[1] << 16) | (val
[2] << 8) | val
[3]);
140 * Get a list of IP addresses for this host removing any address found
141 * in the config file (fileName parameter): /usr/vice/etc/NetRestrict
142 * for clients and /usr/afs/local/NetRestrict for servers.
144 * Returns the number of valid addresses in outAddrs[] and count in
145 * nAddrs. Returns 0 on success; or 1 if the config file was not
146 * there or empty (we still return the host's IP addresses). Returns
147 * -1 on fatal failure with reason in the reason argument (so the
148 * caller can choose to ignore the entire file but should write
149 * something to a log file).
151 * All addresses should be in network byte order as returned by
152 * rx_getAllAddrMaskMtu() and parsed by extract_Addr().
154 * @param[out] outAddrs
155 * All the address that are found to be valid.
156 * @param[out] outMask
157 * Optional associated netmask for address
159 * Optional associated MTU for address
160 * @param[in] maxAddres
161 * Length of the above output arrays
163 * Count of valid addresses
165 * Reason (if any) for the parsing failure
166 * @param[in] fileName
167 * Configuration file to parse
170 * 0 on success; 1 if the config file was not used; -1 on
174 parseNetRestrictFile_int(afs_uint32 outAddrs
[], afs_uint32 outMask
[],
175 afs_uint32 outMtu
[], afs_uint32 maxAddrs
,
176 afs_uint32
*nAddrs
, char reason
[],
177 const char *fileName
, const char *fileName_ni
)
180 char line
[MAX_NETFILE_LINE
];
181 int lineNo
, usedfile
= 0;
182 afs_uint32 i
, neaddrs
, nOutaddrs
;
183 afs_uint32 addr
, mask
, eAddrs
[MAXIPADDRS
], eMask
[MAXIPADDRS
], eMtu
[MAXIPADDRS
];
186 opr_Assert(outAddrs
);
188 opr_Assert(fileName
);
195 for (i
= 0; i
< maxAddrs
; i
++)
199 /* get all network interfaces from the kernel */
200 neaddrs
= rx_getAllAddrMaskMtu(eAddrs
, eMask
, eMtu
, MAXIPADDRS
);
202 sprintf(reason
, "No existing IP interfaces found");
206 if ((neaddrs
< MAXIPADDRS
) && fileName_ni
)
207 i
= ParseNetInfoFile_int(&(eAddrs
[neaddrs
]), &(eMask
[neaddrs
]),
208 &(eMtu
[neaddrs
]), MAXIPADDRS
-neaddrs
, reason
,
214 if ((fp
= fopen(fileName
, "r")) == 0) {
215 sprintf(reason
, "Could not open file %s for reading:%s", fileName
,
220 /* For each line in the NetRestrict file */
223 while (fgets(line
, MAX_NETFILE_LINE
, fp
) != NULL
) {
224 lineNo
++; /* input line number */
225 retval
= extract_Addr(line
, strlen(line
), &addr
, &mask
);
226 if (retval
== AFS_IPINVALID
) { /* syntactically invalid */
227 fprintf(stderr
, "%s : line %d : parse error - invalid IP\n",
231 if (retval
== AFS_IPINVALIDIGNORE
) { /* ignore error */
232 fprintf(stderr
, "%s : line %d : invalid address ... ignoring\n",
238 /* Check if we need to exclude this address */
239 for (i
= 0; i
< neaddrs
; i
++) {
240 if (eAddrs
[i
] && ((eAddrs
[i
] & mask
) == (addr
& mask
))) {
241 eAddrs
[i
] = 0; /* Yes - exclude it by zeroing it for now */
249 sprintf(reason
, "No valid IP addresses in %s\n", fileName
);
254 /* Collect the addresses we have left to return */
256 for (i
= 0; i
< neaddrs
; i
++) {
259 outAddrs
[nOutaddrs
] = eAddrs
[i
];
261 outMask
[nOutaddrs
] = eMask
[i
];
262 outMtu
[nOutaddrs
] = eMtu
[i
];
264 if (++nOutaddrs
>= maxAddrs
)
267 if (nOutaddrs
== 0) {
268 sprintf(reason
, "No addresses to use after parsing %s", fileName
);
272 return (usedfile
? 0 : 1); /* 0=>used the file. 1=>didn't use file */
276 afsconf_ParseNetRestrictFile(afs_uint32 outAddrs
[], afs_uint32 outMask
[],
277 afs_uint32 outMtu
[], afs_uint32 maxAddrs
,
278 afs_uint32
* nAddrs
, char reason
[],
279 const char *fileName
)
281 return parseNetRestrictFile_int(outAddrs
, outMask
, outMtu
, maxAddrs
, nAddrs
, reason
, fileName
, 0);
285 * Get a list of IP addresses for this host allowing only addresses found
286 * in the config file (fileName parameter): /usr/vice/etc/NetInfo for
287 * clients and /usr/afs/local/NetInfo for servers.
289 * All addresses should be in network byte order as returned by
290 * rx_getAllAddrMaskMtu() and parsed by extract_Addr().
292 * @param[out] outAddrs
293 * All the address that are found to be valid.
294 * @param[out] outMask
295 * Associated netmask for interface
297 * Associated MTU for interface
299 * Length of the output above arrays
301 * Reason for the parsing failure
302 * @param[in] fileName
304 * @param[in] fakeonly
305 * Only return addresses if they are marked as fake
308 * The number of valid address on success or < 0 on fatal failure.
311 ParseNetInfoFile_int(afs_uint32 outAddrs
[], afs_uint32 outMask
[], afs_uint32 outMtu
[],
312 int max
, char reason
[], const char *fileName
,
316 afs_uint32 existingAddr
[MAXIPADDRS
], existingMask
[MAXIPADDRS
],
317 existingMtu
[MAXIPADDRS
];
318 char line
[MAX_NETFILE_LINE
];
320 int i
, existNu
, count
= 0;
321 afs_uint32 addr
, mask
;
326 opr_Assert(fileName
);
327 opr_Assert(outAddrs
);
332 /* get all network interfaces from the kernel */
334 rx_getAllAddrMaskMtu(existingAddr
, existingMask
, existingMtu
,
339 if ((fp
= fopen(fileName
, "r")) == 0) {
340 /* If file does not exist or is not readable, then
341 * use all interface addresses.
344 "Failed to open %s(%s)\nUsing all configured addresses\n",
345 fileName
, strerror(errno
));
346 for (i
= 0; i
< existNu
; i
++) {
347 outAddrs
[i
] = existingAddr
[i
];
348 outMask
[i
] = existingMask
[i
];
349 outMtu
[i
] = existingMtu
[i
];
354 /* For each line in the NetInfo file */
355 while (fgets(line
, MAX_NETFILE_LINE
, fp
) != NULL
) {
358 /* See if first char is an 'F' for fake */
359 /* Added to allow the fileserver to advertise fake IPS for use with
360 * the translation tables for NAT-like firewalls - defect 12462 */
361 for (fake
= 0; ((fake
< strlen(line
)) && isspace(line
[fake
]));
363 if ((fake
< strlen(line
))
364 && ((line
[fake
] == 'f') || (line
[fake
] == 'F'))) {
370 lineNo
++; /* input line number */
371 retval
= extract_Addr(&line
[fake
], strlen(&line
[fake
]), &addr
, &mask
);
373 if (retval
== AFS_IPINVALID
) { /* syntactically invalid */
374 fprintf(stderr
, "afs:%s : line %d : parse error\n", fileName
,
378 if (fake
&& ntohl(mask
) != 0xffffffff) {
379 fprintf(stderr
, "afs:%s : line %d : bad fake address\n", fileName
,
383 if (retval
== AFS_IPINVALIDIGNORE
) { /* ignore error */
387 /* See if it is an address that really exists */
388 for (i
= 0; i
< existNu
; i
++) {
389 if ((existingAddr
[i
] & mask
) == (addr
& mask
))
392 if ((i
>= existNu
) && (!fake
))
393 continue; /* not found/fake - ignore */
395 /* Check if it is a duplicate address we alread have */
396 for (l
= 0; l
< count
; l
++) {
397 if ((outAddrs
[l
] & mask
) == (addr
& mask
))
401 fprintf(stderr
, "afs:%x matched more than once in NetInfo file\n",
403 continue; /* duplicate addr - ignore */
406 if (count
> max
) { /* no more space */
408 "afs:Too many interfaces. The current kernel configuration supports a maximum of %d interfaces\n",
412 fprintf(stderr
, "Client (2) also has address %s\n", line
);
413 outAddrs
[count
] = addr
;
414 outMask
[count
] = 0xffffffff;
415 outMtu
[count
] = htonl(1500);
417 } else if (!fakeonly
) {
418 outAddrs
[count
] = existingAddr
[i
];
419 outMask
[count
] = existingMask
[i
];
420 outMtu
[count
] = existingMtu
[i
];
425 /* in case of any error, we use all the interfaces present */
428 "Error in reading/parsing Interface file\nUsing all configured interface addresses \n");
429 for (i
= 0; i
< existNu
; i
++) {
430 outAddrs
[i
] = existingAddr
[i
];
431 outMask
[i
] = existingMask
[i
];
432 outMtu
[i
] = existingMtu
[i
];
440 afsconf_ParseNetInfoFile(afs_uint32 outAddrs
[], afs_uint32 outMask
[], afs_uint32 outMtu
[],
441 int max
, char reason
[], const char *fileName
)
443 return ParseNetInfoFile_int(outAddrs
, outMask
, outMtu
, max
, reason
, fileName
, 0);
447 * Given two arrays of addresses, masks and mtus find the common ones
448 * and return them in the first buffer. Return number of common
452 filterAddrs(afs_uint32 addr1
[], afs_uint32 addr2
[], afs_uint32 mask1
[],
453 afs_uint32 mask2
[], afs_uint32 mtu1
[], afs_uint32 mtu2
[], int n1
,
456 afs_uint32 taddr
[MAXIPADDRS
];
457 afs_uint32 tmask
[MAXIPADDRS
];
458 afs_uint32 tmtu
[MAXIPADDRS
];
459 int count
= 0, i
= 0, j
= 0, found
= 0;
468 for (i
= 0; i
< n1
; i
++) {
470 for (j
= 0; j
< n2
; j
++) {
471 if (addr1
[i
] == addr2
[j
]) {
477 /* Always mask loopback address */
478 if (found
&& rx_IsLoopbackAddr(addr1
[i
]))
482 taddr
[count
] = addr1
[i
];
483 tmask
[count
] = mask1
[i
];
484 tmtu
[count
] = mtu1
[i
];
488 /* copy everything into addr1, mask1 and mtu1 */
489 for (i
= 0; i
< count
; i
++) {
496 /* and zero out the rest */
497 for (i
= count
; i
< n1
; i
++) {
508 * parse both NetInfo and NetRestrict files and return the final
509 * set of IP addresses to use
511 /* max - Entries in addrbuf, maskbuf and mtubuf */
513 afsconf_ParseNetFiles(afs_uint32 addrbuf
[], afs_uint32 maskbuf
[],
514 afs_uint32 mtubuf
[], afs_uint32 max
, char reason
[],
515 const char *niFileName
, const char *nrFileName
)
517 afs_uint32 addrbuf1
[MAXIPADDRS
], maskbuf1
[MAXIPADDRS
],
519 afs_uint32 addrbuf2
[MAXIPADDRS
], maskbuf2
[MAXIPADDRS
],
522 afs_uint32 nAddrs2
= 0;
526 afsconf_ParseNetInfoFile(addrbuf1
, maskbuf1
, mtubuf1
, MAXIPADDRS
,
529 parseNetRestrictFile_int(addrbuf2
, maskbuf2
, mtubuf2
, MAXIPADDRS
,
530 &nAddrs2
, reason
, nrFileName
, niFileName
);
531 if ((nAddrs1
< 0) && (code
)) {
534 } else if ((nAddrs1
> 0) && (code
)) {
535 /* NetInfo succeeded and NetRestrict failed */
536 for (i
= 0; ((i
< nAddrs1
) && (i
< max
)); i
++) {
537 addrbuf
[i
] = addrbuf1
[i
];
539 maskbuf
[i
] = maskbuf1
[i
];
540 mtubuf
[i
] = mtubuf1
[i
];
544 } else if ((!code
) && (nAddrs1
< 0)) {
545 /* NetRestrict succeeded and NetInfo failed */
546 for (i
= 0; ((i
< nAddrs2
) && (i
< max
)); i
++) {
547 addrbuf
[i
] = addrbuf2
[i
];
549 maskbuf
[i
] = maskbuf2
[i
];
550 mtubuf
[i
] = mtubuf2
[i
];
554 } else if ((!code
) && (nAddrs1
>= 0)) {
556 /* take the intersection of addrbuf1 and addrbuf2 */
558 filterAddrs(addrbuf1
, addrbuf2
, maskbuf1
, maskbuf2
, mtubuf1
,
559 mtubuf2
, nAddrs1
, nAddrs2
);
560 for (i
= 0; ((i
< code
) && (i
< max
)); i
++) {
561 addrbuf
[i
] = addrbuf1
[i
];
563 maskbuf
[i
] = maskbuf1
[i
];
564 mtubuf
[i
] = mtubuf1
[i
];