2N/A/*
2N/A * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A /*
2N/A * Misc routines that are used by tcpd and by tcpdchk.
2N/A *
2N/A * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
2N/A */
2N/A
2N/A#ifndef lint
2N/Astatic char sccsic[] = "@(#) misc.c 1.2 96/02/11 17:01:29";
2N/A#endif
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/param.h>
2N/A#include <netinet/in.h>
2N/A#include <arpa/inet.h>
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A#include <ctype.h>
2N/A#include <netdb.h>
2N/A
2N/A#include "tcpd.h"
2N/A
2N/Aextern char *fgets();
2N/A
2N/A#ifndef INADDR_NONE
2N/A#define INADDR_NONE (-1) /* XXX should be 0xffffffff */
2N/A#endif
2N/A
2N/A/* xgets - fgets() with backslash-newline stripping */
2N/A
2N/Achar *xgets(ptr, len, fp)
2N/Achar *ptr;
2N/Aint len;
2N/AFILE *fp;
2N/A{
2N/A int got;
2N/A char *start = ptr;
2N/A
2N/A while (fgets(ptr, len, fp)) {
2N/A got = strlen(ptr);
2N/A if (got >= 1 && ptr[got - 1] == '\n') {
2N/A tcpd_context.line++;
2N/A if (got >= 2 && ptr[got - 2] == '\\') {
2N/A got -= 2;
2N/A } else {
2N/A return (start);
2N/A }
2N/A }
2N/A ptr += got;
2N/A len -= got;
2N/A ptr[0] = 0;
2N/A }
2N/A return (ptr > start ? start : 0);
2N/A}
2N/A
2N/A/* split_at - break string at delimiter or return NULL */
2N/A
2N/Achar *split_at(string, delimiter)
2N/Achar *string;
2N/Aint delimiter;
2N/A{
2N/A char *cp;
2N/A
2N/A if ((cp = strchr(string, delimiter)) != 0)
2N/A *cp++ = 0;
2N/A return (cp);
2N/A}
2N/A
2N/A/* dot_quad_addr - convert dotted quad to internal form */
2N/A
2N/Aunsigned long dot_quad_addr(str)
2N/Achar *str;
2N/A{
2N/A int in_run = 0;
2N/A int runs = 0;
2N/A char *cp = str;
2N/A
2N/A /* Count the number of runs of non-dot characters. */
2N/A
2N/A while (*cp) {
2N/A if (*cp == '.') {
2N/A in_run = 0;
2N/A } else if (in_run == 0) {
2N/A in_run = 1;
2N/A runs++;
2N/A }
2N/A cp++;
2N/A }
2N/A return (runs == 4 ? inet_addr(str) : INADDR_NONE);
2N/A}
2N/A
2N/A/* numeric_addr - convert textual IP address to binary form */
2N/A
2N/Aint numeric_addr(str, addr, af, len)
2N/Achar *str;
2N/Aunion gen_addr *addr;
2N/Aint *af;
2N/Aint *len;
2N/A{
2N/A union gen_addr t;
2N/A
2N/A if (addr == NULL)
2N/A addr = &t;
2N/A#ifdef HAVE_IPV6
2N/A if (strchr(str,':')) {
2N/A if (af) *af = AF_INET6;
2N/A if (len) *len = sizeof(struct in6_addr);
2N/A if (inet_pton(AF_INET6, str, (void*) addr) == 1)
2N/A return 0;
2N/A return -1;
2N/A }
2N/A#endif
2N/A if (af) *af = AF_INET;
2N/A if (len) *len = sizeof(struct in_addr);
2N/A addr->ga_in.s_addr = dot_quad_addr(str);
2N/A return addr->ga_in.s_addr == INADDR_NONE ? -1 : 0;
2N/A}
2N/A
2N/A/* For none RFC 2553 compliant systems */
2N/A#ifdef USE_GETHOSTBYNAME2
2N/A#define getipnodebyname(h,af,flags,err) gethostbyname2(h,af)
2N/A#define freehostent(x) x = 0
2N/A#endif
2N/A
2N/A/* tcpd_gethostbyname - an IP family neutral gethostbyname */
2N/A
2N/Astruct hostent *tcpd_gethostbyname(host, af)
2N/Achar *host;
2N/Aint af;
2N/A{
2N/A#ifdef HAVE_IPV6
2N/A struct hostent *hp;
2N/A static struct hostent *hs; /* freehostent() on next call */
2N/A int err;
2N/A
2N/A if (af == AF_INET6) { /* must be AF_INET6 */
2N/A if (hs)
2N/A freehostent(hs);
2N/A return (hs = getipnodebyname(host, AF_INET6, 0, &err));
2N/A }
2N/A hp = gethostbyname(host);
2N/A if (hp != NULL || af == AF_INET) { /* found or must be AF_INET */
2N/A return hp;
2N/A } else { /* Try INET6 */
2N/A if (hs)
2N/A freehostent(hs);
2N/A return (hs = getipnodebyname(host, AF_INET6, 0, &err));
2N/A }
2N/A#else
2N/A return gethostbyname(host);
2N/A#endif
2N/A}
2N/A
2N/A#ifdef HAVE_IPV6
2N/A/*
2N/A * When using IPv6 addresses, we'll be seeing lots of ":"s;
2N/A * we require the addresses to be specified as [address].
2N/A * An IPv6 address can be specified in 3 ways:
2N/A *
2N/A * x:x:x:x:x:x:x:x (fully specified)
2N/A * x::x:x:x:x (zeroes squashed)
2N/A * ::FFFF:1.2.3.4 (IPv4 mapped)
2N/A *
2N/A * These need to be skipped to get at the ":" delimeters.
2N/A *
2N/A * We also allow a '/prefix' specifier.
2N/A */
2N/Achar *skip_ipv6_addrs(str)
2N/Achar *str;
2N/A{
2N/A char *obr, *cbr, *colon;
2N/A char *p = str;
2N/A char *q;
2N/A
2N/A while (1) {
2N/A if ((colon = strchr(p, ':')) == NULL)
2N/A return p;
2N/A if ((obr = strchr(p, '[')) == NULL || obr > colon)
2N/A return p;
2N/A if ((cbr = strchr(obr, ']')) == NULL)
2N/A return p;
2N/A
2N/A for (q = obr + 1; q < cbr; q++) {
2N/A /*
2N/A * Quick and dirty parse, cheaper than inet_pton
2N/A * Could count colons and dots (must be 0 or 3 dots, no
2N/A * colons after dots seens, only one double :, etc, etc)
2N/A */
2N/A if (*q != ':' && *q != '.' && *q != '/' && !isxdigit(*q & 0xff))
2N/A return p;
2N/A }
2N/A p = cbr + 1;
2N/A }
2N/A}
2N/A#endif /* HAVE_IPV6 */