204 lines
4.6 KiB
C
204 lines
4.6 KiB
C
/*++
|
|
/* NAME
|
|
/* valid_hostname 3
|
|
/* SUMMARY
|
|
/* network name validation
|
|
/* SYNOPSIS
|
|
/* #include <valid_hostname.h>
|
|
/*
|
|
/* int valid_hostname(name)
|
|
/* const char *name;
|
|
/*
|
|
/* int valid_hostaddr(addr)
|
|
/* const char *addr;
|
|
/* DESCRIPTION
|
|
/* valid_hostname() scrutinizes a hostname: the name should be no
|
|
/* longer than VALID_HOSTNAME_LEN characters, should contain only
|
|
/* letters, digits, dots and hyphens, no adjacent dots and hyphens,
|
|
/* no leading or trailing dots or hyphens, no labels longer than
|
|
/* VALID_LABEL_LEN characters, and no numeric top-level domain.
|
|
/*
|
|
/* valid_hostaddr() requirs that the input is a valid string
|
|
/* representation of an internet network address.
|
|
/* DIAGNOSTICS
|
|
/* Both functions return zero if they disagree with the input.
|
|
/* SEE ALSO
|
|
/* RFC 952, 1123, RFC 1035
|
|
/* LICENSE
|
|
/* .ad
|
|
/* .fi
|
|
/* The Secure Mailer license must be distributed with this software.
|
|
/* AUTHOR(S)
|
|
/* Wietse Venema
|
|
/* IBM T.J. Watson Research
|
|
/* P.O. Box 704
|
|
/* Yorktown Heights, NY 10598, USA
|
|
/*--*/
|
|
|
|
/* System library. */
|
|
|
|
#include <sys_defs.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
/* Utility library. */
|
|
|
|
#include "msg.h"
|
|
#include "mymalloc.h"
|
|
#include "stringops.h"
|
|
#include "valid_hostname.h"
|
|
|
|
/* valid_hostname - screen out bad hostnames */
|
|
|
|
int valid_hostname(const char *name)
|
|
{
|
|
const char *myname = "valid_hostname";
|
|
const char *cp;
|
|
int label_length = 0;
|
|
int label_count = 0;
|
|
int non_numeric = 0;
|
|
int ch;
|
|
|
|
/*
|
|
* Trivial cases first.
|
|
*/
|
|
if (*name == 0) {
|
|
msg_warn("%s: empty hostname", myname);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Find bad characters or label lengths. Find adjacent delimiters.
|
|
*/
|
|
for (cp = name; (ch = *(unsigned char *) cp) != 0; cp++) {
|
|
if (ISALNUM(ch) || ch == '_') { /* grr.. */
|
|
if (label_length == 0)
|
|
label_count++;
|
|
label_length++;
|
|
if (label_length > VALID_LABEL_LEN) {
|
|
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) {
|
|
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] == '.') {
|
|
msg_warn("%s: misplaced hyphen: %.100s", myname, name);
|
|
return (0);
|
|
}
|
|
} else {
|
|
msg_warn("%s: invalid character %d(decimal): %.100s",
|
|
myname, ch, name);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
if (non_numeric == 0) {
|
|
msg_warn("%s: numeric hostname: %.100s", myname, name);
|
|
/* NOT: return (0); this confuses users of the DNS client */
|
|
}
|
|
if (cp - name > VALID_HOSTNAME_LEN) {
|
|
msg_warn("%s: bad length %d for %.100s...", myname, cp - name, name);
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/* valid_hostaddr - test dotted quad string for correctness */
|
|
|
|
int valid_hostaddr(const char *addr)
|
|
{
|
|
const char *cp;
|
|
const char *myname = "valid_hostaddr";
|
|
int in_byte = 0;
|
|
int byte_count = 0;
|
|
int byte_val = 0;
|
|
int ch;
|
|
|
|
#define BYTES_NEEDED 4
|
|
|
|
/*
|
|
* Trivial cases first.
|
|
*/
|
|
if (*addr == 0) {
|
|
msg_warn("%s: empty address", myname);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Scary code to avoid sscanf() overflow nasties.
|
|
*/
|
|
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) {
|
|
msg_warn("%s: invalid octet value: %.100s", myname, addr);
|
|
return (0);
|
|
}
|
|
} else if (ch == '.') {
|
|
if (in_byte == 0 || cp[1] == 0) {
|
|
msg_warn("%s: misplaced dot: %.100s", myname, addr);
|
|
return (0);
|
|
}
|
|
if ((byte_count == 1 && byte_val == 0)) {
|
|
msg_warn("%s: bad initial octet value: %.100s", myname, addr);
|
|
return (0);
|
|
}
|
|
in_byte = 0;
|
|
} else {
|
|
msg_warn("%s: invalid character %d(decimal): %.100s",
|
|
myname, ch, addr);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
if (byte_count != BYTES_NEEDED) {
|
|
msg_warn("%s: invalid octet count: %.100s", myname, addr);
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
#ifdef TEST
|
|
|
|
/*
|
|
* Test program - reads hostnames from stdin, reports invalid hostnames to
|
|
* stderr.
|
|
*/
|
|
#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));
|
|
valid_hostaddr(vstring_str(buffer));
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
#endif
|