1 | /*************************************** 2 | $Revision: 1.15 $ 3 | 4 | Example code: Determine which keys to look for. 5 | 6 | This is based on the C code that was reversed engineered from existing Perl 7 | code. (~ottrey/which_table/which_table.c) 8 | 9 | ******************/ /****************** 10 | Copyright (c) 1999 RIPE NCC 11 | 12 | All Rights Reserved 13 | 14 | Permission to use, copy, modify, and distribute this software and its 15 | documentation for any purpose and without fee is hereby granted, 16 | provided that the above copyright notice appear in all copies and that 17 | both that copyright notice and this permission notice appear in 18 | supporting documentation, and that the name of the author not be 19 | used in advertising or publicity pertaining to distribution of the 20 | software without specific, written prior permission. 21 | 22 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 23 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 24 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 25 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 26 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 27 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 28 | ***************************************/ 29 | #include <stdio.h> 30 | #include <stdlib.h> 31 | #include <strings.h> 32 | #include <libgen.h> 33 | #include <glib.h> 34 | 35 | #include "isnic.h" 36 | #include "bitmask.h" 37 | #include "memwrap.h" 38 | 39 | #define WK_IMPL 40 | #include "which_keytypes.h" 41 | 42 | 43 | 44 | #define DOMAINNAME "^[ ]*[a-zA-Z0-9--]*(\\.[a-zA-Z0-9--]+)*[ ]*$" 45 | /* add a constraint: there must be at least one character in the domain name 46 | because the TLD must not be composed of digits only */ 47 | #define DOMAINALPHA "[a-zA-Z]" 48 | 49 | #define LEN_MIN 0 50 | #define LEN_MAX 32 51 | 52 | #define NETLEN 16 53 | #define NETQUADS 4 54 | #define NETQUAD_MIN 0 55 | #define NETQUAD_MAX 255 56 | 57 | #define ASNUM_MIN 1 58 | #define ASNUM_MAX 65535 59 | #define ASNUM_NUMOFFSET 2 /* XXX - (This is really kludgy!) Offset to the number bit of ASNUM */ 60 | 61 | #define VALIDIP6PREFIX "^[0-9A-F:]*:[0-9A-F:/]*$" /* at least one colon */ 62 | /* "^[0-9A-F]{1,4}(:[0-9A-F]{1,4}){7}$"*/ 63 | 64 | #define NET "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$" 65 | 66 | #define ASNUM "^AS[1-9]+[0-9]*$" 67 | 68 | #define ASRANGE "^AS[0-9]+[ ]*([-][ ]*AS[0-9]+){0,1}$" /* [ ]*(-[ ]*AS[0-9]+)? */ 69 | 70 | #define NETNAME "^[A-Z][A-Z0-9-]*$" 71 | 72 | #define MAINTAINER "^[A-Z][A-Z0-9-]*$" 73 | 74 | #define LIMERICK "^LIM-[A-Z0-9-]+$" 75 | 76 | #define KEYCERT "^PGPKEY-[0-9A-F]{8}$" 77 | 78 | #define ROUTESETNAME "^RS-[A-Z0-9-_]*$" 79 | 80 | #define ASSETNAME "^AS-[A-Z0-9-_]*$" 81 | 82 | #define AUTONICPREFIXREGULAR "^AUTO-" 83 | 84 | #define IPRANGE "^[0-9]{1,3}(\\.[0-9]{1,3}){0,3}[ ]*-[ ]*[0-9]{1,3}(\\.[0-9]{1,3}){0,3}$" 85 | 86 | #define IPADDRESS "^[0-9.]+$" 87 | 88 | #define IPPREFIX "^[0-9.]+/[0-9]+$" 89 | 90 | #define PEERINGSET "^PRNG-" 91 | 92 | #define FILTERSET "^FLTR-" 93 | 94 | #define RTRSET "^RTRS-" 95 | 96 | /* 97 | XXX This seems to be the same as the Perl code. But I don't see where a " " is allowed for. 98 | I.e. Perl -> ^[a-zA-Z][\w\-\.\'\|\`]*$ 99 | Does \w include [ ;:,?/}{()+*#] ? 100 | #define NAME_B "^[a-zA-Z][a-zA-Z_0-9.'|`-]*$" 101 | */ 102 | #define NAME_B "^[a-zA-Z][a-zA-Z_0-9.'|`;:,?/}{()+*#&-]*$" 103 | 104 | #define VALIDIP4PREFIX 105 | 106 | #define EMAIL "^[.a-zA-Z0-9--]*@[a-zA-Z0-9--]*(\\.[a-zA-Z0-9--]+)*$" 107 | 108 | static int perform_regex_test(const char *pattern, char *string) { 109 | int match; 110 | 111 | char *re; 112 | 113 | re = regcmp(pattern, (char*)0); 114 | if (regex(re, string) == NULL) { 115 | match = 0; 116 | } 117 | else { 118 | match = 1; 119 | } 120 | 121 | free(re); /* not a wrapper, because we have not allocated it */ 122 | 123 | return match; 124 | } /* perform_regex_test() */ 125 | 126 | static int isasnum(char *string) { 127 | int result='-'; 128 | int as_value; 129 | 130 | /* First check if the string matches an ASNUM */ 131 | result = perform_regex_test(ASNUM, string); 132 | 133 | /* Then check if the value is between ASNUM_MIN and ASNUM_MAX */ 134 | if (result == 1) { 135 | as_value = atoi(string+ASNUM_NUMOFFSET); 136 | if ((as_value < ASNUM_MIN) || (as_value > ASNUM_MAX)) { 137 | /* an invalid value */ 138 | result=0; 139 | } 140 | } 141 | 142 | return result; 143 | } 144 | 145 | /******************************************************* 146 | # the problem is as follows: 147 | # 148 | # we can never find out which NIC handles are possible on the 149 | # globe since we don't know that they exist 150 | # 151 | # we want to solve this with once with DNS : 152 | # 153 | # RIPE.registries.int CNAME whois.ripe.net 154 | # InterNIC.registries.int CNAME whois.internic.net 155 | # and so on... 156 | 157 | # 158 | # 1) it first does a basic syntax check 159 | # 160 | # notes: 161 | # 162 | # - catches InterNIC handles 163 | # - catches the JP|JP-JP APNIC exceptions 164 | # - limits the number of initials to three with a good reason: 165 | # we have a much better chance to find syntax errors like: 166 | # RIPE-DK13 and other problems like this 167 | # 168 | # 2) checks for valid suffixes 169 | # - all 'source:' attribute values from sites that we mirror 170 | # are allowed 171 | # - country codes are allowed for APNIC compatibility 172 | # - APNIC AP|CC-AU exceptions are handled correctly 173 | # - -ORG organization InterNIC handles 174 | # - -ARIN ARIN handles 175 | # - -ORG-ARIN ARIN handles 176 | ********************************************************/ 177 | static int isnichandle(char *nichdl) { 178 | 179 | char *regexp, *match; 180 | char ret[1024]; 181 | char *suffix; 182 | 183 | int i; 184 | 185 | /* set ret to the empty string */ 186 | ret[0]='\0'; 187 | 188 | /* 189 | # Japanese NIC handles 190 | # 191 | # leading zeros in the number part *are* allowed 192 | # 193 | # e.g. AB021JP AB199JP-JP 194 | # 195 | */ 196 | regexp = regcmp("[A-Z]{2}[0-9]{3}JP(-JP){0,1}",(char *)0); 197 | match = regex(regexp,nichdl); 198 | free(regexp); /* not a wrapper, because we have not allocated it */ 199 | if (match) return 1; 200 | 201 | /* 202 | # Standard NIC handles 203 | # 204 | # leading zeros in the number part are *not* allowed 205 | # 206 | # InterNIC - TBQ, IP4 207 | # RIPE format - AB1-RIPE 208 | # APNIC use two letter country code suffix 209 | # Austraila have used -1-AU, -2-AU, -CC-AU suffix. 210 | # Internic used -ORG suffix 211 | # ARIN use -ARIN suffix 212 | # ARIN also use -ORG-ARIN suffix 213 | # 214 | */ 215 | regexp = regcmp("^[A-Z]{2,4}([1-9][0-9]{0,5}){0,1}((-[^ ]+){0,1})$0$",(char *)0); 216 | match = regex(regexp,nichdl,ret); 217 | 218 | free(regexp); /* not a wrapper, because we have not allocated it */ 219 | 220 | if (match == NULL) { 221 | return 0; 222 | } else { 223 | if (ret[0] == '\0') { 224 | return 1; 225 | } else { 226 | /* strip leading '-' */ 227 | suffix = ret+1; 228 | /* suffix of local sources */ 229 | for (i=0;i<=NUM_NICPOSTFIX;i++) { 230 | if ( !strcmp(suffix,nicpostfix[i]) ) { 231 | return 1; 232 | } 233 | } 234 | /* country codes */ 235 | for (i=0;i<NUM_COUNTRIES;i++) { 236 | if ( !strcmp(suffix,countries[i]) ) { 237 | return 1; 238 | } 239 | } 240 | /* special suffix */ 241 | for (i=0;i<NUM_SPECIAL;i++) { 242 | if ( !strcmp(suffix,special[i]) ) { 243 | return 1; 244 | } 245 | } 246 | } 247 | } 248 | return 0; 249 | } /* isnichandle() */ 250 | 251 | static int isdomname(char *string) { 252 | return ( perform_regex_test(DOMAINNAME, string) 253 | && perform_regex_test(DOMAINALPHA, string)); 254 | } 255 | 256 | /* 257 | I split the isname up into isname_a & isname_b. And created isname_ab to join them together. 258 | - So I can test it properly. -ottrey 259 | */ 260 | static int isname_a(char *string) { 261 | return perform_regex_test(AUTONICPREFIXREGULAR, string); 262 | } 263 | 264 | static int isname_b(char *string) { 265 | return perform_regex_test(NAME_B, string); 266 | } 267 | 268 | static int isname_ab(char *string) { 269 | return (isname_a(string) || isname_b(string)); 270 | } 271 | 272 | static int isnetname(char *string) { 273 | return perform_regex_test(NETNAME, string); 274 | } /* wk_is_netname() */ 275 | 276 | static int wk_is_name(char *key) { 277 | /* Everything matches to name */ 278 | return 1; 279 | } /* wk_is_name() */ 280 | 281 | static int wk_is_nic_hdl(char *key) { 282 | return isnichandle(key); 283 | } /* wk_is_nic_hdl() */ 284 | 285 | static int wk_is_email(char *key) { 286 | return perform_regex_test(EMAIL, key); 287 | } /* wk_is_email() */ 288 | 289 | static int wk_is_mntner(char *key) { 290 | return perform_regex_test(MAINTAINER, key); 291 | } /* wk_is_mntner() */ 292 | 293 | static int wk_is_key_cert(char *key) { 294 | return perform_regex_test(KEYCERT, key); 295 | } /* wk_is_key_cert() */ 296 | 297 | static int wk_is_ipaddress(char *key) { 298 | return perform_regex_test(IPADDRESS, key); 299 | } /* wk_is_key_cert() */ 300 | 301 | static int wk_is_iprange(char *key) { 302 | return perform_regex_test(IPRANGE, key); 303 | } /* wk_is_iprange() */ 304 | 305 | static int wk_is_ipprefix(char *key) { 306 | return perform_regex_test(IPPREFIX, key); 307 | } /* wk_is_iprange() */ 308 | 309 | static int wk_is_ip6prefix(char *key) { 310 | return perform_regex_test(VALIDIP6PREFIX, key); 311 | } /* wk_is_ip6prefix() */ 312 | 313 | static int wk_is_netname(char *key) { 314 | return isnetname(key); 315 | } /* wk_is_netname() */ 316 | 317 | /* XXX Note: This function uses the same call as wk_is_netname(). */ 318 | static int wk_is_net6name(char *key) { 319 | return isnetname(key); 320 | } /* wk_is_netname() */ 321 | 322 | static int wk_is_autnum(char *key) { 323 | return isasnum(key); 324 | } /* wk_is_autnum() */ 325 | 326 | static int wk_is_asrange(char *key) { 327 | return perform_regex_test(ASRANGE, key); 328 | } /* wk_is_autnum() */ 329 | 330 | static int wk_is_assetname(char *key) { 331 | return perform_regex_test(ASSETNAME, key); 332 | } /* wk_is_assetname() */ 333 | 334 | static int wk_is_routesetname(char *key) { 335 | return perform_regex_test(ROUTESETNAME, key); 336 | } /* wk_is_routesetname() */ 337 | 338 | static int wk_is_domain(char *key) { 339 | return isdomname(key); 340 | } /* wk_is_domname() */ 341 | 342 | static int wk_is_hostname(char *key) { 343 | /* XXX Why is there a hostname & a domainname? */ 344 | /* Answer - hostname can be a domainname or an IP */ 345 | return (isdomname(key) || wk_is_iprange(key)); 346 | } /* wk_is_hostname() */ 347 | 348 | static int wk_is_limerick(char *key) { 349 | return perform_regex_test(LIMERICK, key); 350 | } /* wk_is_limerick() */ 351 | 352 | static int wk_is_peeringset(char *key) { 353 | return perform_regex_test(PEERINGSET, key); 354 | } /* wk_is_peeringset() */ 355 | 356 | static int wk_is_rtrset(char *key) { 357 | return perform_regex_test(RTRSET, key); 358 | } /* wk_is_rtrset() */ 359 | 360 | static int wk_is_filterset(char *key) { 361 | return perform_regex_test(FILTERSET, key); 362 | } /* wk_is_filterset() */ 363 | 364 | /* WK_to_string() */ 365 | /*++++++++++++++++++++++++++++++++++++++ 366 | Convert the which keytypes bitmap into a string. 367 | 368 | mask_t wk The which keytypes mask to be converted. 369 | 370 | More: 371 | +html+ <PRE> 372 | Authors: 373 | ottrey 374 | +html+ </PRE><DL COMPACT> 375 | +html+ <DT>Online References: 376 | +html+ <DD><UL> 377 | +html+ </UL></DL> 378 | 379 | ++++++++++++++++++++++++++++++++++++++*/ 380 | char *WK_to_string(mask_t wk) { 381 | 382 | return MA_to_string(wk, Keytypes); 383 | 384 | } /* WK_to_string() */ 385 | 386 | /* WK_new() */ 387 | /*++++++++++++++++++++++++++++++++++++++ 388 | Create a new which keytypes bitmap. 389 | 390 | char *key The key to be examined. 391 | 392 | More: 393 | +html+ <PRE> 394 | Authors: 395 | ottrey 396 | +html+ </PRE><DL COMPACT> 397 | +html+ <DT>Online References: 398 | +html+ <DD><UL> 399 | +html+ </UL></DL> 400 | 401 | ++++++++++++++++++++++++++++++++++++++*/ 402 | mask_t WK_new(char *key) { 403 | mask_t wk; 404 | 405 | wk = MA_new(MA_END); 406 | 407 | MA_set(&wk, WK_NAME, wk_is_name(key)); 408 | MA_set(&wk, WK_NIC_HDL, wk_is_nic_hdl(key)); 409 | MA_set(&wk, WK_EMAIL, wk_is_email(key)); 410 | MA_set(&wk, WK_MNTNER, wk_is_mntner(key)); 411 | MA_set(&wk, WK_KEY_CERT, wk_is_key_cert(key)); 412 | MA_set(&wk, WK_IPADDRESS, wk_is_ipaddress(key)); 413 | MA_set(&wk, WK_IPRANGE, wk_is_iprange(key)); 414 | MA_set(&wk, WK_IPPREFIX, wk_is_ipprefix(key)); 415 | MA_set(&wk, WK_IP6PREFIX, wk_is_ip6prefix(key)); 416 | MA_set(&wk, WK_NETNAME, wk_is_netname(key)); 417 | MA_set(&wk, WK_NET6NAME, wk_is_net6name(key)); 418 | MA_set(&wk, WK_AUTNUM, wk_is_autnum(key)); 419 | MA_set(&wk, WK_ASSETNAME, wk_is_assetname(key)); 420 | MA_set(&wk, WK_ROUTESETNAME, wk_is_routesetname(key)); 421 | MA_set(&wk, WK_DOMAIN, wk_is_domain(key)); 422 | MA_set(&wk, WK_HOSTNAME, wk_is_hostname(key)); 423 | MA_set(&wk, WK_LIMERICK, wk_is_limerick(key)); 424 | MA_set(&wk, WK_ASRANGE, wk_is_asrange(key)); 425 | MA_set(&wk, WK_PEERINGSET, wk_is_peeringset(key)); 426 | MA_set(&wk, WK_FILTERSET, wk_is_filterset(key)); 427 | MA_set(&wk, WK_RTRSET, wk_is_rtrset(key)); 428 | 429 | return wk; 430 | 431 | } /* WK_new() */