/* * convert from ASCII form of subnet specification to binary * Copyright (C) 1998, 1999 Henry Spencer. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public * License for more details. */ #include "internal.h" #include "freeswan.h" #ifndef DEFAULTSUBNET #define DEFAULTSUBNET "%default" #endif /* - atosubnet - convert ASCII "addr/mask" to address and mask * Mask can be integer bit count. */ const char * /* NULL for success, else string literal */ atosubnet(src, srclen, addrp, maskp) const char *src; size_t srclen; /* 0 means "apply strlen" */ struct in_addr *addrp; struct in_addr *maskp; { const char *slash; const char *mask; size_t mlen; const char *oops; unsigned long bc; static char def[] = DEFAULTSUBNET; # define DEFLEN (sizeof(def) - 1) /* -1 for NUL */ static char defis[] = "0/0"; # define DEFILEN (sizeof(defis) - 1) if (srclen == 0) srclen = strlen(src); if (srclen == 0) return "empty string"; if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) { src = defis; srclen = DEFILEN; } slash = memchr(src, '/', srclen); if (slash == NULL) return "no / in subnet specification"; mask = slash + 1; mlen = srclen - (mask - src); oops = atoaddr(src, slash-src, addrp); if (oops != NULL) return oops; oops = atoul(mask, mlen, 10, &bc); if (oops == NULL) { /* atoul succeeded, it's a bit-count mask */ if (bc > ABITS) return "bit-count mask too large"; #ifdef NOLEADINGZEROS if (mlen > 1 && *mask == '0') return "octal not allowed in mask"; #endif /* NOLEADINGZEROS */ *maskp = bitstomask((int)bc); } else { oops = atoaddr(mask, mlen, maskp); if (oops != NULL) return oops; if (!goodmask(*maskp)) return "non-contiguous mask"; } addrp->s_addr &= maskp->s_addr; return NULL; } #ifdef ATOSUBNET_MAIN #include #include #include #include void regress(void); int main(int argc, char *argv[]) { struct in_addr a; struct in_addr m; char buf[100]; const char *oops; size_t n; if (argc < 2) { fprintf(stderr, "Usage: %s {addr/mask|-r}\n", argv[0]); exit(2); } if (strcmp(argv[1], "-r") == 0) { regress(); fprintf(stderr, "regress() returned?!?\n"); exit(1); } oops = atosubnet(argv[1], 0, &a, &m); if (oops != NULL) { fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); exit(1); } n = subnettoa(a, m, 0, buf, sizeof(buf)); if (n > sizeof(buf)) { fprintf(stderr, "%s: reverse conversion of ", argv[0]); fprintf(stderr, "%s/", inet_ntoa(a)); fprintf(stderr, "%s", inet_ntoa(m)); fprintf(stderr, " failed: need %ld bytes, have only %ld\n", (long)n, (long)sizeof(buf)); exit(1); } printf("%s\n", buf); exit(0); } struct rtab { char *input; char *output; /* NULL means error expected */ } rtab[] = { {"1.2.3.0/255.255.255.0", "1.2.3.0/24"}, {"1.2.3.0/24", "1.2.3.0/24"}, {"1.2.3.1/255.255.255.240", "1.2.3.0/28"}, {"1.2.3.1/32", "1.2.3.1/32"}, {"1.2.3.1/0", "0.0.0.0/0"}, /* "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0", */ {"1.2.3.1/255.255.127.0", NULL}, {"128.009.000.032/32", "128.9.0.32/32"}, {"128.0x9.0.32/32", NULL}, {"0x80090020/32", "128.9.0.32/32"}, {"0x800x0020/32", NULL}, {"128.9.0.32/0xffFF0000", "128.9.0.0/16"}, {"128.9.0.32/0xff0000FF", NULL}, {"128.9.0.32/0x0000ffFF", NULL}, {"128.9.0.32/0x00ffFF0000", NULL}, {"128.9.0.32/0xffFF", NULL}, {"128.9.0.32.27/32", NULL}, {"128.9.0k32/32", NULL}, {"328.9.0.32/32", NULL}, {"128.9..32/32", NULL}, {"10/8", "10.0.0.0/8"}, {"10.0/8", "10.0.0.0/8"}, {"10.0.0/8", "10.0.0.0/8"}, {"10.0.1/24", "10.0.1.0/24"}, {"_", NULL}, {"_/_", NULL}, {"1.2.3.1", NULL}, {"1.2.3.1/_", NULL}, {"1.2.3.1/24._", NULL}, {"1.2.3.1/99", NULL}, {"localhost/32", "127.0.0.1/32"}, {"%default", "0.0.0.0/0"}, {NULL, NULL} }; void regress() { struct rtab *r; int status = 0; struct in_addr a; struct in_addr m; char in[100]; char buf[100]; const char *oops; size_t n; for (r = rtab; r->input != NULL; r++) { strcpy(in, r->input); oops = atosubnet(in, 0, &a, &m); if (oops != NULL && r->output == NULL) {} /* okay, error expected */ else if (oops != NULL) { printf("`%s' atosubnet failed: %s\n", r->input, oops); status = 1; } else if (r->output == NULL) { printf("`%s' atosubnet succeeded unexpectedly\n", r->input); status = 1; } else { n = subnettoa(a, m, 0, buf, sizeof(buf)); if (n > sizeof(buf)) { printf("`%s' subnettoa failed: need %ld\n", r->input, (long)n); status = 1; } else if (strcmp(r->output, buf) != 0) { printf("`%s' gave `%s', expected `%s'\n", r->input, buf, r->output); status = 1; } } } exit(status); } #endif /* ATOSUBNET_MAIN */