#include <sys_defs.h>
#include <string.h>
#include <ctype.h>
#include "msg.h"
#include "mymalloc.h"
#include "stringops.h"
#include "valid_hostname.h"
int valid_hostname(const char *name, int gripe)
{
const char *myname = "valid_hostname";
const char *cp;
int label_length = 0;
int label_count = 0;
int non_numeric = 0;
int ch;
if (*name == 0) {
if (gripe)
msg_warn("%s: empty hostname", myname);
return (0);
}
for (cp = name; (ch = *(unsigned char *) cp) != 0; cp++) {
if (ISALNUM(ch) || ch == '_') {
if (label_length == 0)
label_count++;
label_length++;
if (label_length > VALID_LABEL_LEN) {
if (gripe)
msg_warn("%s: hostname label too long: %.100s", myname, name);
return (0);
}
if (!ISDIGIT(ch))
non_numeric = 1;
} else if (ch == '.') {
if (label_length == 0 || cp[1] == 0) {
if (gripe)
msg_warn("%s: misplaced delimiter: %.100s", myname, name);
return (0);
}
label_length = 0;
} else if (ch == '-') {
label_length++;
if (label_length == 1 || cp[1] == 0 || cp[1] == '.') {
if (gripe)
msg_warn("%s: misplaced hyphen: %.100s", myname, name);
return (0);
}
}
#ifdef SLOPPY_VALID_HOSTNAME
else if (ch == ':' && valid_ipv6_hostaddr(name, DONT_GRIPE)) {
non_numeric = 0;
break;
}
#endif
else {
if (gripe)
msg_warn("%s: invalid character %d(decimal): %.100s",
myname, ch, name);
return (0);
}
}
if (non_numeric == 0) {
if (gripe)
msg_warn("%s: numeric hostname: %.100s", myname, name);
#ifndef SLOPPY_VALID_HOSTNAME
return (0);
#endif
}
if (cp - name > VALID_HOSTNAME_LEN) {
if (gripe)
msg_warn("%s: bad length %d for %.100s...",
myname, (int) (cp - name), name);
return (0);
}
return (1);
}
int valid_hostaddr(const char *addr, int gripe)
{
const char *myname = "valid_hostaddr";
if (*addr == 0) {
if (gripe)
msg_warn("%s: empty address", myname);
return (0);
}
if (strchr(addr, ':') != 0)
return (valid_ipv6_hostaddr(addr, gripe));
else
return (valid_ipv4_hostaddr(addr, gripe));
}
int valid_ipv4_hostaddr(const char *addr, int gripe)
{
const char *cp;
const char *myname = "valid_ipv4_hostaddr";
int in_byte = 0;
int byte_count = 0;
int byte_val = 0;
int ch;
#define BYTES_NEEDED 4
for (cp = addr; (ch = *(unsigned const char *) cp) != 0; cp++) {
if (ISDIGIT(ch)) {
if (in_byte == 0) {
in_byte = 1;
byte_val = 0;
byte_count++;
}
byte_val *= 10;
byte_val += ch - '0';
if (byte_val > 255) {
if (gripe)
msg_warn("%s: invalid octet value: %.100s", myname, addr);
return (0);
}
} else if (ch == '.') {
if (in_byte == 0 || cp[1] == 0) {
if (gripe)
msg_warn("%s: misplaced dot: %.100s", myname, addr);
return (0);
}
if (byte_count == 1 && byte_val == 0 && addr[strspn(addr, "0.")]) {
if (gripe)
msg_warn("%s: bad initial octet value: %.100s", myname, addr);
return (0);
}
in_byte = 0;
} else {
if (gripe)
msg_warn("%s: invalid character %d(decimal): %.100s",
myname, ch, addr);
return (0);
}
}
if (byte_count != BYTES_NEEDED) {
if (gripe)
msg_warn("%s: invalid octet count: %.100s", myname, addr);
return (0);
}
return (1);
}
int valid_ipv6_hostaddr(const char *addr, int gripe)
{
const char *myname = "valid_ipv6_hostaddr";
int null_field = 0;
int field = 0;
unsigned char *cp = (unsigned char *) addr;
int len = 0;
for (;;) {
switch (*cp) {
case 0:
if (field < 2) {
if (gripe)
msg_warn("%s: too few `:' in IPv6 address: %.100s",
myname, addr);
return (0);
} else if (len == 0 && null_field != field - 1) {
if (gripe)
msg_warn("%s: bad null last field in IPv6 address: %.100s",
myname, addr);
return (0);
} else
return (1);
case '.':
if (field < 2 || field > 6) {
if (gripe)
msg_warn("%s: malformed IPv4-in-IPv6 address: %.100s",
myname, addr);
return (0);
} else
return (valid_ipv4_hostaddr((char *) cp - len, gripe));
case ':':
if (field == 0 && len == 0 && ISALNUM(cp[1])) {
if (gripe)
msg_warn("%s: bad null first field in IPv6 address: %.100s",
myname, addr);
return (0);
}
field++;
if (field > 7) {
if (gripe)
msg_warn("%s: too many `:' in IPv6 address: %.100s",
myname, addr);
return (0);
}
cp++;
len = 0;
if (*cp == ':') {
if (null_field > 0) {
if (gripe)
msg_warn("%s: too many `::' in IPv6 address: %.100s",
myname, addr);
return (0);
}
null_field = field;
}
break;
default:
len = strspn((char *) cp, "0123456789abcdefABCDEF");
if (len > 4) {
if (gripe)
msg_warn("%s: malformed IPv6 address: %.100s",
myname, addr);
return (0);
}
if (len <= 0) {
if (gripe)
msg_warn("%s: invalid character %d(decimal) in IPv6 address: %.100s",
myname, *cp, addr);
return (0);
}
cp += len;
break;
}
}
}
#ifdef TEST
#include <stdlib.h>
#include "vstring.h"
#include "vstream.h"
#include "vstring_vstream.h"
#include "msg_vstream.h"
int main(int unused_argc, char **argv)
{
VSTRING *buffer = vstring_alloc(1);
msg_vstream_init(argv[0], VSTREAM_ERR);
msg_verbose = 1;
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
msg_info("testing: \"%s\"", vstring_str(buffer));
valid_hostname(vstring_str(buffer), DO_GRIPE);
valid_hostaddr(vstring_str(buffer), DO_GRIPE);
}
exit(0);
}
#endif