1    | /***************************************
2    |   $Revision: 1.29 $
3    | 
4    |   which_keytypes:  Determine which keys to look for.
5    |   
6    |   This is based on the existing Perl code. 
7    | 
8    |   Authors: ottrey, marek
9    | 
10   |   ******************/ /******************
11   |   Copyright (c) 1999,2000,2001,2002               RIPE NCC
12   |  
13   |   All Rights Reserved
14   |   
15   |   Permission to use, copy, modify, and distribute this software and its
16   |   documentation for any purpose and without fee is hereby granted,
17   |   provided that the above copyright notice appear in all copies and that
18   |   both that copyright notice and this permission notice appear in
19   |   supporting documentation, and that the name of the author not be
20   |   used in advertising or publicity pertaining to distribution of the
21   |   software without specific, written prior permission.
22   |   
23   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
25   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
26   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
28   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29   |   ***************************************/
30   | 
31   | #define  WK_IMPL
32   | #include "rip.h"
33   | 
34   | #include <stdio.h>
35   | #include <stdlib.h>
36   | #include <strings.h>
37   | #include <glib.h>
38   | #include <pthread.h>
39   | #include <regex.h>
40   | 
41   | #define DOMAINNAME "^[ ]*[a-zA-Z0-9/-]*(\\.[a-zA-Z0-9-]+)*[ ]*$"
42   | /* add a constraint: there must be at least one character in the domain name
43   |    because the TLD must not be composed of digits only */
44   | #define DOMAINALPHA  "[a-zA-Z]"
45   | 
46   | #define VALIDIP6PREFIX "^[0-9A-F:]*:[0-9A-F:/]*$"     /* at least one colon */
47   | /* "^[0-9A-F]{1,4}(:[0-9A-F]{1,4}){7}$"*/
48   | 
49   | /* AS numbers, prepared for 32-bit AS numbers */
50   | #define ASNUM "^AS[1-9][0-9]{0,9}$"
51   | 
52   | /* AS numbers, prepared for 32-bit AS numbers */
53   | #define ASRANGE "^AS[1-9][0-9]{0,9}[ ]*([-][ ]*AS[1-9][0-9]{0,9}){0,1}$"   /* [ ]*(-[ ]*AS[0-9]+)?   */
54   | 
55   | #define NETNAME "^[A-Z][A-Z0-9_-]*$"
56   | 
57   | #define MAINTAINER "^[A-Z][A-Z0-9_-]*$"
58   | 
59   | #define LIMERICK "^LIM-[A-Z0-9_-]+$"
60   | 
61   | #define KEYCERT "^PGPKEY-[0-9A-F]{8}$"
62   | 
63   | /* made less restrictive to make consistent with other sets ... shane */
64   | /* made to match what we're actually looking for - shane */
65   | /*#define ROUTESETNAME "^RS-[A-Z0-9_:-]*$"*/
66   | #define ROUTESETNAME "(^|:)RS-[A-Z0-9_-]*[A-Z0-9](:|$)"
67   | 
68   | /* made less restrictive to make consistent with other sets ... shane */
69   | /* made to match what we're actually looking for - shane */
70   | /*#define ASSETNAME "^AS-[A-Z0-9_:-]*$"*/
71   | #define ASSETNAME "(^|:)AS-[A-Z0-9_-]*[A-Z0-9](:|$)" 
72   | 
73   | #define AUTONICPREFIXREGULAR "^AUTO-"
74   | 
75   | #define IPRANGE "^[0-9]{1,3}(\\.[0-9]{1,3}){0,3}[ ]*-[ ]*[0-9]{1,3}(\\.[0-9]{1,3}){0,3}$"
76   | 
77   | #define IPADDRESS "^[0-9.]+$"
78   | 
79   | #define IPPREFIX "^[0-9.]+/[0-9]+$"
80   | 
81   | /*#define PEERINGSET "^PRNG-"*/
82   | #define PEERINGSET "(^|:)PRNG-[A-Z0-9_-]*[A-Z0-9](:|$)" 
83   | 
84   | /*#define FILTERSET  "^FLTR-"*/
85   | #define FILTERSET "(^|:)FLTR-[A-Z0-9_-]*[A-Z0-9](:|$)" 
86   | 
87   | /*#define RTRSET     "^RTRS-"*/
88   | #define RTRSET "(^|:)RTRS-[A-Z0-9_-]*[A-Z0-9](:|$)" 
89   | 
90   | #define IRT "^IRT-[A-Z0-9_-]+[A-Z0-9]$"
91   | 
92   | #define NICHANDLE "^[A-Z0-9-]+$"
93   | 
94   | /*
95   |   XXX This seems to be the same as the Perl code.  But I don't see where a " " is allowed for.
96   |   I.e. Perl -> ^[a-zA-Z][\w\-\.\'\|\`]*$
97   |   Does \w include [ ;:,?/}{()+*#] ?
98   | #define NAME_B "^[a-zA-Z][a-zA-Z_0-9.'|`-]*$"
99   | */
100  | #define NAME_B "^[a-zA-Z][a-zA-Z_0-9.'|`;:,?/}{()+*#&-]*$"
101  | 
102  | #define EMAIL "@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$"
103  | 
104  | /* structure for simple keys, with a single regular expression to match */
105  | /* NOTE: the WK_NAME, WK_DOMAIN, and WK_HOSTNAME are not handled here   */
106  | struct {
107  |     int key_type;		/* identifier for key, e.g. WK_RTRSET */
108  |     char *pattern;		/* string for regular expression */
109  |     regex_t regex;		/* regular expression */
110  | } wk_regex_list[] = {
111  |     { WK_NIC_HDL,       NICHANDLE },
112  |     { WK_EMAIL,         EMAIL },
113  |     { WK_MNTNER,        MAINTAINER },
114  |     { WK_KEY_CERT,      KEYCERT },
115  |     { WK_IPRANGE,       IPRANGE },
116  |     { WK_IPADDRESS,     IPADDRESS },
117  |     { WK_IPPREFIX,      IPPREFIX },
118  |     { WK_IP6PREFIX,     VALIDIP6PREFIX },
119  |     { WK_NETNAME,       NETNAME },
120  |     { WK_NET6NAME,      NETNAME },
121  |     { WK_AUTNUM,        ASNUM },
122  |     { WK_ASSETNAME,     ASSETNAME },
123  |     { WK_ROUTESETNAME,  ROUTESETNAME },
124  |     { WK_LIMERICK,      LIMERICK },
125  |     { WK_ASRANGE,       ASRANGE },
126  |     { WK_PEERINGSET,    PEERINGSET },
127  |     { WK_FILTERSET,     FILTERSET },
128  |     { WK_RTRSET,        RTRSET },
129  |     { WK_IRT,           IRT }
130  | };
131  | #define WK_REGEX_LIST_LEN  (sizeof(wk_regex_list)/sizeof(wk_regex_list[0]))
132  | 
133  | /* regular expressions used by wk_is_name() */
134  | static regex_t ipaddress;
135  | static regex_t ipprefix;
136  | static regex_t validip6prefix;
137  | 
138  | /* regular expression used by isdomname() */
139  | static regex_t domainname;
140  | static regex_t domainalpha;
141  | 
142  | /* initialize regular expressions */
143  | static void 
144  | wk_regex_init ()
145  | {
146  |     int i;
147  |     int errcode;
148  | 
149  |     /* initialize our table */
150  |     for (i=0; i<WK_REGEX_LIST_LEN; i++) {
151  |         errcode = regcomp(&wk_regex_list[i].regex, 
152  | 	                  wk_regex_list[i].pattern, 
153  | 		          REG_EXTENDED|REG_NOSUB);
154  |         dieif(errcode != 0);
155  |     }
156  | 
157  |     /* add some special cases used by our other functions */
158  |     errcode = regcomp(&ipaddress, IPADDRESS, REG_EXTENDED|REG_NOSUB);
159  |     dieif(errcode != 0);
160  |     errcode = regcomp(&ipprefix, IPPREFIX, REG_EXTENDED|REG_NOSUB);
161  |     dieif(errcode != 0);
162  |     errcode = regcomp(&validip6prefix, VALIDIP6PREFIX, REG_EXTENDED|REG_NOSUB);
163  |     dieif(errcode != 0);
164  |     errcode = regcomp(&domainname, DOMAINNAME, REG_EXTENDED|REG_NOSUB);
165  |     dieif(errcode != 0);
166  |     errcode = regcomp(&domainalpha, DOMAINALPHA, REG_EXTENDED|REG_NOSUB);
167  |     dieif(errcode != 0);
168  | }
169  | 
170  | 
171  | /* see if the key looks like it could be a name */
172  | static unsigned int 
173  | wk_is_name (char *key) 
174  | {
175  |     /* if it's an address, it cannot be a name */
176  |     if (regexec(&ipaddress, key, 0, NULL, 0) == 0) { 
177  |         return 0;
178  |     }
179  |     if (regexec(&ipprefix, key, 0, NULL, 0) == 0) { 
180  |         return 0;
181  |     }
182  |     if (regexec(&validip6prefix, key, 0, NULL, 0) == 0) { 
183  |         return 0;
184  |     }
185  | 
186  |     /* Everything apart from addresses matches to name */
187  |     return 1;
188  | } /* wk_is_name() */
189  | 
190  | /* check for domain name */
191  | static unsigned int 
192  | wk_is_domain (char *key) 
193  | {
194  |     /* if it matches the general domain name search, and contains an */
195  |     /* alphabetic character, consider it a possible domain name */
196  |     if (regexec(&domainname, key, 0, NULL, 0) == 0) {
197  |         if (regexec(&domainalpha, key, 0, NULL, 0) == 0) {
198  | 	    return 1;
199  | 	}
200  |     }
201  |     return 0;
202  | } 
203  | 
204  | /* check for a host name (could be a domain, or an IP) */
205  | static unsigned int 
206  | wk_is_hostname (char *key) 
207  | {
208  |     /* Fix - should check for IPADDRESS, not IPRANGE.  - Shane */
209  |     return (wk_is_domain(key) || (regexec(&ipaddress, key, 0, NULL, 0) == 0));
210  | } /* wk_is_hostname() */
211  | 
212  | /* WK_to_string() */
213  | /*++++++++++++++++++++++++++++++++++++++
214  |   Convert the which keytypes bitmap into a string.
215  | 
216  |   mask_t wk The which keytypes mask to be converted.
217  | 
218  |   More:
219  |   +html+ <PRE>
220  |   Authors:
221  |         ottrey
222  |   +html+ </PRE><DL COMPACT>
223  |   +html+ <DT>Online References:
224  |   +html+ <DD><UL>
225  |   +html+ </UL></DL>
226  | 
227  |   ++++++++++++++++++++++++++++++++++++++*/
228  | char *
229  | WK_to_string (mask_t wk) 
230  | {
231  | 
232  |   return MA_to_string(wk, Keytypes);
233  | 
234  | } /* WK_to_string() */
235  | 
236  | /* WK_new() */
237  | /*++++++++++++++++++++++++++++++++++++++
238  |   Create a new which keytypes bitmap.
239  | 
240  |   This checks the string to see which keys it looks like.  This helps 
241  |   us decide what SQL tables (or radix trees) we need to query for a
242  |   match.
243  | 
244  |   char *key The key to be examined.
245  | 
246  |   More:
247  |   +html+ <PRE>
248  |   Authors:
249  |         ottrey
250  | 	shane
251  |   +html+ </PRE><DL COMPACT>
252  |   +html+ <DT>Online References:
253  |   +html+ <DD><UL>
254  |   +html+ </UL></DL>
255  | 
256  |   ++++++++++++++++++++++++++++++++++++++*/
257  | mask_t 
258  | WK_new (char *key) 
259  | {
260  |   static pthread_once_t once_control = PTHREAD_ONCE_INIT;
261  | 
262  |   mask_t wk; 
263  |   int i;
264  | 
265  |   /* initialize our regular expressions on the first call */
266  |   pthread_once(&once_control, wk_regex_init);
267  | 
268  |   /* empty bitmask */
269  |   wk = MA_new(MA_END);
270  | 
271  |   /* search regular expressions in the list */
272  |   for (i=0; i<WK_REGEX_LIST_LEN; i++) {
273  |       if (regexec(&wk_regex_list[i].regex, key, 0, NULL, 0) == 0) { 
274  |           MA_set(&wk, wk_regex_list[i].key_type, 1);
275  |       }
276  |   }
277  | 
278  |   /* check our more complicated key patterns */
279  |   MA_set(&wk, WK_NAME,         wk_is_name(key));
280  |   MA_set(&wk, WK_DOMAIN,       wk_is_domain(key));
281  |   MA_set(&wk, WK_HOSTNAME,     wk_is_hostname(key));
282  |   
283  |   /* return resulting bitmask */
284  |   return wk;
285  | 
286  | } /* WK_new() */