David van Moolenbroek 00b67f09dd Import NetBSD named(8)
Also known as ISC bind.  This import adds utilities such as host(1),
dig(1), and nslookup(1), as well as many other tools and libraries.

Change-Id: I035ca46e64f1965d57019e773f4ff0ef035e4aa3
2017-03-21 22:00:06 +00:00

335 lines
9.4 KiB
C

/* $NetBSD: domaincmp.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $ */
/*****************************************************************
**
** @(#) domaincmp.c -- compare two domain names
**
** Copyright (c) Aug 2005, Karle Boss, Holger Zuleger (kaho).
** isparentdomain() (c) Mar 2010 by Holger Zuleger
** All rights reserved.
**
** This software is open source.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** Redistributions of source code must retain the above copyright notice,
** this list of conditions and the following disclaimer.
**
** Redistributions in binary form must reproduce the above copyright notice,
** this list of conditions and the following disclaimer in the documentation
** and/or other materials provided with the distribution.
**
** Neither the name of Karle Boss or Holger Zuleger (kaho) nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
**
*****************************************************************/
# include <stdio.h>
# include <string.h>
# include <assert.h>
# include <ctype.h>
#define extern
# include "domaincmp.h"
#undef extern
#define goto_labelstart(str, p) while ( (p) > (str) && *((p)-1) != '.' ) \
(p)--
/*****************************************************************
** int domaincmp (a, b)
** compare a and b as fqdns.
** return <0 | 0 | >0 as in strcmp
** A subdomain is less than the corresponding parent domain,
** thus domaincmp ("z.example.net", "example.net") return < 0 !!
*****************************************************************/
int domaincmp (const char *a, const char *b)
{
return domaincmp_dir (a, b, 1);
}
/*****************************************************************
** int domaincmp_dir (a, b, subdomain_above)
** compare a and b as fqdns.
** return <0 | 0 | >0 as in strcmp
** A subdomain is less than the corresponding parent domain,
** thus domaincmp ("z.example.net", "example.net") return < 0 !!
*****************************************************************/
int domaincmp_dir (const char *a, const char *b, int subdomain_above)
{
register const char *pa;
register const char *pb;
int dir;
if ( a == NULL ) return -1;
if ( b == NULL ) return 1;
if ( subdomain_above )
dir = 1;
else
dir = -1;
if ( *a == '.' ) /* skip a leading dot */
a++;
if ( *b == '.' ) /* same at the other string */
b++;
/* let pa and pb point to the last non dot char */
pa = a + strlen (a);
do
pa--;
while ( pa > a && *pa == '.' );
pb = b + strlen (b);
do
pb--;
while ( pb > b && *pb == '.' );
/* cmp both domains starting at the end */
while ( *pa == *pb && pa > a && pb > b )
pa--, pb--;
if ( *pa != *pb ) /* both domains are different ? */
{
if ( *pa == '.' )
pa++; /* set to beginning of next label */
else
goto_labelstart (a, pa); /* find begin of current label */
if ( *pb == '.' )
pb++; /* set to beginning of next label */
else
goto_labelstart (b, pb); /* find begin of current label */
}
else /* maybe one of them has a subdomain */
{
if ( pa > a )
if ( pa[-1] == '.' )
return -1 * dir;
else
goto_labelstart (a, pa);
else if ( pb > b )
if ( pb[-1] == '.' )
return 1 * dir;
else
goto_labelstart (b, pb);
else
return 0; /* both are at the beginning, so they are equal */
}
/* both domains are definitly unequal */
while ( *pa == *pb ) /* so we have to look at the point where they differ */
pa++, pb++;
return *pa - *pb;
}
/*****************************************************************
**
** int issubdomain ("child", "parent")
**
** "child" and "parent" are standardized domain names in such
** a way that even both domain names are ending with a dot,
** or none of them.
**
** returns 1 if "child" is a subdomain of "parent"
** returns 0 if "child" is not a subdomain of "parent"
**
*****************************************************************/
int issubdomain (const char *child, const char *parent)
{
const char *p;
const char *cdot;
int ccnt;
int pcnt;
if ( !child || !parent || *child == '\0' || *parent == '\0' )
return 0;
cdot = NULL;
pcnt = 0;
for ( p = parent; *p; p++ )
if ( *p == '.' )
pcnt++;
ccnt = 0;
for ( p = child; *p; p++ )
if ( *p == '.' )
{
if ( ccnt == 0 )
cdot = p;
ccnt++;
}
if ( ccnt == 0 ) /* child is not a fqdn or is not deep enough ? */
return 0;
if ( pcnt == 0 ) /* parent is not a fqdn ? */
return 0;
if ( pcnt >= ccnt ) /* parent has more levels than child ? */
return 0;
/* is child a (one level) subdomain of parent ? */
if ( strcmp (cdot+1, parent) == 0 ) /* the domains are equal ? */
return 1;
return 0;
}
/*****************************************************************
**
** int isparentdomain ("child", "parent", level)
**
** "child" and "parent" are standardized domain names in such
** a way that even both domain names are ending with a dot,
** or none of them.
**
** returns 1 if "child" is a subdomain of "parent"
** returns 0 if "child" is not a subdomain of "parent"
** returns -1 if "child" and "parent" are the same domain
**
*****************************************************************/
int isparentdomain (const char *child, const char *parent, int level)
{
const char *p;
const char *cdot;
const char *pdot;
int ccnt;
int pcnt;
if ( !child || !parent || *child == '\0' || *parent == '\0' )
return 0;
pdot = cdot = NULL;
pcnt = 0;
for ( p = parent; *p; p++ )
if ( *p == '.' )
{
if ( pcnt == 0 )
pdot = p;
pcnt++;
}
ccnt = 0;
for ( p = child; *p; p++ )
if ( *p == '.' )
{
if ( ccnt == 0 )
cdot = p;
ccnt++;
}
if ( ccnt == 0 || ccnt < level ) /* child is not a fqdn or is not deep enough ? */
return 0;
if ( pcnt == 0 ) /* parent is not a fqdn ? */
return 0;
if ( pcnt > ccnt ) /* parent has more levels than child ? */
return 0;
if ( pcnt == ccnt ) /* both are at the same level ? */
{
/* let's check the domain part */
if ( strcmp (cdot, pdot) == 0 ) /* the domains are equal ? */
return -1;
return 0;
}
if ( pcnt > ccnt ) /* parent has more levels than child ? */
return 0;
/* is child a (one level) subdomain of parent ? */
if ( strcmp (cdot+1, parent) == 0 ) /* the domains are equal ? */
return 1;
return 0;
}
#ifdef DOMAINCMP_TEST
static struct {
char *a;
char *b;
int res;
} ex[] = {
{ ".", ".", 0 },
{ "test", "", 1 },
{ "", "test2", -1 },
{ "", "", 0 },
{ "de", "de", 0 },
{ ".de", "de", 0 },
{ "de.", "de.", 0 },
{ ".de", ".de", 0 },
{ ".de.", ".de.", 0 },
{ ".de", "zde", -1 },
{ ".de", "ade", 1 },
{ "zde", ".de", 1 },
{ "ade", ".de", -1 },
{ "a.de", ".de", -1 },
{ ".de", "a.de", 1 },
{ "a.de", "b.de", -1 },
{ "a.de.", "b.de", -1 },
{ "a.de", "b.de.", -1 },
{ "a.de", "a.de.", 0 },
{ "aa.de", "b.de", -1 },
{ "ba.de", "b.de", 1 },
{ "a.de", "a.dk", -1 },
{ "anna.example.de", "anna.example.de", 0 },
{ "anna.example.de", "annamirl.example.de", -1 },
{ "anna.example.de", "ann.example.de", 1 },
{ "example.de.", "xy.example.de.", 1 },
{ "example.de.", "ab.example.de.", 1 },
{ "example.de", "ab.example.de", 1 },
{ "xy.example.de.", "example.de.", -1 },
{ "ab.example.de.", "example.de.", -1 },
{ "ab.example.de", "example.de", -1 },
{ "ab.mast.de", "axt.de", 1 },
{ "ab.mast.de", "obt.de", -1 },
{ "abc.example.de.", "xy.example.de.", -1 },
{ NULL, NULL, 0 }
};
const char *progname;
main (int argc, char *argv[])
{
int expect;
int res;
int c;
int i;
progname = *argv;
for ( i = 0; ex[i].a; i++ )
{
expect = ex[i].res;
if ( expect < 0 )
c = '<';
else if ( expect > 0 )
c = '>';
else
c = '=';
printf ("%-20s %-20s ", ex[i].a, ex[i].b);
printf ("%3d ", issubdomain (ex[i].a, ex[i].b));
printf ("\t==> 0 %c ", c);
fflush (stdout);
res = domaincmp (ex[i].a, ex[i].b);
printf ("%3d ", res);
if ( res < 0 && expect < 0 || res > 0 && expect > 0 || res == 0 && expect == 0 )
puts ("ok");
else
puts ("not ok");
}
}
#endif