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() */