1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
/* IP4 address parsing routines
*/
#include "ip4addr.h"
#define digit(c) ((c) >= '0' && (c) <= '9')
#define d2n(c) ((c) - '0')
/* cret(): returns v if last byte is \0, or else
* either sets *np to point to the last byte and
* returns v, or return -1 */
#define cret(v, np, s) ((np) ? *(np) = (char*)(s), (v) : *(s) ? -1 : (v))
/* eret(): returns -1 and sets *np if np is non-NULL */
#define eret(np, s) ((np) ? *(np) = (char*)(s), -1 : -1)
static int ip4mbits(const char *s, char **np) {
/* helper routine for ip4cidr() and ip4range() */
int bits;
if (!digit(*s))
return eret(np, s - 1);
bits = d2n(*s++);
while(digit(*s))
if ((bits = bits * 10 + d2n(*s++)) > 32)
return eret(np, s - 1);
/*if (!bits) return eret(np, s - 1); allow /0 mask too */
return cret(bits, np, s);
}
/* parse a prefix, return # of bits (8,16,24 or 32)
* or <0 on error. Can't return 0. */
int ip4prefix(const char *s, ip4addr_t *ap, char **np) {
ip4addr_t o;
*ap = 0;
#define ip4oct(bits) \
if (!digit(*s)) \
return eret(np, s); \
o = d2n(*s++); \
while(digit(*s)) \
if ((o = o * 10 + d2n(*s++)) > 255) \
return eret(np, s - 1); \
*ap |= o << bits
ip4oct(24);
if (*s != '.') return cret(8, np, s);
++s;
ip4oct(16);
if (*s != '.') return cret(16, np, s);
++s;
ip4oct(8);
if (*s != '.') return cret(24, np, s);
++s;
ip4oct(0);
return cret(32, np, s);
#undef ip4oct
}
/* Parse ip4 CIDR range in `s', store base
* in *ap and return number of bits (may be 0)
* or <0 on error.
* To zero hostpart:
* *ap &= ip4mask(bits)
* where bits is the return value
*/
int ip4cidr(const char *s, ip4addr_t *ap, char **np) {
int bits = ip4prefix(s, ap, (char**)&s);
if (bits < 0) /* error */
return eret(np, s);
else if (*s == '/') /* probably /bits */
return ip4mbits(s + 1, np);
else if (bits == 8) /* disallow bare numbers */
return eret(np, s);
else
return cret(bits, np, s);
}
/* Parse ip4 range or CIDR in `s',
* store start in *ap and end in *bp,
* return
* bits (may be 0) if that was CIDR or prefix,
* 32 if plain range,
* <0 on error.
* *ap may have non-zero hostpart on
* return and should be adjusted as
* *ap &= ip4mask(bits)
* where bits is the return value.
*/
int ip4range(const char *s, ip4addr_t *ap, ip4addr_t *bp, char **np) {
int bits = ip4prefix(s, ap, (char**)&s);
if (bits < 0)
return eret(np, s);
else if (*s == '-') { /* a-z */
int bbits = ip4prefix(s + 1, bp, (char**)&s);
if (bbits < 0) return eret(np, s);
if (bbits == 8) { /* treat 127.0.0.1-2 as 127.0.0.1-127.0.0.2 */
*bp = (*bp >> (bits - 8)) | (*ap & ip4mask(bits - 8));
bbits = bits;
}
else if (bbits != bits)
/* disallow weird stuff like 1.2-1.2.3.4 */
return eret(np, s);
if (bbits != 32) /* complete last octets */
*bp |= ~ip4mask(bbits);
if (*ap > *bp) return eret(np, s);
return cret(32, np, s);
}
else {
if (*s == '/') { /* /bits */
bits = ip4mbits(s + 1, (char**)&s);
if (bits < 0) return eret(np, s);
}
else if (bits == 8)
/* disallow bare numbers - use /8 */
return eret(np, s);
*bp = *ap | ~ip4mask(bits);
return cret(bits, np, s);
}
}
/* traditional inet_aton/inet_addr. Werid:
* 127.1 = 127.0.0.1
* 1 = 0.0.0.1!!! - but here we go...
* return #bits in _prefix_ (8,16,24 or 32), or <0 on error.
*/
int ip4addr(const char *s, ip4addr_t *ap, char **np) {
int bits = ip4prefix(s, ap, np);
switch(bits) {
case 8: /* what a werid case! */
*ap >>= 24;
break;
case 16:
*ap = (*ap & 0xff000000u) | ((*ap >> 16) & 255);
break;
case 24:
*ap = (*ap & 0xffff0000u) | ((*ap >> 8) & 255);
break;
}
return bits;
}
#ifdef TEST
#include <stdio.h>
int main(int argc, char **argv) {
int i;
ip4addr_t a, b;
int bits;
char *np;
#define octets(x) (x)>>24,((x)>>16)&255,((x)>>8)&255,(x)&255
#define IPFMT "%u.%u.%u.%u"
for(i = 1; i < argc; ++i) {
char *s = argv[i];
printf("%s:\n", s);
#define PFX " pfx : bits=%d "
#define ADDR " addr : bits=%d "
#define CIDR " cidr : bits=%d "
#define RANGE " range: bits=%d "
#define HP(a,bits) (a & ~ip4mask(bits) ? " (non-zero hostpart)" : "")
bits = ip4prefix(s, &a, NULL);
if (bits < 0) printf(" pfx : err\n");
else printf(" pfx : bits=%d " IPFMT "\n", bits, octets(a));
bits = ip4prefix(s, &a, &np);
if (bits < 0) printf(" pfx : err tail=`%s'\n", np);
else
printf(" pfx : bits=%d " IPFMT " tail=`%s'\n", bits, octets(a), np);
bits = ip4addr(s, &a, NULL);
if (bits < 0) printf(" addr : err\n");
else printf(" addr : bits=%d " IPFMT "\n", bits, octets(a));
bits = ip4addr(s, &a, &np);
if (bits < 0) printf(" addr : err tail=`%s'\n", np);
else printf(" addr : bits=%d " IPFMT " tail=`%s'\n", bits, octets(a), np);
bits = ip4cidr(s, &a, NULL);
if (bits < 0) printf(" cidr : err\n");
else
printf(" cidr : bits=%d " IPFMT "%s\n", bits, octets(a), HP(a,bits));
bits = ip4cidr(argv[i], &a, &np);
if (bits < 0) printf(" cidr : err tail=`%s'\n", np);
else
printf(" cidr : bits=%d " IPFMT " " IPFMT " tail=`%s'%s\n",
bits, octets(a), octets(a&ip4mask(bits)), np, HP(a,bits));
bits = ip4range(s, &a, &b, NULL);
if (bits < 0) printf(" range: err\n");
else
printf(" range: bits=%d " IPFMT "-" IPFMT "%s\n",
bits, octets(a), octets(b), HP(a,bits));
bits = ip4range(s, &a, &b, &np);
if (bits < 0) printf(" range: err tail=`%s'\n", np);
else
printf(" range: bits=%d " IPFMT "-" IPFMT " tail=`%s'%s\n",
bits, octets(a), octets(b), np, HP(a,bits));
}
return 0;
}
#endif
|