1 /* $NetBSD: domaincmp.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $ */ 2 3 /***************************************************************** 4 ** 5 ** @(#) domaincmp.c -- compare two domain names 6 ** 7 ** Copyright (c) Aug 2005, Karle Boss, Holger Zuleger (kaho). 8 ** isparentdomain() (c) Mar 2010 by Holger Zuleger 9 ** All rights reserved. 10 ** 11 ** This software is open source. 12 ** 13 ** Redistribution and use in source and binary forms, with or without 14 ** modification, are permitted provided that the following conditions 15 ** are met: 16 ** 17 ** Redistributions of source code must retain the above copyright notice, 18 ** this list of conditions and the following disclaimer. 19 ** 20 ** Redistributions in binary form must reproduce the above copyright notice, 21 ** this list of conditions and the following disclaimer in the documentation 22 ** and/or other materials provided with the distribution. 23 ** 24 ** Neither the name of Karle Boss or Holger Zuleger (kaho) nor the 25 ** names of its contributors may be used to endorse or promote products 26 ** derived from this software without specific prior written permission. 27 ** 28 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 32 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 ** POSSIBILITY OF SUCH DAMAGE. 39 ** 40 *****************************************************************/ 41 # include <stdio.h> 42 # include <string.h> 43 # include <assert.h> 44 # include <ctype.h> 45 #define extern 46 # include "domaincmp.h" 47 #undef extern 48 49 50 #define goto_labelstart(str, p) while ( (p) > (str) && *((p)-1) != '.' ) \ 51 (p)-- 52 53 /***************************************************************** 54 ** int domaincmp (a, b) 55 ** compare a and b as fqdns. 56 ** return <0 | 0 | >0 as in strcmp 57 ** A subdomain is less than the corresponding parent domain, 58 ** thus domaincmp ("z.example.net", "example.net") return < 0 !! 59 *****************************************************************/ 60 int domaincmp (const char *a, const char *b) 61 { 62 return domaincmp_dir (a, b, 1); 63 } 64 65 /***************************************************************** 66 ** int domaincmp_dir (a, b, subdomain_above) 67 ** compare a and b as fqdns. 68 ** return <0 | 0 | >0 as in strcmp 69 ** A subdomain is less than the corresponding parent domain, 70 ** thus domaincmp ("z.example.net", "example.net") return < 0 !! 71 *****************************************************************/ 72 int domaincmp_dir (const char *a, const char *b, int subdomain_above) 73 { 74 register const char *pa; 75 register const char *pb; 76 int dir; 77 78 if ( a == NULL ) return -1; 79 if ( b == NULL ) return 1; 80 81 if ( subdomain_above ) 82 dir = 1; 83 else 84 dir = -1; 85 86 if ( *a == '.' ) /* skip a leading dot */ 87 a++; 88 if ( *b == '.' ) /* same at the other string */ 89 b++; 90 91 /* let pa and pb point to the last non dot char */ 92 pa = a + strlen (a); 93 do 94 pa--; 95 while ( pa > a && *pa == '.' ); 96 97 pb = b + strlen (b); 98 do 99 pb--; 100 while ( pb > b && *pb == '.' ); 101 102 /* cmp both domains starting at the end */ 103 while ( *pa == *pb && pa > a && pb > b ) 104 pa--, pb--; 105 106 if ( *pa != *pb ) /* both domains are different ? */ 107 { 108 if ( *pa == '.' ) 109 pa++; /* set to beginning of next label */ 110 else 111 goto_labelstart (a, pa); /* find begin of current label */ 112 if ( *pb == '.' ) 113 pb++; /* set to beginning of next label */ 114 else 115 goto_labelstart (b, pb); /* find begin of current label */ 116 } 117 else /* maybe one of them has a subdomain */ 118 { 119 if ( pa > a ) 120 if ( pa[-1] == '.' ) 121 return -1 * dir; 122 else 123 goto_labelstart (a, pa); 124 else if ( pb > b ) 125 if ( pb[-1] == '.' ) 126 return 1 * dir; 127 else 128 goto_labelstart (b, pb); 129 else 130 return 0; /* both are at the beginning, so they are equal */ 131 } 132 133 /* both domains are definitly unequal */ 134 while ( *pa == *pb ) /* so we have to look at the point where they differ */ 135 pa++, pb++; 136 137 return *pa - *pb; 138 } 139 140 /***************************************************************** 141 ** 142 ** int issubdomain ("child", "parent") 143 ** 144 ** "child" and "parent" are standardized domain names in such 145 ** a way that even both domain names are ending with a dot, 146 ** or none of them. 147 ** 148 ** returns 1 if "child" is a subdomain of "parent" 149 ** returns 0 if "child" is not a subdomain of "parent" 150 ** 151 *****************************************************************/ 152 int issubdomain (const char *child, const char *parent) 153 { 154 const char *p; 155 const char *cdot; 156 int ccnt; 157 int pcnt; 158 159 if ( !child || !parent || *child == '\0' || *parent == '\0' ) 160 return 0; 161 162 cdot = NULL; 163 pcnt = 0; 164 for ( p = parent; *p; p++ ) 165 if ( *p == '.' ) 166 pcnt++; 167 168 ccnt = 0; 169 for ( p = child; *p; p++ ) 170 if ( *p == '.' ) 171 { 172 if ( ccnt == 0 ) 173 cdot = p; 174 ccnt++; 175 } 176 if ( ccnt == 0 ) /* child is not a fqdn or is not deep enough ? */ 177 return 0; 178 if ( pcnt == 0 ) /* parent is not a fqdn ? */ 179 return 0; 180 181 if ( pcnt >= ccnt ) /* parent has more levels than child ? */ 182 return 0; 183 184 /* is child a (one level) subdomain of parent ? */ 185 if ( strcmp (cdot+1, parent) == 0 ) /* the domains are equal ? */ 186 return 1; 187 188 return 0; 189 } 190 191 /***************************************************************** 192 ** 193 ** int isparentdomain ("child", "parent", level) 194 ** 195 ** "child" and "parent" are standardized domain names in such 196 ** a way that even both domain names are ending with a dot, 197 ** or none of them. 198 ** 199 ** returns 1 if "child" is a subdomain of "parent" 200 ** returns 0 if "child" is not a subdomain of "parent" 201 ** returns -1 if "child" and "parent" are the same domain 202 ** 203 *****************************************************************/ 204 int isparentdomain (const char *child, const char *parent, int level) 205 { 206 const char *p; 207 const char *cdot; 208 const char *pdot; 209 int ccnt; 210 int pcnt; 211 212 if ( !child || !parent || *child == '\0' || *parent == '\0' ) 213 return 0; 214 215 pdot = cdot = NULL; 216 pcnt = 0; 217 for ( p = parent; *p; p++ ) 218 if ( *p == '.' ) 219 { 220 if ( pcnt == 0 ) 221 pdot = p; 222 pcnt++; 223 } 224 225 ccnt = 0; 226 for ( p = child; *p; p++ ) 227 if ( *p == '.' ) 228 { 229 if ( ccnt == 0 ) 230 cdot = p; 231 ccnt++; 232 } 233 if ( ccnt == 0 || ccnt < level ) /* child is not a fqdn or is not deep enough ? */ 234 return 0; 235 if ( pcnt == 0 ) /* parent is not a fqdn ? */ 236 return 0; 237 238 if ( pcnt > ccnt ) /* parent has more levels than child ? */ 239 return 0; 240 241 if ( pcnt == ccnt ) /* both are at the same level ? */ 242 { 243 /* let's check the domain part */ 244 if ( strcmp (cdot, pdot) == 0 ) /* the domains are equal ? */ 245 return -1; 246 return 0; 247 } 248 249 if ( pcnt > ccnt ) /* parent has more levels than child ? */ 250 return 0; 251 252 /* is child a (one level) subdomain of parent ? */ 253 if ( strcmp (cdot+1, parent) == 0 ) /* the domains are equal ? */ 254 return 1; 255 256 return 0; 257 } 258 259 #ifdef DOMAINCMP_TEST 260 static struct { 261 char *a; 262 char *b; 263 int res; 264 } ex[] = { 265 { ".", ".", 0 }, 266 { "test", "", 1 }, 267 { "", "test2", -1 }, 268 { "", "", 0 }, 269 { "de", "de", 0 }, 270 { ".de", "de", 0 }, 271 { "de.", "de.", 0 }, 272 { ".de", ".de", 0 }, 273 { ".de.", ".de.", 0 }, 274 { ".de", "zde", -1 }, 275 { ".de", "ade", 1 }, 276 { "zde", ".de", 1 }, 277 { "ade", ".de", -1 }, 278 { "a.de", ".de", -1 }, 279 { ".de", "a.de", 1 }, 280 { "a.de", "b.de", -1 }, 281 { "a.de.", "b.de", -1 }, 282 { "a.de", "b.de.", -1 }, 283 { "a.de", "a.de.", 0 }, 284 { "aa.de", "b.de", -1 }, 285 { "ba.de", "b.de", 1 }, 286 { "a.de", "a.dk", -1 }, 287 { "anna.example.de", "anna.example.de", 0 }, 288 { "anna.example.de", "annamirl.example.de", -1 }, 289 { "anna.example.de", "ann.example.de", 1 }, 290 { "example.de.", "xy.example.de.", 1 }, 291 { "example.de.", "ab.example.de.", 1 }, 292 { "example.de", "ab.example.de", 1 }, 293 { "xy.example.de.", "example.de.", -1 }, 294 { "ab.example.de.", "example.de.", -1 }, 295 { "ab.example.de", "example.de", -1 }, 296 { "ab.mast.de", "axt.de", 1 }, 297 { "ab.mast.de", "obt.de", -1 }, 298 { "abc.example.de.", "xy.example.de.", -1 }, 299 { NULL, NULL, 0 } 300 }; 301 302 const char *progname; 303 main (int argc, char *argv[]) 304 { 305 306 int expect; 307 int res; 308 int c; 309 int i; 310 311 progname = *argv; 312 313 for ( i = 0; ex[i].a; i++ ) 314 { 315 expect = ex[i].res; 316 if ( expect < 0 ) 317 c = '<'; 318 else if ( expect > 0 ) 319 c = '>'; 320 else 321 c = '='; 322 printf ("%-20s %-20s ", ex[i].a, ex[i].b); 323 printf ("%3d ", issubdomain (ex[i].a, ex[i].b)); 324 printf ("\t==> 0 %c ", c); 325 fflush (stdout); 326 res = domaincmp (ex[i].a, ex[i].b); 327 printf ("%3d ", res); 328 if ( res < 0 && expect < 0 || res > 0 && expect > 0 || res == 0 && expect == 0 ) 329 puts ("ok"); 330 else 331 puts ("not ok"); 332 } 333 } 334 #endif 335