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