]>
Commit | Line | Data |
---|---|---|
4192ca66 BH |
1 | /* |
2 | PowerDNS Versatile Database Driven Nameserver | |
9c92ad4b | 3 | Copyright (C) 2005 - 2010 PowerDNS.COM BV |
4192ca66 BH |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License version 2 as | |
7 | published by the Free Software Foundation | |
8 | ||
f782fe38 MH |
9 | Additionally, the license of this program contains a special |
10 | exception which allows to distribute the program in binary form when | |
11 | it is linked against OpenSSL. | |
12 | ||
4192ca66 BH |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program; if not, write to the Free Software | |
06bd9ccf | 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
4192ca66 BH |
21 | */ |
22 | ||
a0a276c2 BH |
23 | #ifndef PDNS_DNSRECORDS_HH |
24 | #define PDNS_DNSRECORDS_HH | |
25 | ||
26 | #include "dnsparser.hh" | |
27 | #include "dnswriter.hh" | |
cbf0e7f3 | 28 | #include "rcpgenerator.hh" |
a0a276c2 | 29 | #include <boost/lexical_cast.hpp> |
8c1c9170 | 30 | #include <set> |
51083cab | 31 | #include <bitset> |
8c1c9170 | 32 | |
10f4eea8 | 33 | #include "namespaces.hh" |
61b26744 | 34 | #include "namespaces.hh" |
a0a276c2 | 35 | |
2770fad0 BH |
36 | #define includeboilerplate(RNAME) RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \ |
37 | RNAME##RecordContent(const string& zoneData); \ | |
38 | static void report(void); \ | |
ee1ada80 | 39 | static void unreport(void); \ |
2770fad0 BH |
40 | static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); \ |
41 | static DNSRecordContent* make(const string& zonedata); \ | |
42 | string getZoneRepresentation() const; \ | |
43 | void toPacket(DNSPacketWriter& pw); \ | |
44 | template<class Convertor> void xfrPacket(Convertor& conv); | |
a0a276c2 BH |
45 | |
46 | class NAPTRRecordContent : public DNSRecordContent | |
47 | { | |
48 | public: | |
49 | NAPTRRecordContent(uint16_t order, uint16_t preference, string flags, string services, string regexp, string replacement); | |
a0a276c2 | 50 | |
2770fad0 | 51 | includeboilerplate(NAPTR); |
cbf0e7f3 | 52 | template<class Convertor> void xfrRecordContent(Convertor& conv); |
a0a276c2 BH |
53 | private: |
54 | uint16_t d_order, d_preference; | |
55 | string d_flags, d_services, d_regexp, d_replacement; | |
56 | }; | |
57 | ||
2770fad0 | 58 | |
a0a276c2 BH |
59 | class ARecordContent : public DNSRecordContent |
60 | { | |
61 | public: | |
efb265e3 | 62 | explicit ARecordContent(uint32_t ip); |
2770fad0 BH |
63 | includeboilerplate(A); |
64 | void doRecordCheck(const DNSRecord& dr); | |
65 | uint32_t getIP() const; | |
a0a276c2 | 66 | |
2770fad0 BH |
67 | private: |
68 | uint32_t d_ip; | |
69 | }; | |
a0a276c2 | 70 | |
fc465b41 AT |
71 | class AAAARecordContent : public DNSRecordContent |
72 | { | |
73 | public: | |
74 | AAAARecordContent(std::string &val); | |
75 | includeboilerplate(AAAA); | |
76 | private: | |
77 | std::string d_ip6; | |
78 | }; | |
79 | ||
2770fad0 BH |
80 | class MXRecordContent : public DNSRecordContent |
81 | { | |
82 | public: | |
83 | MXRecordContent(uint16_t preference, const string& mxname); | |
a0a276c2 | 84 | |
2770fad0 | 85 | includeboilerplate(MX) |
a0a276c2 BH |
86 | |
87 | private: | |
2770fad0 BH |
88 | uint16_t d_preference; |
89 | string d_mxname; | |
90 | }; | |
91 | ||
9fd71f2e BH |
92 | class KXRecordContent : public DNSRecordContent |
93 | { | |
94 | public: | |
95 | KXRecordContent(uint16_t preference, const string& exchanger); | |
96 | ||
97 | includeboilerplate(KX) | |
98 | ||
99 | private: | |
100 | uint16_t d_preference; | |
101 | string d_exchanger; | |
102 | }; | |
103 | ||
104 | class IPSECKEYRecordContent : public DNSRecordContent | |
105 | { | |
106 | public: | |
107 | IPSECKEYRecordContent(uint16_t preference, uint8_t gatewaytype, uint8_t algo, const std::string& gateway, const std::string &publickey); | |
108 | ||
109 | includeboilerplate(IPSECKEY) | |
110 | ||
111 | private: | |
112 | uint8_t d_preference, d_gatewaytype, d_algorithm; | |
113 | string d_gateway, d_publickey; | |
1cafb958 AT |
114 | uint32_t d_ip4; |
115 | string d_ip6; | |
9fd71f2e BH |
116 | }; |
117 | ||
118 | class DHCIDRecordContent : public DNSRecordContent | |
119 | { | |
120 | public: | |
121 | includeboilerplate(DHCID) | |
122 | ||
123 | private: | |
124 | string d_content; | |
125 | }; | |
126 | ||
127 | ||
2770fad0 BH |
128 | class SRVRecordContent : public DNSRecordContent |
129 | { | |
130 | public: | |
131 | SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const string& target); | |
132 | ||
133 | includeboilerplate(SRV) | |
134 | ||
135 | private: | |
136 | uint16_t d_preference, d_weight, d_port; | |
137 | string d_target; | |
138 | }; | |
139 | ||
06ffdc52 BH |
140 | class TSIGRecordContent : public DNSRecordContent |
141 | { | |
142 | public: | |
143 | includeboilerplate(TSIG) | |
0407751c | 144 | TSIGRecordContent() : DNSRecordContent(QType::TSIG) {} |
06ffdc52 BH |
145 | |
146 | string d_algoName; | |
147 | uint64_t d_time; // 48 bits | |
148 | uint16_t d_fudge; | |
149 | // uint16_t d_macSize; | |
150 | string d_mac; | |
151 | uint16_t d_origID; | |
152 | uint16_t d_eRcode; | |
153 | // uint16_t d_otherLen | |
154 | string d_otherData; | |
155 | }; | |
156 | ||
2770fad0 BH |
157 | |
158 | class TXTRecordContent : public DNSRecordContent | |
159 | { | |
160 | public: | |
161 | includeboilerplate(TXT) | |
162 | ||
163 | private: | |
164 | string d_text; | |
a0a276c2 BH |
165 | }; |
166 | ||
8c1c9170 BH |
167 | class SPFRecordContent : public DNSRecordContent |
168 | { | |
169 | public: | |
170 | includeboilerplate(SPF) | |
171 | ||
172 | private: | |
173 | string d_text; | |
174 | }; | |
175 | ||
176 | ||
cbf0e7f3 BH |
177 | class NSRecordContent : public DNSRecordContent |
178 | { | |
179 | public: | |
180 | includeboilerplate(NS) | |
181 | ||
182 | private: | |
183 | string d_content; | |
184 | }; | |
185 | ||
186 | class PTRRecordContent : public DNSRecordContent | |
187 | { | |
188 | public: | |
189 | includeboilerplate(PTR) | |
190 | ||
191 | private: | |
192 | string d_content; | |
193 | }; | |
194 | ||
195 | class CNAMERecordContent : public DNSRecordContent | |
196 | { | |
197 | public: | |
198 | includeboilerplate(CNAME) | |
199 | ||
200 | private: | |
201 | string d_content; | |
202 | }; | |
203 | ||
4e0805a6 BH |
204 | class MRRecordContent : public DNSRecordContent |
205 | { | |
206 | public: | |
207 | includeboilerplate(MR) | |
208 | ||
209 | private: | |
210 | string d_alias; | |
211 | }; | |
212 | ||
7c0b8593 | 213 | class MINFORecordContent : public DNSRecordContent |
214 | { | |
215 | public: | |
216 | includeboilerplate(MINFO) | |
217 | ||
218 | private: | |
219 | string d_rmailbx; | |
220 | string d_emailbx; | |
221 | }; | |
cbf0e7f3 | 222 | |
878435ce BH |
223 | class OPTRecordContent : public DNSRecordContent |
224 | { | |
225 | public: | |
226 | includeboilerplate(OPT) | |
7f7b8d55 | 227 | void getData(vector<pair<uint16_t, string> > &opts); |
878435ce BH |
228 | private: |
229 | string d_data; | |
230 | }; | |
231 | ||
232 | ||
cbf0e7f3 BH |
233 | class HINFORecordContent : public DNSRecordContent |
234 | { | |
235 | public: | |
236 | includeboilerplate(HINFO) | |
237 | ||
238 | private: | |
239 | string d_cpu, d_host; | |
240 | }; | |
241 | ||
242 | class RPRecordContent : public DNSRecordContent | |
243 | { | |
244 | public: | |
245 | includeboilerplate(RP) | |
246 | ||
247 | private: | |
248 | string d_mbox, d_info; | |
249 | }; | |
250 | ||
251 | ||
8c1c9170 BH |
252 | class DNSKEYRecordContent : public DNSRecordContent |
253 | { | |
254 | public: | |
1c4d88c5 | 255 | DNSKEYRecordContent(); |
8c1c9170 | 256 | includeboilerplate(DNSKEY) |
1c4d88c5 | 257 | uint16_t getTag(); |
8c1c9170 | 258 | |
8c1c9170 BH |
259 | uint16_t d_flags; |
260 | uint8_t d_protocol; | |
261 | uint8_t d_algorithm; | |
262 | string d_key; | |
263 | }; | |
264 | ||
265 | class DSRecordContent : public DNSRecordContent | |
266 | { | |
267 | public: | |
1c4d88c5 | 268 | DSRecordContent(); |
8c1c9170 BH |
269 | includeboilerplate(DS) |
270 | ||
8c1c9170 BH |
271 | uint16_t d_tag; |
272 | uint8_t d_algorithm, d_digesttype; | |
273 | string d_digest; | |
274 | }; | |
275 | ||
0b55f2f5 BH |
276 | class DLVRecordContent : public DNSRecordContent |
277 | { | |
278 | public: | |
279 | DLVRecordContent(); | |
280 | includeboilerplate(DLV) | |
281 | ||
282 | uint16_t d_tag; | |
283 | uint8_t d_algorithm, d_digesttype; | |
284 | string d_digest; | |
285 | }; | |
286 | ||
287 | ||
a40a693b BH |
288 | class SSHFPRecordContent : public DNSRecordContent |
289 | { | |
290 | public: | |
291 | includeboilerplate(SSHFP) | |
292 | ||
293 | private: | |
294 | uint8_t d_algorithm, d_fptype; | |
295 | string d_fingerprint; | |
296 | }; | |
8c1c9170 | 297 | |
4b5762f1 BH |
298 | class KEYRecordContent : public DNSRecordContent |
299 | { | |
300 | public: | |
301 | includeboilerplate(KEY) | |
302 | ||
303 | private: | |
304 | uint16_t d_flags; | |
305 | uint8_t d_protocol, d_algorithm; | |
306 | string d_certificate; | |
307 | }; | |
308 | ||
37f47031 BH |
309 | class AFSDBRecordContent : public DNSRecordContent |
310 | { | |
311 | public: | |
312 | includeboilerplate(AFSDB) | |
313 | ||
314 | private: | |
315 | uint16_t d_subtype; | |
316 | string d_hostname; | |
317 | }; | |
318 | ||
319 | ||
2475a4fc BH |
320 | class CERTRecordContent : public DNSRecordContent |
321 | { | |
322 | public: | |
323 | includeboilerplate(CERT) | |
324 | ||
325 | private: | |
326 | uint16_t d_type, d_tag; | |
327 | uint8_t d_algorithm; | |
328 | string d_certificate; | |
329 | }; | |
330 | ||
07dbe87e BH |
331 | class TLSARecordContent : public DNSRecordContent |
332 | { | |
333 | public: | |
334 | includeboilerplate(TLSA) | |
335 | ||
336 | private: | |
f5a09796 | 337 | uint8_t d_certusage, d_selector, d_matchtype; |
07dbe87e BH |
338 | string d_cert; |
339 | }; | |
340 | ||
341 | ||
8c1c9170 BH |
342 | class RRSIGRecordContent : public DNSRecordContent |
343 | { | |
344 | public: | |
1c4d88c5 | 345 | RRSIGRecordContent(); |
8c1c9170 BH |
346 | includeboilerplate(RRSIG) |
347 | ||
8c1c9170 BH |
348 | uint16_t d_type; |
349 | uint8_t d_algorithm, d_labels; | |
350 | uint32_t d_originalttl, d_sigexpire, d_siginception; | |
351 | uint16_t d_tag; | |
352 | string d_signer, d_signature; | |
353 | }; | |
354 | ||
355 | ||
356 | ||
5ac6a3a3 | 357 | //namespace { |
2770fad0 BH |
358 | struct soatimes |
359 | { | |
360 | uint32_t serial; | |
361 | uint32_t refresh; | |
362 | uint32_t retry; | |
363 | uint32_t expire; | |
364 | uint32_t minimum; | |
365 | }; | |
5ac6a3a3 | 366 | //} |
2770fad0 | 367 | |
3150a49c | 368 | class RKEYRecordContent : public DNSRecordContent |
369 | { | |
370 | public: | |
371 | RKEYRecordContent(); | |
372 | includeboilerplate(RKEY) | |
373 | uint16_t d_flags; | |
374 | uint8_t d_protocol, d_algorithm; | |
375 | string d_key; | |
376 | }; | |
2770fad0 BH |
377 | |
378 | class SOARecordContent : public DNSRecordContent | |
379 | { | |
380 | public: | |
381 | includeboilerplate(SOA) | |
382 | SOARecordContent(const string& mname, const string& rname, const struct soatimes& st); | |
383 | ||
2770fad0 BH |
384 | string d_mname; |
385 | string d_rname; | |
386 | struct soatimes d_st; | |
387 | }; | |
a0a276c2 | 388 | |
20133c59 BH |
389 | class NSECRecordContent : public DNSRecordContent |
390 | { | |
391 | public: | |
392 | static void report(void); | |
ea634573 | 393 | NSECRecordContent() : DNSRecordContent(47) |
20133c59 | 394 | {} |
20133c59 BH |
395 | NSECRecordContent(const string& content, const string& zone=""); |
396 | ||
397 | static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); | |
250d1fd8 | 398 | static DNSRecordContent* make(const string& content); |
20133c59 BH |
399 | string getZoneRepresentation() const; |
400 | void toPacket(DNSPacketWriter& pw); | |
401 | string d_next; | |
402 | std::set<uint16_t> d_set; | |
403 | private: | |
20133c59 BH |
404 | }; |
405 | ||
1c4d88c5 BH |
406 | class NSEC3RecordContent : public DNSRecordContent |
407 | { | |
408 | public: | |
409 | static void report(void); | |
410 | NSEC3RecordContent() : DNSRecordContent(50) | |
411 | {} | |
412 | NSEC3RecordContent(const string& content, const string& zone=""); | |
413 | ||
414 | static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); | |
415 | static DNSRecordContent* make(const string& content); | |
416 | string getZoneRepresentation() const; | |
417 | void toPacket(DNSPacketWriter& pw); | |
418 | ||
419 | uint8_t d_algorithm, d_flags; | |
420 | uint16_t d_iterations; | |
421 | uint8_t d_saltlength; | |
422 | string d_salt; | |
423 | uint8_t d_nexthashlength; | |
424 | string d_nexthash; | |
425 | std::set<uint16_t> d_set; | |
426 | ||
427 | private: | |
428 | }; | |
429 | ||
430 | ||
431 | class NSEC3PARAMRecordContent : public DNSRecordContent | |
432 | { | |
433 | public: | |
827634f0 BH |
434 | static void report(void); |
435 | NSEC3PARAMRecordContent() : DNSRecordContent(51) | |
436 | {} | |
437 | NSEC3PARAMRecordContent(const string& content, const string& zone=""); | |
438 | ||
439 | static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); | |
440 | static DNSRecordContent* make(const string& content); | |
441 | string getZoneRepresentation() const; | |
442 | void toPacket(DNSPacketWriter& pw); | |
443 | ||
1c4d88c5 BH |
444 | |
445 | uint8_t d_algorithm, d_flags; | |
446 | uint16_t d_iterations; | |
447 | uint8_t d_saltlength; | |
448 | string d_salt; | |
449 | }; | |
450 | ||
451 | ||
c6a60874 BH |
452 | class LOCRecordContent : public DNSRecordContent |
453 | { | |
454 | public: | |
455 | static void report(void); | |
456 | LOCRecordContent() : DNSRecordContent(ns_t_loc) | |
457 | {} | |
458 | LOCRecordContent(const string& content, const string& zone=""); | |
20133c59 | 459 | |
c6a60874 BH |
460 | static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); |
461 | static DNSRecordContent* make(const string& content); | |
462 | string getZoneRepresentation() const; | |
463 | void toPacket(DNSPacketWriter& pw); | |
464 | ||
465 | uint8_t d_version, d_size, d_horizpre, d_vertpre; | |
466 | uint32_t d_latitude, d_longitude, d_altitude; | |
467 | ||
468 | private: | |
469 | }; | |
8c1c9170 | 470 | |
51083cab BH |
471 | |
472 | class WKSRecordContent : public DNSRecordContent | |
473 | { | |
474 | public: | |
475 | static void report(void); | |
476 | WKSRecordContent() : DNSRecordContent(ns_t_wks) | |
477 | {} | |
478 | WKSRecordContent(const string& content, const string& zone=""); | |
479 | ||
480 | static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); | |
481 | static DNSRecordContent* make(const string& content); | |
482 | string getZoneRepresentation() const; | |
483 | void toPacket(DNSPacketWriter& pw); | |
484 | ||
485 | uint32_t d_ip; | |
486 | std::bitset<65535> d_services; | |
487 | private: | |
488 | }; | |
489 | ||
490 | ||
afbb76cd BH |
491 | class URLRecordContent : public DNSRecordContent // Fake, 'fancy record' with type 256 |
492 | { | |
493 | public: | |
494 | includeboilerplate(URL) | |
495 | private: | |
496 | string d_url; | |
497 | }; | |
498 | ||
d34d3e01 BH |
499 | class MBOXFWRecordContent : public DNSRecordContent // Fake, 'fancy record' with type 256 |
500 | { | |
501 | public: | |
502 | includeboilerplate(MBOXFW) | |
503 | private: | |
504 | string d_mboxfw; | |
505 | }; | |
506 | ||
66a07c55 AT |
507 | class EUI48RecordContent : public DNSRecordContent |
508 | { | |
509 | public: | |
510 | EUI48RecordContent() : DNSRecordContent(ns_t_eui48) {}; | |
511 | static void report(void); | |
512 | static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); | |
513 | static DNSRecordContent* make(const string& zone); | |
514 | void toPacket(DNSPacketWriter& pw); | |
515 | string getZoneRepresentation() const; | |
516 | private: | |
517 | // storage for the bytes | |
518 | uint8_t d_eui48[6]; | |
519 | }; | |
520 | ||
521 | class EUI64RecordContent : public DNSRecordContent | |
522 | { | |
523 | public: | |
524 | EUI64RecordContent() : DNSRecordContent(ns_t_eui64) {}; | |
525 | static void report(void); | |
526 | static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); | |
527 | static DNSRecordContent* make(const string& zone); | |
528 | void toPacket(DNSPacketWriter& pw); | |
529 | string getZoneRepresentation() const; | |
530 | private: | |
531 | // storage for the bytes | |
532 | uint8_t d_eui64[8]; | |
533 | }; | |
d34d3e01 | 534 | |
8c1c9170 BH |
535 | #define boilerplate(RNAME, RTYPE) \ |
536 | RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const DNSRecord& dr, PacketReader& pr) \ | |
537 | { \ | |
538 | return new RNAME##RecordContent(dr, pr); \ | |
539 | } \ | |
540 | \ | |
ea634573 | 541 | RNAME##RecordContent::RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr) : DNSRecordContent(RTYPE) \ |
8c1c9170 BH |
542 | { \ |
543 | doRecordCheck(dr); \ | |
544 | xfrPacket(pr); \ | |
545 | } \ | |
546 | \ | |
547 | RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const string& zonedata) \ | |
548 | { \ | |
549 | return new RNAME##RecordContent(zonedata); \ | |
550 | } \ | |
551 | \ | |
552 | void RNAME##RecordContent::toPacket(DNSPacketWriter& pw) \ | |
553 | { \ | |
554 | this->xfrPacket(pw); \ | |
555 | } \ | |
556 | \ | |
557 | void RNAME##RecordContent::report(void) \ | |
558 | { \ | |
250d1fd8 | 559 | regist(1, RTYPE, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME); \ |
d6f3feee | 560 | regist(254, RTYPE, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME); \ |
ee1ada80 BH |
561 | } \ |
562 | void RNAME##RecordContent::unreport(void) \ | |
563 | { \ | |
564 | unregist(1, RTYPE); \ | |
d6f3feee | 565 | unregist(254, RTYPE); \ |
8c1c9170 BH |
566 | } \ |
567 | \ | |
ea634573 | 568 | RNAME##RecordContent::RNAME##RecordContent(const string& zoneData) : DNSRecordContent(RTYPE) \ |
8c1c9170 | 569 | { \ |
aab4adb0 BH |
570 | try { \ |
571 | RecordTextReader rtr(zoneData); \ | |
572 | xfrPacket(rtr); \ | |
573 | } \ | |
574 | catch(RecordTextException& rtr) { \ | |
7b1469bb | 575 | throw MOADNSException("Parsing record content: "+string(rtr.what())); \ |
4957a608 | 576 | } \ |
8c1c9170 BH |
577 | } \ |
578 | \ | |
579 | string RNAME##RecordContent::getZoneRepresentation() const \ | |
580 | { \ | |
581 | string ret; \ | |
582 | RecordTextWriter rtw(ret); \ | |
583 | const_cast<RNAME##RecordContent*>(this)->xfrPacket(rtw); \ | |
584 | return ret; \ | |
585 | } | |
586 | ||
587 | ||
588 | #define boilerplate_conv(RNAME, TYPE, CONV) \ | |
589 | boilerplate(RNAME, TYPE) \ | |
590 | template<class Convertor> \ | |
591 | void RNAME##RecordContent::xfrPacket(Convertor& conv) \ | |
592 | { \ | |
593 | CONV; \ | |
594 | } \ | |
595 | ||
7f7b8d55 BH |
596 | struct EDNSOpts |
597 | { | |
598 | uint16_t d_packetsize; | |
599 | uint8_t d_extRCode, d_version; | |
600 | uint16_t d_Z; | |
601 | vector<pair<uint16_t, string> > d_options; | |
12b33ac2 | 602 | enum zFlags { DNSSECOK=32768 }; |
7f7b8d55 BH |
603 | }; |
604 | //! Convenience function that fills out EDNS0 options, and returns true if there are any | |
605 | ||
606 | class MOADNSParser; | |
607 | bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo); | |
608 | ||
ea634573 BH |
609 | void reportBasicTypes(); |
610 | void reportOtherTypes(); | |
611 | void reportAllTypes(); | |
afbb76cd | 612 | void reportFancyTypes(); |
ea634573 | 613 | |
a0a276c2 | 614 | #endif |