From 3c7a315b635fc4ee2118ee541f1169cf147622d5 Mon Sep 17 00:00:00 2001 From: "Chas Williams (CONTRACTOR)" Date: Mon, 7 Jul 2014 09:55:44 -0400 Subject: [PATCH] auth: Allow subnet ranges in NetInfo and NetRestrict Add the ability to specify a range of addresses in both NetInfo and NetRestrict. Change-Id: Iecdcca8587aa2e6e7cd56cbbebb63eb41b5d6f40 Reviewed-on: https://gerrit.openafs.org/11313 Reviewed-by: Daria Phoebe Brashear Reviewed-by: Benjamin Kaduk Tested-by: BuildBot --- doc/man-pages/pod5/NetInfo.pod | 14 ++-- doc/man-pages/pod5/NetRestrict.pod | 19 ++++- doc/xml/AdminGuide/auagd008.xml | 6 +- doc/xml/AdminGuide/auagd015.xml | 6 +- src/auth/netrestrict.c | 123 +++++++++++++++++++++------- src/auth/test/Makefile.in | 5 +- src/auth/test/testnetrestrict.c | 125 +++++++++++++++++++++++++++++ 7 files changed, 252 insertions(+), 46 deletions(-) create mode 100644 src/auth/test/testnetrestrict.c diff --git a/doc/man-pages/pod5/NetInfo.pod b/doc/man-pages/pod5/NetInfo.pod index 58e9ae98f..1d7890717 100644 --- a/doc/man-pages/pod5/NetInfo.pod +++ b/doc/man-pages/pod5/NetInfo.pod @@ -30,10 +30,11 @@ File Server initiates RPCs: when it breaks callbacks and when it pings the client machine to verify that the Cache Manager is still accessible. The F file is in ASCII format. One of the machine's IP addresses -appears on each line, in dotted decimal format. The File Server initially -uses the address that appears first in the list. The order of the -remaining addresses is not significant: if an RPC to the first interface -fails, the File Server simultaneously sends RPCs to all of the other +appears on each line, in dotted decimal format. To match a network instead +of an individual address, use a slash (C) followed a subnet length. The +File Server initially uses the address that matches first in the list. The +order of the remaining addresses is not significant: if an RPC to the first +interface fails, the File Server simultaneously sends RPCs to all of the other interfaces in the list. Whichever interface replies first is the one to which the File Server then sends pings and RPCs to break callbacks. @@ -77,8 +78,9 @@ to use for communication with the peer processes on other database machines in the cell. The F file is in ASCII format. One of the machine's IP addresses -appears on each line, in dotted decimal format. The order of the addresses -is not significant. +appears on each line, in dotted decimal format. To match a network +instead of an individual address, use a slash (C) followed a subnet +length. The order of the addresses is not significant. Optionally, the File Server can be forced to use an IP address that does not belong to one of the server interfaces. To do this, add a line to the diff --git a/doc/man-pages/pod5/NetRestrict.pod b/doc/man-pages/pod5/NetRestrict.pod index 471b025b3..f5d76d9f7 100644 --- a/doc/man-pages/pod5/NetRestrict.pod +++ b/doc/man-pages/pod5/NetRestrict.pod @@ -14,9 +14,9 @@ to talk to other database servers. =head2 FORMAT The F file is in ASCII format. One IP address appears on each -line, in dotted decimal format. The order of the addresses is not -significant. There is currently no mechanism to specify a range of -addresses or a wildcard; each IP address must be listed individually. +line, in dotted decimal format. To specify a network instead, use a +slash (C) followed by a subnet length. The order of the addresses is +not significant. =head2 Client NetRestrict @@ -70,6 +70,19 @@ the peer processes on other database machines in the cell. To display the File Server interface addresses registered in the VLDB, use the B command. +=head1 EXAMPLES + +If the File Server should not use the IP address 192.168.1.1 on one of +its private interfaces, then the F file should contain +the following: + + 196.168.1.1 + +In order to prevent the usage of any 192.168/16 addresses on its local +interfaces, the F file should contain: + + 196.168.0.0/16 + =head1 SEE ALSO L, diff --git a/doc/xml/AdminGuide/auagd008.xml b/doc/xml/AdminGuide/auagd008.xml index 2f490e3e5..9e4f11936 100644 --- a/doc/xml/AdminGuide/auagd008.xml +++ b/doc/xml/AdminGuide/auagd008.xml @@ -5218,9 +5218,9 @@ Using a text editor, open the /usr/afs/local/NetRestrict file. Place one IP address - in dotted decimal format on each line. The order of the addresses is not significant. Use the value 255 as a wildcard that represents all possible addresses in that field. For example, the entry - 192.12.105.255 indicates that the Cache Manager does not register any of the addresses in + in dotted decimal format on each line. The order of the addresses is not significant. Use a slash (/) followed by a subnet length to represent all possible addresses in a range. For example, the entry + 192.12.105.0/24 indicates that the Cache Manager does not register any of the addresses in the 192.12.105 subnet. diff --git a/doc/xml/AdminGuide/auagd015.xml b/doc/xml/AdminGuide/auagd015.xml index 4ffe0cc4c..47a51be58 100644 --- a/doc/xml/AdminGuide/auagd015.xml +++ b/doc/xml/AdminGuide/auagd015.xml @@ -3366,9 +3366,9 @@ Using a text editor, open the /usr/vice/etc/NetRestrict file. Place one IP address - in dotted decimal format on each line. The order of the addresses is not significant. Use the value 255 as a wildcard that represents all possible addresses in that field. For example, the entry - 192.12.105.255 indicates that the Cache Manager does not register any of the addresses in + in dotted decimal format on each line. The order of the addresses is not significant. Use a slash (/) followed by a subnet length to represent all possible addresses in a range. For example, the entry + 192.12.105.0/24 indicates that the Cache Manager does not register any of the addresses in the 192.12.105 subnet. diff --git a/src/auth/netrestrict.c b/src/auth/netrestrict.c index a5a048ebb..38bff9404 100644 --- a/src/auth/netrestrict.c +++ b/src/auth/netrestrict.c @@ -25,28 +25,46 @@ #include "cellconfig.h" -#define AFS_IPINVALID 0xffffffff /* invalid IP address */ -#define AFS_IPINVALIDIGNORE 0xfffffffe /* no input given to extractAddr */ -#define MAX_NETFILE_LINE 2048 /* length of a line in the netrestrict file */ +#define AFS_IPINVALID -1 /* invalid IP address */ +#define AFS_IPINVALIDIGNORE -2 /* no input given to extractAddr */ +#define MAX_NETFILE_LINE 2048 /* length of a line in the NetRestrict file */ #define MAXIPADDRS 1024 /* from afsd.c */ static int ParseNetInfoFile_int(afs_uint32 *, afs_uint32 *, afs_uint32 *, int, char reason[], const char *, int); -/* + +/** * The line parameter is a pointer to a buffer containing a string of - * bytes of the form -** w.x.y.z # machineName - * returns the network interface IP Address in NBO + * bytes of the form: + * + * w.x.y.z[/n] # machineName + * + * Returns an IPv4 address and mask in network byte order. Optionally, + * a '/' may be used to specify a subnet mask length. + * + * @param[in] line + * Pointer to a string of bytes + * @param[out] maxSize + * Length to search in line for addresses + * @param[out] addr + * IPv4 address in network byte order + * @param[out] mask + * IPv4 subnet mask in network byte order, default to 0xffffffff + * + * @return + * @retval 0 success + * @retval AFS_IPINVALID the address is invalid or parsing failed + * @retval AFS_IPINVALIDIGNORE blank line that can be ignored */ -afs_uint32 -extract_Addr(char *line, int maxSize) +static int +extract_Addr(char *line, int maxSize, afs_uint32 *addr, afs_uint32 *mask) { char bytes[4][32]; int i = 0, n = 0; char *endPtr; afs_uint32 val[4]; - afs_uint32 retval = 0; + int subnet_len = 32; /* skip empty spaces */ while (isspace(*line) && maxSize) { @@ -57,8 +75,15 @@ extract_Addr(char *line, int maxSize) if (!maxSize || !*line) return AFS_IPINVALIDIGNORE; + /* init to 0.0.0.0 for strtol() */ + for (n = 0; n < 4; n++) { + bytes[n][0] = '0'; + bytes[n][1] = '\0'; + } + for (n = 0; n < 4; n++) { - while ((*line != '.') && !isspace(*line) && maxSize) { /* extract nth byte */ + while ((*line != '.') && !isspace(*line) + && (*line != '/') && maxSize) { /* extract nth byte */ if (!isdigit(*line)) return AFS_IPINVALID; if (i > 31) @@ -68,16 +93,47 @@ extract_Addr(char *line, int maxSize) } /* while */ if (!maxSize) return AFS_IPINVALID; - bytes[n][i] = 0; - i = 0, line++; + bytes[n][i] = '\0'; + if (*line == '/') + break; + i = 0; + line++; + } + + if (*line == '.') + ++line; /* single trailing . allowed */ + + if (*line == '/') { /* have a subnet length */ + line++; + subnet_len = 0; + while (isdigit(*line)) { + subnet_len = subnet_len * 10 + (*line - '0'); + if (subnet_len > 32) + return AFS_IPINVALID; /* subnet length too long */ + ++line; + } + if (subnet_len == 0) + return AFS_IPINVALID; /* subnet length too short */ + } + + if (!isspace(*line) && (*line != '\0')) + return AFS_IPINVALID; /* improperly formed comment */ + + for (n = 0; n < 4; n++) { errno = 0; val[n] = strtol(bytes[n], &endPtr, 10); - if ((val[n] == 0) && (errno != 0 || bytes[n] == endPtr)) /* no conversion */ + if ((val[n] == 0) && (errno != 0 || bytes[n] == endPtr)) /* no conversion */ return AFS_IPINVALID; - } /* for */ + } + + *mask = 0; + while (subnet_len--) { + *mask = (*mask >> 1) | 0x80000000; + } - retval = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3]; - return htonl(retval); + *mask = htonl(*mask); + *addr = htonl((val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3]); + return 0; } /** @@ -124,7 +180,8 @@ parseNetRestrictFile_int(afs_uint32 outAddrs[], afs_uint32 outMask[], char line[MAX_NETFILE_LINE]; int lineNo, usedfile = 0; afs_uint32 i, neaddrs, nOutaddrs; - afs_uint32 addr, eAddrs[MAXIPADDRS], eMask[MAXIPADDRS], eMtu[MAXIPADDRS]; + afs_uint32 addr, mask, eAddrs[MAXIPADDRS], eMask[MAXIPADDRS], eMtu[MAXIPADDRS]; + int retval; opr_Assert(outAddrs); opr_Assert(reason); @@ -165,13 +222,13 @@ parseNetRestrictFile_int(afs_uint32 outAddrs[], afs_uint32 outMask[], usedfile = 0; while (fgets(line, MAX_NETFILE_LINE, fp) != NULL) { lineNo++; /* input line number */ - addr = extract_Addr(line, strlen(line)); - if (addr == AFS_IPINVALID) { /* syntactically invalid */ + retval = extract_Addr(line, strlen(line), &addr, &mask); + if (retval == AFS_IPINVALID) { /* syntactically invalid */ fprintf(stderr, "%s : line %d : parse error - invalid IP\n", fileName, lineNo); continue; } - if (addr == AFS_IPINVALIDIGNORE) { /* ignore error */ + if (retval == AFS_IPINVALIDIGNORE) { /* ignore error */ fprintf(stderr, "%s : line %d : invalid address ... ignoring\n", fileName, lineNo); continue; @@ -180,7 +237,7 @@ parseNetRestrictFile_int(afs_uint32 outAddrs[], afs_uint32 outMask[], /* Check if we need to exclude this address */ for (i = 0; i < neaddrs; i++) { - if (eAddrs[i] && (eAddrs[i] == addr)) { + if (eAddrs[i] && ((eAddrs[i] & mask) == (addr & mask))) { eAddrs[i] = 0; /* Yes - exclude it by zeroing it for now */ } } @@ -261,9 +318,10 @@ ParseNetInfoFile_int(afs_uint32 outAddrs[], afs_uint32 outMask[], afs_uint32 out char line[MAX_NETFILE_LINE]; FILE *fp; int i, existNu, count = 0; - afs_uint32 addr; + afs_uint32 addr, mask; int lineNo = 0; int l; + int retval; opr_Assert(fileName); opr_Assert(outAddrs); @@ -310,20 +368,25 @@ ParseNetInfoFile_int(afs_uint32 outAddrs[], afs_uint32 outMask[], afs_uint32 out } lineNo++; /* input line number */ - addr = extract_Addr(&line[fake], strlen(&line[fake])); + retval = extract_Addr(&line[fake], strlen(&line[fake]), &addr, &mask); - if (addr == AFS_IPINVALID) { /* syntactically invalid */ + if (retval == AFS_IPINVALID) { /* syntactically invalid */ fprintf(stderr, "afs:%s : line %d : parse error\n", fileName, lineNo); continue; } - if (addr == AFS_IPINVALIDIGNORE) { /* ignore error */ + if (fake && ntohl(mask) != 0xffffffff) { + fprintf(stderr, "afs:%s : line %d : bad fake address\n", fileName, + lineNo); + continue; + } + if (retval == AFS_IPINVALIDIGNORE) { /* ignore error */ continue; } /* See if it is an address that really exists */ for (i = 0; i < existNu; i++) { - if (existingAddr[i] == addr) + if ((existingAddr[i] & mask) == (addr & mask)) break; } if ((i >= existNu) && (!fake)) @@ -331,12 +394,12 @@ ParseNetInfoFile_int(afs_uint32 outAddrs[], afs_uint32 outMask[], afs_uint32 out /* Check if it is a duplicate address we alread have */ for (l = 0; l < count; l++) { - if (outAddrs[l] == addr) + if ((outAddrs[l] & mask) == (addr & mask)) break; } if (l < count) { - fprintf(stderr, "afs:%x specified twice in NetInfo file\n", - ntohl(addr)); + fprintf(stderr, "afs:%x matched more than once in NetInfo file\n", + ntohl(outAddrs[l])); continue; /* duplicate addr - ignore */ } diff --git a/src/auth/test/Makefile.in b/src/auth/test/Makefile.in index f45f530f8..ee8ebdedd 100644 --- a/src/auth/test/Makefile.in +++ b/src/auth/test/Makefile.in @@ -17,7 +17,7 @@ LT_deps = \ $(TOP_OBJDIR)/src/opr/liboafs_opr.la LT_libs = $(LDFLAGS_roken) $(LIB_roken) -tests all: testcellconf ktctest +tests all: testcellconf ktctest testnetrestrict testcellconf: testcellconf.lo $(LT_LDRULE_static) testcellconf.lo $(LT_deps) $(LT_libs) @@ -25,6 +25,9 @@ testcellconf: testcellconf.lo ktctest: ktctest.lo $(LT_LDRULE_static) ktctest.lo $(LT_deps) $(LT_libs) +testnetrestrict: testnetrestrict.o + $(AFS_LDRULE) testnetrestrict.o $(TOP_LIBDIR)/libauth.a $(TOP_LIBDIR)/libopr.a + clean: $(LT_CLEAN) $(RM) -f copyauth testcellconf ktctest setkey auth.h cellconfig.h acfg_errors.c ktc_errors.c core diff --git a/src/auth/test/testnetrestrict.c b/src/auth/test/testnetrestrict.c new file mode 100644 index 000000000..26ff9578a --- /dev/null +++ b/src/auth/test/testnetrestrict.c @@ -0,0 +1,125 @@ +/* + * testnetstrict.c + * + * Utility to test NetInfo and NetRestrict parsing + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +char *interfaceList, *filenameNetInfo, *filenameNetRestrict; + +int +rx_getAllAddrMaskMtu(afs_uint32 addrBuffer[], + afs_uint32 maskBuffer[], + afs_uint32 mtuBuffer[], + int maxSize) +{ + FILE *fp; + int nInterfaces = 0, lineNo = 1; + int a[4], m[4], mtu; + char line[80]; + + fp = fopen(interfaceList, "r"); + if (fp == NULL) { + perror("fopen"); + exit(1); + } + + while (nInterfaces < maxSize) { + ++lineNo; + if (fgets(line, 80, fp) == NULL) + break; + if (sscanf(line, "%d.%d.%d.%d %d.%d.%d.%d %d\n", + &a[0], &a[1], &a[2], &a[3], + &m[0], &m[1], &m[2], &m[3], &mtu) == 9) { + + addrBuffer[nInterfaces] = htonl(a[0] << 24 | a[1] << 16 + | a[2] << 8 | a[3]); + maskBuffer[nInterfaces] = htonl(m[0] << 24 | m[1] << 16 + | m[2] << 8 | m[3]); + mtuBuffer[nInterfaces] = htonl(mtu); + ++nInterfaces; + } else { + fprintf(stderr, "failed to parse line %d in %s\n", lineNo, interfaceList); + } + } + fclose(fp); + + return nInterfaces; +} + +#define MAXADDRS 16 + +int +main(int argc, char *argv[]) +{ + afs_uint32 outAddrs[MAXADDRS], outMask[MAXADDRS], outMtu[MAXADDRS], nAddrs; + char reason[1024]; + int i, retval; + + if (argc < 4) { + fprintf(stderr, "usage: testnetrestrict \n"); + exit(1); + } + + interfaceList = argv[1]; + filenameNetInfo = argv[2]; + filenameNetRestrict = argv[3]; + + reason[0] = '\0'; + retval = afsconf_ParseNetInfoFile(outAddrs, outMask, outMtu, MAXADDRS, + reason, filenameNetInfo); + + printf("afsconf_ParseNetInfoFile() returned %d\n", retval); + if (reason[0] != '\0') + printf("reason: %s\n", reason); + + printf("final address list:\n"); + if (retval > 0) { + for(i = 0; i < retval; ++i) { + printf("\taddress 0x%x mask 0x%x mtu %d\n", + ntohl(outAddrs[i]), ntohl(outMask[i]), ntohl(outMtu[i])); + } + } + + reason[0] = '\0'; + retval = afsconf_ParseNetRestrictFile(outAddrs, outMask, outMtu, MAXADDRS, + &nAddrs, reason, filenameNetRestrict); + + printf("\nafsconf_ParseNetRestrictFile() returned %d\n", retval); + if (reason[0] != '\0') + printf("reason: %s\n", reason); + if (nAddrs > 0) { + printf("final address list:\n"); + for(i = 0; i < nAddrs; ++i) { + printf("\taddress 0x%x mask 0x%x mtu %d\n", + ntohl(outAddrs[i]), ntohl(outMask[i]), ntohl(outMtu[i])); + } + } + + reason[0] = '\0'; + retval = afsconf_ParseNetFiles(outAddrs, outMask, outMtu, MAXADDRS, + reason, filenameNetInfo, filenameNetRestrict); + + printf("\nafsconf_ParseNetFiles() returned %d\n", retval); + if (reason[0] != '\0') + printf("reason: %s\n", reason); + if (retval > 0) { + printf("final address list:\n"); + for(i = 0; i < retval; ++i) { + printf("\taddress 0x%x mask 0x%x mtu %d\n", + ntohl(outAddrs[i]), ntohl(outMask[i]), ntohl(outMtu[i])); + } + } + + exit(0); +} -- 2.39.5