
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
335 lines
9.4 KiB
C
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
|