Message.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177
  1. /*
  2. * Copyright (c) 2024, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/CountingStream.h>
  7. #include <AK/MemoryStream.h>
  8. #include <AK/Stream.h>
  9. #include <AK/UFixedBigInt.h>
  10. #include <LibCore/DateTime.h>
  11. #include <LibDNS/Message.h>
  12. namespace DNS::Messages {
  13. String Options::to_string() const
  14. {
  15. StringBuilder builder;
  16. builder.appendff("QR: {}, Opcode: {}, AA: {}, TC: {}, RD: {}, RA: {}, AD: {}, CD: {}, RCODE: {}",
  17. is_question() ? "Q" : "R",
  18. Messages::to_string(op_code()),
  19. is_authoritative_answer(),
  20. is_truncated(),
  21. recursion_desired(),
  22. recursion_available(),
  23. authenticated_data(),
  24. checking_disabled(),
  25. Messages::to_string(response_code()));
  26. return MUST(builder.to_string());
  27. }
  28. StringView to_string(Options::ResponseCode code)
  29. {
  30. switch (code) {
  31. case Options::ResponseCode::NoError:
  32. return "NoError"sv;
  33. case Options::ResponseCode::FormatError:
  34. return "FormatError"sv;
  35. case Options::ResponseCode::ServerFailure:
  36. return "ServerFailure"sv;
  37. case Options::ResponseCode::NameError:
  38. return "NameError"sv;
  39. case Options::ResponseCode::NotImplemented:
  40. return "NotImplemented"sv;
  41. case Options::ResponseCode::Refused:
  42. return "Refused"sv;
  43. default:
  44. return "UNKNOWN"sv;
  45. }
  46. }
  47. ErrorOr<Message> Message::from_raw(AK::Stream& stream)
  48. {
  49. CountingStream counting_stream { MaybeOwned(stream) };
  50. auto context = ParseContext { counting_stream, make<RedBlackTree<u16, DomainName>>() };
  51. return from_raw(context);
  52. }
  53. ErrorOr<Message> Message::from_raw(ParseContext& ctx)
  54. {
  55. // RFC 1035, 4.1. (Messages) Format.
  56. // | Header |
  57. // | Question | the question for the name server
  58. // | Answer | RRs answering the question
  59. // | Authority | RRs pointing toward an authority
  60. // | Additional | RRs holding additional information
  61. //
  62. // The header section is always present. The header includes fields that
  63. // specify which of the remaining sections are present, and also specify
  64. // whether the message is a query or a response, a standard query or some
  65. // other opcode, etc.
  66. Header header;
  67. Bytes header_bytes { &header, sizeof(Header) };
  68. TRY(ctx.stream.read_until_filled(header_bytes));
  69. Message message {};
  70. message.header = header;
  71. for (size_t i = 0; i < header.question_count; ++i) {
  72. auto question = TRY(Question::from_raw(ctx));
  73. message.questions.append(move(question));
  74. }
  75. for (size_t i = 0; i < header.answer_count; ++i) {
  76. auto answer = TRY(ResourceRecord::from_raw(ctx));
  77. message.answers.append(move(answer));
  78. }
  79. for (size_t i = 0; i < header.authority_count; ++i) {
  80. auto authority = TRY(ResourceRecord::from_raw(ctx));
  81. message.authorities.append(move(authority));
  82. }
  83. for (size_t i = 0; i < header.additional_count; ++i) {
  84. auto additional = TRY(ResourceRecord::from_raw(ctx));
  85. message.additional_records.append(move(additional));
  86. }
  87. return message;
  88. }
  89. ErrorOr<size_t> Message::to_raw(ByteBuffer& out) const
  90. {
  91. // NOTE: This is minimally implemented to allow for sending queries,
  92. // server-side responses are not implemented yet.
  93. VERIFY(header.answer_count == 0);
  94. VERIFY(header.authority_count == 0);
  95. auto start_size = out.size();
  96. auto header_bytes = TRY(out.get_bytes_for_writing(sizeof(Header)));
  97. memcpy(header_bytes.data(), &header, sizeof(Header));
  98. for (size_t i = 0; i < header.question_count; i++)
  99. TRY(questions[i].to_raw(out));
  100. for (size_t i = 0; i < header.additional_count; i++)
  101. TRY(additional_records[i].to_raw(out));
  102. return out.size() - start_size;
  103. }
  104. ErrorOr<String> Message::format_for_log() const
  105. {
  106. StringBuilder builder;
  107. builder.appendff("ID: {}\n", header.id);
  108. builder.appendff("Flags: {} ({:x})\n", header.options.to_string(), header.options.raw);
  109. builder.appendff("qdcount: {}, ancount: {}, nscount: {}, arcount: {}\n", header.question_count, header.answer_count, header.authority_count, header.additional_count);
  110. if (header.question_count > 0) {
  111. builder.appendff("Questions:\n");
  112. for (auto& q : questions)
  113. builder.appendff(" {} {} {}\n", q.name.to_string(), to_string(q.class_), to_string(q.type));
  114. }
  115. if (header.answer_count > 0) {
  116. builder.appendff("Answers:\n");
  117. for (auto& a : answers) {
  118. builder.appendff(" {} {} {}\n", a.name.to_string(), to_string(a.class_), to_string(a.type));
  119. a.record.visit(
  120. [&](auto const& record) { builder.appendff(" {}\n", MUST(record.to_string())); },
  121. [&](ByteBuffer const& raw) {
  122. builder.appendff(" {:hex-dump}\n", raw.bytes());
  123. });
  124. }
  125. }
  126. if (header.authority_count > 0) {
  127. builder.appendff("Authorities:\n");
  128. for (auto& a : authorities) {
  129. builder.appendff(" {} {} {}\n", a.name.to_string(), to_string(a.class_), to_string(a.type));
  130. a.record.visit(
  131. [&](auto const& record) { builder.appendff(" {}\n", MUST(record.to_string())); },
  132. [&](ByteBuffer const& raw) {
  133. builder.appendff(" {:hex-dump}\n", raw.bytes());
  134. });
  135. }
  136. }
  137. if (header.additional_count > 0) {
  138. builder.appendff("Additional:\n");
  139. for (auto& a : additional_records) {
  140. builder.appendff(" {} {} {}\n", a.name.to_string(), to_string(a.type), to_string(a.class_));
  141. a.record.visit(
  142. [&](auto const& record) { builder.appendff(" {}\n", MUST(record.to_string())); },
  143. [&](ByteBuffer const& raw) {
  144. builder.appendff(" {:hex-dump}\n", raw.bytes());
  145. });
  146. }
  147. }
  148. return builder.to_string();
  149. }
  150. ErrorOr<Question> Question::from_raw(ParseContext& ctx)
  151. {
  152. // RFC 1035, 4.1.2. Question section format.
  153. // + +
  154. // | QNAME | a domain name represented as a sequence of labels
  155. // + +
  156. // | QTYPE | a two octet code which specifies the type of the query
  157. // | QCLASS | a two octet code that specifies the class of the query
  158. auto name = TRY(DomainName::from_raw(ctx));
  159. auto type = static_cast<ResourceType>(static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>())));
  160. auto class_ = static_cast<Class>(static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>())));
  161. return Question { move(name), type, class_ };
  162. }
  163. ErrorOr<void> Question::to_raw(ByteBuffer& out) const
  164. {
  165. TRY(name.to_raw(out));
  166. auto type_bytes = TRY(out.get_bytes_for_writing(2));
  167. auto net_type = static_cast<NetworkOrdered<u16>>(to_underlying(type));
  168. memcpy(type_bytes.data(), &net_type, 2);
  169. auto class_bytes = TRY(out.get_bytes_for_writing(2));
  170. auto net_class = static_cast<NetworkOrdered<u16>>(to_underlying(class_));
  171. memcpy(class_bytes.data(), &net_class, 2);
  172. return {};
  173. }
  174. StringView to_string(ResourceType type)
  175. {
  176. switch (type) {
  177. case ResourceType::Reserved:
  178. return "Reserved"sv;
  179. case ResourceType::A:
  180. return "A"sv;
  181. case ResourceType::NS:
  182. return "NS"sv;
  183. case ResourceType::MD:
  184. return "MD"sv;
  185. case ResourceType::MF:
  186. return "MF"sv;
  187. case ResourceType::CNAME:
  188. return "CNAME"sv;
  189. case ResourceType::SOA:
  190. return "SOA"sv;
  191. case ResourceType::MB:
  192. return "MB"sv;
  193. case ResourceType::MG:
  194. return "MG"sv;
  195. case ResourceType::MR:
  196. return "MR"sv;
  197. case ResourceType::NULL_:
  198. return "NULL_"sv;
  199. case ResourceType::WKS:
  200. return "WKS"sv;
  201. case ResourceType::PTR:
  202. return "PTR"sv;
  203. case ResourceType::HINFO:
  204. return "HINFO"sv;
  205. case ResourceType::MINFO:
  206. return "MINFO"sv;
  207. case ResourceType::MX:
  208. return "MX"sv;
  209. case ResourceType::TXT:
  210. return "TXT"sv;
  211. case ResourceType::RP:
  212. return "RP"sv;
  213. case ResourceType::AFSDB:
  214. return "AFSDB"sv;
  215. case ResourceType::X25:
  216. return "X25"sv;
  217. case ResourceType::ISDN:
  218. return "ISDN"sv;
  219. case ResourceType::RT:
  220. return "RT"sv;
  221. case ResourceType::NSAP:
  222. return "NSAP"sv;
  223. case ResourceType::NSAP_PTR:
  224. return "NSAP_PTR"sv;
  225. case ResourceType::SIG:
  226. return "SIG"sv;
  227. case ResourceType::KEY:
  228. return "KEY"sv;
  229. case ResourceType::PX:
  230. return "PX"sv;
  231. case ResourceType::GPOS:
  232. return "GPOS"sv;
  233. case ResourceType::AAAA:
  234. return "AAAA"sv;
  235. case ResourceType::LOC:
  236. return "LOC"sv;
  237. case ResourceType::NXT:
  238. return "NXT"sv;
  239. case ResourceType::EID:
  240. return "EID"sv;
  241. case ResourceType::NIMLOC:
  242. return "NIMLOC"sv;
  243. case ResourceType::SRV:
  244. return "SRV"sv;
  245. case ResourceType::ATMA:
  246. return "ATMA"sv;
  247. case ResourceType::NAPTR:
  248. return "NAPTR"sv;
  249. case ResourceType::KX:
  250. return "KX"sv;
  251. case ResourceType::CERT:
  252. return "CERT"sv;
  253. case ResourceType::A6:
  254. return "A6"sv;
  255. case ResourceType::DNAME:
  256. return "DNAME"sv;
  257. case ResourceType::SINK:
  258. return "SINK"sv;
  259. case ResourceType::OPT:
  260. return "OPT"sv;
  261. case ResourceType::APL:
  262. return "APL"sv;
  263. case ResourceType::DS:
  264. return "DS"sv;
  265. case ResourceType::SSHFP:
  266. return "SSHFP"sv;
  267. case ResourceType::IPSECKEY:
  268. return "IPSECKEY"sv;
  269. case ResourceType::RRSIG:
  270. return "RRSIG"sv;
  271. case ResourceType::NSEC:
  272. return "NSEC"sv;
  273. case ResourceType::DNSKEY:
  274. return "DNSKEY"sv;
  275. case ResourceType::DHCID:
  276. return "DHCID"sv;
  277. case ResourceType::NSEC3:
  278. return "NSEC3"sv;
  279. case ResourceType::NSEC3PARAM:
  280. return "NSEC3PARAM"sv;
  281. case ResourceType::TLSA:
  282. return "TLSA"sv;
  283. case ResourceType::SMIMEA:
  284. return "SMIMEA"sv;
  285. case ResourceType::HIP:
  286. return "HIP"sv;
  287. case ResourceType::NINFO:
  288. return "NINFO"sv;
  289. case ResourceType::RKEY:
  290. return "RKEY"sv;
  291. case ResourceType::TALINK:
  292. return "TALINK"sv;
  293. case ResourceType::CDS:
  294. return "CDS"sv;
  295. case ResourceType::CDNSKEY:
  296. return "CDNSKEY"sv;
  297. case ResourceType::OPENPGPKEY:
  298. return "OPENPGPKEY"sv;
  299. case ResourceType::CSYNC:
  300. return "CSYNC"sv;
  301. case ResourceType::ZONEMD:
  302. return "ZONEMD"sv;
  303. case ResourceType::SVCB:
  304. return "SVCB"sv;
  305. case ResourceType::HTTPS:
  306. return "HTTPS"sv;
  307. case ResourceType::SPF:
  308. return "SPF"sv;
  309. case ResourceType::UINFO:
  310. return "UINFO"sv;
  311. case ResourceType::UID:
  312. return "UID"sv;
  313. case ResourceType::GID:
  314. return "GID"sv;
  315. case ResourceType::UNSPEC:
  316. return "UNSPEC"sv;
  317. case ResourceType::NID:
  318. return "NID"sv;
  319. case ResourceType::L32:
  320. return "L32"sv;
  321. case ResourceType::L64:
  322. return "L64"sv;
  323. case ResourceType::LP:
  324. return "LP"sv;
  325. case ResourceType::EUI48:
  326. return "EUI48"sv;
  327. case ResourceType::EUI64:
  328. return "EUI64"sv;
  329. case ResourceType::NXNAME:
  330. return "NXNAME"sv;
  331. case ResourceType::TKEY:
  332. return "TKEY"sv;
  333. case ResourceType::TSIG:
  334. return "TSIG"sv;
  335. case ResourceType::IXFR:
  336. return "IXFR"sv;
  337. case ResourceType::AXFR:
  338. return "AXFR"sv;
  339. case ResourceType::MAILB:
  340. return "MAILB"sv;
  341. case ResourceType::MAILA:
  342. return "MAILA"sv;
  343. case ResourceType::ANY:
  344. return "ANY"sv;
  345. case ResourceType::URI:
  346. return "URI"sv;
  347. case ResourceType::CAA:
  348. return "CAA"sv;
  349. case ResourceType::AVC:
  350. return "AVC"sv;
  351. case ResourceType::DOA:
  352. return "DOA"sv;
  353. case ResourceType::AMTRELAY:
  354. return "AMTRELAY"sv;
  355. case ResourceType::RESINFO:
  356. return "RESINFO"sv;
  357. case ResourceType::WALLET:
  358. return "WALLET"sv;
  359. case ResourceType::CLA:
  360. return "CLA"sv;
  361. case ResourceType::IPN:
  362. return "IPN"sv;
  363. case ResourceType::TA:
  364. return "TA"sv;
  365. case ResourceType::DLV:
  366. return "DLV"sv;
  367. default:
  368. return "UNKNOWN"sv;
  369. }
  370. }
  371. Optional<ResourceType> resource_type_from_string(StringView name)
  372. {
  373. if (name == "Reserved"sv)
  374. return ResourceType::Reserved;
  375. if (name == "A"sv)
  376. return ResourceType::A;
  377. if (name == "NS"sv)
  378. return ResourceType::NS;
  379. if (name == "MD"sv)
  380. return ResourceType::MD;
  381. if (name == "MF"sv)
  382. return ResourceType::MF;
  383. if (name == "CNAME"sv)
  384. return ResourceType::CNAME;
  385. if (name == "SOA"sv)
  386. return ResourceType::SOA;
  387. if (name == "MB"sv)
  388. return ResourceType::MB;
  389. if (name == "MG"sv)
  390. return ResourceType::MG;
  391. if (name == "MR"sv)
  392. return ResourceType::MR;
  393. if (name == "NULL_"sv)
  394. return ResourceType::NULL_;
  395. if (name == "WKS"sv)
  396. return ResourceType::WKS;
  397. if (name == "PTR"sv)
  398. return ResourceType::PTR;
  399. if (name == "HINFO"sv)
  400. return ResourceType::HINFO;
  401. if (name == "MINFO"sv)
  402. return ResourceType::MINFO;
  403. if (name == "MX"sv)
  404. return ResourceType::MX;
  405. if (name == "TXT"sv)
  406. return ResourceType::TXT;
  407. if (name == "RP"sv)
  408. return ResourceType::RP;
  409. if (name == "AFSDB"sv)
  410. return ResourceType::AFSDB;
  411. if (name == "X25"sv)
  412. return ResourceType::X25;
  413. if (name == "ISDN"sv)
  414. return ResourceType::ISDN;
  415. if (name == "RT"sv)
  416. return ResourceType::RT;
  417. if (name == "NSAP"sv)
  418. return ResourceType::NSAP;
  419. if (name == "NSAP_PTR"sv)
  420. return ResourceType::NSAP_PTR;
  421. if (name == "SIG"sv)
  422. return ResourceType::SIG;
  423. if (name == "KEY"sv)
  424. return ResourceType::KEY;
  425. if (name == "PX"sv)
  426. return ResourceType::PX;
  427. if (name == "GPOS"sv)
  428. return ResourceType::GPOS;
  429. if (name == "AAAA"sv)
  430. return ResourceType::AAAA;
  431. if (name == "LOC"sv)
  432. return ResourceType::LOC;
  433. if (name == "NXT"sv)
  434. return ResourceType::NXT;
  435. if (name == "EID"sv)
  436. return ResourceType::EID;
  437. if (name == "NIMLOC"sv)
  438. return ResourceType::NIMLOC;
  439. if (name == "SRV"sv)
  440. return ResourceType::SRV;
  441. if (name == "ATMA"sv)
  442. return ResourceType::ATMA;
  443. if (name == "NAPTR"sv)
  444. return ResourceType::NAPTR;
  445. if (name == "KX"sv)
  446. return ResourceType::KX;
  447. if (name == "CERT"sv)
  448. return ResourceType::CERT;
  449. if (name == "A6"sv)
  450. return ResourceType::A6;
  451. if (name == "DNAME"sv)
  452. return ResourceType::DNAME;
  453. if (name == "SINK"sv)
  454. return ResourceType::SINK;
  455. if (name == "OPT"sv)
  456. return ResourceType::OPT;
  457. if (name == "APL"sv)
  458. return ResourceType::APL;
  459. if (name == "DS"sv)
  460. return ResourceType::DS;
  461. if (name == "SSHFP"sv)
  462. return ResourceType::SSHFP;
  463. if (name == "IPSECKEY"sv)
  464. return ResourceType::IPSECKEY;
  465. if (name == "RRSIG"sv)
  466. return ResourceType::RRSIG;
  467. if (name == "NSEC"sv)
  468. return ResourceType::NSEC;
  469. if (name == "DNSKEY"sv)
  470. return ResourceType::DNSKEY;
  471. if (name == "DHCID"sv)
  472. return ResourceType::DHCID;
  473. if (name == "NSEC3"sv)
  474. return ResourceType::NSEC3;
  475. if (name == "NSEC3PARAM"sv)
  476. return ResourceType::NSEC3PARAM;
  477. if (name == "TLSA"sv)
  478. return ResourceType::TLSA;
  479. if (name == "SMIMEA"sv)
  480. return ResourceType::SMIMEA;
  481. if (name == "HIP"sv)
  482. return ResourceType::HIP;
  483. if (name == "NINFO"sv)
  484. return ResourceType::NINFO;
  485. if (name == "RKEY"sv)
  486. return ResourceType::RKEY;
  487. if (name == "TALINK"sv)
  488. return ResourceType::TALINK;
  489. if (name == "CDS"sv)
  490. return ResourceType::CDS;
  491. if (name == "CDNSKEY"sv)
  492. return ResourceType::CDNSKEY;
  493. if (name == "OPENPGPKEY"sv)
  494. return ResourceType::OPENPGPKEY;
  495. if (name == "CSYNC"sv)
  496. return ResourceType::CSYNC;
  497. if (name == "ZONEMD"sv)
  498. return ResourceType::ZONEMD;
  499. if (name == "SVCB"sv)
  500. return ResourceType::SVCB;
  501. if (name == "HTTPS"sv)
  502. return ResourceType::HTTPS;
  503. if (name == "SPF"sv)
  504. return ResourceType::SPF;
  505. if (name == "UINFO"sv)
  506. return ResourceType::UINFO;
  507. if (name == "UID"sv)
  508. return ResourceType::UID;
  509. if (name == "GID"sv)
  510. return ResourceType::GID;
  511. if (name == "UNSPEC"sv)
  512. return ResourceType::UNSPEC;
  513. if (name == "NID"sv)
  514. return ResourceType::NID;
  515. if (name == "L32"sv)
  516. return ResourceType::L32;
  517. if (name == "L64"sv)
  518. return ResourceType::L64;
  519. if (name == "LP"sv)
  520. return ResourceType::LP;
  521. if (name == "EUI48"sv)
  522. return ResourceType::EUI48;
  523. if (name == "EUI64"sv)
  524. return ResourceType::EUI64;
  525. if (name == "NXNAME"sv)
  526. return ResourceType::NXNAME;
  527. if (name == "TKEY"sv)
  528. return ResourceType::TKEY;
  529. if (name == "TSIG"sv)
  530. return ResourceType::TSIG;
  531. if (name == "IXFR"sv)
  532. return ResourceType::IXFR;
  533. if (name == "AXFR"sv)
  534. return ResourceType::AXFR;
  535. if (name == "MAILB"sv)
  536. return ResourceType::MAILB;
  537. if (name == "MAILA"sv)
  538. return ResourceType::MAILA;
  539. if (name == "ANY"sv)
  540. return ResourceType::ANY;
  541. if (name == "URI"sv)
  542. return ResourceType::URI;
  543. if (name == "CAA"sv)
  544. return ResourceType::CAA;
  545. if (name == "AVC"sv)
  546. return ResourceType::AVC;
  547. if (name == "DOA"sv)
  548. return ResourceType::DOA;
  549. if (name == "AMTRELAY"sv)
  550. return ResourceType::AMTRELAY;
  551. if (name == "RESINFO"sv)
  552. return ResourceType::RESINFO;
  553. if (name == "WALLET"sv)
  554. return ResourceType::WALLET;
  555. if (name == "CLA"sv)
  556. return ResourceType::CLA;
  557. if (name == "IPN"sv)
  558. return ResourceType::IPN;
  559. if (name == "TA"sv)
  560. return ResourceType::TA;
  561. if (name == "DLV"sv)
  562. return ResourceType::DLV;
  563. return {};
  564. }
  565. StringView to_string(Class class_)
  566. {
  567. switch (class_) {
  568. case Class::IN:
  569. return "IN"sv;
  570. case Class::CH:
  571. return "CH"sv;
  572. case Class::HS:
  573. return "HS"sv;
  574. default:
  575. return "UNKNOWN"sv;
  576. }
  577. }
  578. StringView to_string(OpCode code)
  579. {
  580. if ((to_underlying(code) & to_underlying(OpCode::Reserved)) != 0)
  581. return "Reserved"sv;
  582. switch (code) {
  583. case OpCode::Query:
  584. return "Query"sv;
  585. case OpCode::IQuery:
  586. return "IQuery"sv;
  587. case OpCode::Status:
  588. return "Status"sv;
  589. case OpCode::Notify:
  590. return "Notify"sv;
  591. case OpCode::Update:
  592. return "Update"sv;
  593. case OpCode::DSO:
  594. return "DSO"sv;
  595. default:
  596. return "UNKNOWN"sv;
  597. }
  598. }
  599. DomainName DomainName::from_string(StringView name)
  600. {
  601. DomainName domain_name;
  602. name.for_each_split_view('.', SplitBehavior::Nothing, [&](StringView piece) {
  603. domain_name.labels.append(piece);
  604. });
  605. return domain_name;
  606. }
  607. ErrorOr<DomainName> DomainName::from_raw(ParseContext& ctx)
  608. {
  609. // RFC 1035, 4.1.2. Question section format.
  610. // QNAME a domain name represented as a sequence of labels, where
  611. // each label consists of a length octet followed by that
  612. // number of octets. The domain name terminates with the
  613. // zero length octet for the null label of the root. Note
  614. // that this field may be an odd number of octets; no
  615. // padding is used.
  616. DomainName name;
  617. auto input_offset_marker = ctx.stream.read_bytes();
  618. while (true) {
  619. auto length = TRY(ctx.stream.read_value<u8>());
  620. if (length == 0)
  621. break;
  622. constexpr static u8 OffsetMarkerMask = 0b11000000;
  623. if ((length & OffsetMarkerMask) == OffsetMarkerMask) {
  624. // This is a pointer to a prior domain name.
  625. u16 const offset = static_cast<u16>(length & ~OffsetMarkerMask) << 8 | TRY(ctx.stream.read_value<u8>());
  626. if (auto it = ctx.pointers->find_largest_not_above_iterator(offset); !it.is_end()) {
  627. auto labels = it->labels;
  628. for (auto& entry : labels)
  629. name.labels.append(entry);
  630. break;
  631. }
  632. dbgln("Invalid domain name pointer in label, no prior domain name found around offset {}", offset);
  633. return Error::from_string_literal("Invalid domain name pointer in label");
  634. }
  635. ByteBuffer content;
  636. TRY(ctx.stream.read_until_filled(TRY(content.get_bytes_for_writing(length))));
  637. name.labels.append(ByteString::copy(content));
  638. }
  639. ctx.pointers->insert(input_offset_marker, name);
  640. return name;
  641. }
  642. ErrorOr<void> DomainName::to_raw(ByteBuffer& out) const
  643. {
  644. for (auto& label : labels) {
  645. VERIFY(label.length() <= 63);
  646. auto size_bytes = TRY(out.get_bytes_for_writing(1));
  647. u8 size = static_cast<u8>(label.length());
  648. memcpy(size_bytes.data(), &size, 1);
  649. auto content_bytes = TRY(out.get_bytes_for_writing(label.length()));
  650. memcpy(content_bytes.data(), label.characters(), label.length());
  651. }
  652. TRY(out.try_append(0));
  653. return {};
  654. }
  655. String DomainName::to_string() const
  656. {
  657. StringBuilder builder;
  658. for (size_t i = 0; i < labels.size(); ++i) {
  659. builder.append(labels[i]);
  660. builder.append('.');
  661. }
  662. return MUST(builder.to_string());
  663. }
  664. class RecordingStream final : public Stream {
  665. public:
  666. explicit RecordingStream(Stream& stream)
  667. : m_stream(stream)
  668. {
  669. }
  670. ByteBuffer take_recorded_data() && { return move(m_recorded_data); }
  671. virtual ErrorOr<Bytes> read_some(Bytes bytes) override
  672. {
  673. auto result = TRY(m_stream->read_some(bytes));
  674. m_recorded_data.append(result.data(), result.size());
  675. return result;
  676. }
  677. virtual ErrorOr<void> discard(size_t discarded_bytes) override
  678. {
  679. auto space = TRY(m_recorded_data.get_bytes_for_writing(discarded_bytes));
  680. TRY(m_stream->read_until_filled(space));
  681. return {};
  682. }
  683. virtual ErrorOr<size_t> write_some(ReadonlyBytes bytes) override { return m_stream->write_some(bytes); }
  684. virtual bool is_eof() const override { return m_stream->is_eof(); }
  685. virtual bool is_open() const override { return m_stream->is_open(); }
  686. virtual void close() override { m_stream->close(); }
  687. private:
  688. MaybeOwned<Stream> m_stream;
  689. ByteBuffer m_recorded_data;
  690. };
  691. ErrorOr<ResourceRecord> ResourceRecord::from_raw(ParseContext& ctx)
  692. {
  693. // RFC 1035, 4.1.3. Resource record format.
  694. // + +
  695. // | NAME | a domain name to which this resource record pertains
  696. // + +
  697. // | TYPE | two octets containing one of the RR type codes
  698. // | CLASS | two octets containing one of the RR class codes
  699. // | TTL | a 32-bit unsigned integer that specifies the time interval
  700. // | | that the resource record may be cached
  701. // | RDLENGTH | an unsigned 16-bit integer that specifies the length in
  702. // | | octets of the RDATA field
  703. // | RDATA | a variable length string of octets that describes the resource
  704. ByteBuffer rdata;
  705. ByteBuffer rr_raw_data;
  706. DomainName name;
  707. ResourceType type;
  708. Class class_;
  709. u32 ttl;
  710. {
  711. RecordingStream rr_stream { ctx.stream };
  712. CountingStream rr_counting_stream { MaybeOwned<Stream>(rr_stream) };
  713. ParseContext rr_ctx { rr_counting_stream, move(ctx.pointers) };
  714. ScopeGuard guard([&] { ctx.pointers = move(rr_ctx.pointers); });
  715. name = TRY(DomainName::from_raw(rr_ctx));
  716. type = static_cast<ResourceType>(static_cast<u16>(TRY(rr_ctx.stream.read_value<NetworkOrdered<u16>>())));
  717. if (type == ResourceType::OPT) {
  718. auto record = ResourceRecord {
  719. move(name),
  720. type,
  721. Class::IN,
  722. 0,
  723. TRY(Records::OPT::from_raw(rr_ctx)),
  724. {},
  725. };
  726. record.raw = move(rr_stream).take_recorded_data();
  727. return record;
  728. }
  729. class_ = static_cast<Class>(static_cast<u16>(TRY(rr_ctx.stream.read_value<NetworkOrdered<u16>>())));
  730. ttl = static_cast<u32>(TRY(rr_ctx.stream.read_value<NetworkOrdered<u32>>()));
  731. auto rd_length = static_cast<u16>(TRY(rr_ctx.stream.read_value<NetworkOrdered<u16>>()));
  732. TRY(rr_ctx.stream.read_until_filled(TRY(rdata.get_bytes_for_writing(rd_length))));
  733. rr_raw_data = move(rr_stream).take_recorded_data();
  734. }
  735. FixedMemoryStream stream { rdata.bytes() };
  736. CountingStream rdata_stream { MaybeOwned<Stream>(stream) };
  737. ParseContext rdata_ctx { rdata_stream, move(ctx.pointers) };
  738. ScopeGuard guard([&] { ctx.pointers = move(rdata_ctx.pointers); });
  739. #define PARSE_AS_RR(TYPE) \
  740. do { \
  741. auto rr = TRY(Records::TYPE::from_raw(rdata_ctx)); \
  742. if (!rdata_stream.is_eof()) { \
  743. dbgln("Extra data ({}) left in stream: {:hex-dump}", rdata.size() - rdata_stream.read_bytes(), rdata.bytes().slice(rdata_stream.read_bytes())); \
  744. return Error::from_string_literal("Extra data in " #TYPE " record content"); \
  745. } \
  746. return ResourceRecord { move(name), type, class_, ttl, rr, move(rr_raw_data) }; \
  747. } while (0)
  748. switch (type) {
  749. case ResourceType::A:
  750. PARSE_AS_RR(A);
  751. case ResourceType::AAAA:
  752. PARSE_AS_RR(AAAA);
  753. case ResourceType::TXT:
  754. PARSE_AS_RR(TXT);
  755. case ResourceType::CNAME:
  756. PARSE_AS_RR(CNAME);
  757. case ResourceType::NS:
  758. PARSE_AS_RR(NS);
  759. case ResourceType::SOA:
  760. PARSE_AS_RR(SOA);
  761. case ResourceType::MX:
  762. PARSE_AS_RR(MX);
  763. case ResourceType::PTR:
  764. PARSE_AS_RR(PTR);
  765. case ResourceType::SRV:
  766. PARSE_AS_RR(SRV);
  767. case ResourceType::DNSKEY:
  768. PARSE_AS_RR(DNSKEY);
  769. case ResourceType::CDNSKEY:
  770. PARSE_AS_RR(CDNSKEY);
  771. case ResourceType::DS:
  772. PARSE_AS_RR(DS);
  773. case ResourceType::CDS:
  774. PARSE_AS_RR(CDS);
  775. case ResourceType::RRSIG:
  776. PARSE_AS_RR(RRSIG);
  777. // case ResourceType::NSEC:
  778. // PARSE_AS_RR(NSEC);
  779. // case ResourceType::NSEC3:
  780. // PARSE_AS_RR(NSEC3);
  781. // case ResourceType::NSEC3PARAM:
  782. // PARSE_AS_RR(NSEC3PARAM);
  783. // case ResourceType::TLSA:
  784. // PARSE_AS_RR(TLSA);
  785. case ResourceType::HINFO:
  786. PARSE_AS_RR(HINFO);
  787. default:
  788. return ResourceRecord { move(name), type, class_, ttl, move(rdata), move(rr_raw_data) };
  789. }
  790. #undef PARSE_AS_RR
  791. }
  792. ErrorOr<void> ResourceRecord::to_raw(ByteBuffer& buffer) const
  793. {
  794. TRY(name.to_raw(buffer));
  795. auto type_bytes = TRY(buffer.get_bytes_for_writing(2));
  796. auto net_type = static_cast<NetworkOrdered<u16>>(to_underlying(type));
  797. memcpy(type_bytes.data(), &net_type, 2);
  798. if (type != ResourceType::OPT) {
  799. auto class_bytes = TRY(buffer.get_bytes_for_writing(2));
  800. auto net_class = static_cast<NetworkOrdered<u16>>(to_underlying(class_));
  801. memcpy(class_bytes.data(), &net_class, 2);
  802. auto ttl_bytes = TRY(buffer.get_bytes_for_writing(4));
  803. auto net_ttl = static_cast<NetworkOrdered<u32>>(ttl);
  804. memcpy(ttl_bytes.data(), &net_ttl, 4);
  805. }
  806. ByteBuffer rdata;
  807. TRY(record.visit(
  808. [&](auto const& record) { return record.to_raw(rdata); },
  809. [&](ByteBuffer const& raw) { return rdata.try_append(raw); }));
  810. if (type != ResourceType::OPT) {
  811. auto rdata_length_bytes = TRY(buffer.get_bytes_for_writing(2));
  812. auto net_rdata_length = static_cast<NetworkOrdered<u16>>(rdata.size());
  813. memcpy(rdata_length_bytes.data(), &net_rdata_length, 2);
  814. }
  815. TRY(buffer.try_append(rdata));
  816. return {};
  817. }
  818. ErrorOr<String> ResourceRecord::to_string() const
  819. {
  820. StringBuilder builder;
  821. record.visit(
  822. [&](auto const& record) { builder.appendff("{}", MUST(record.to_string())); },
  823. [&](ByteBuffer const& raw) { builder.appendff("{:hex-dump}", raw.bytes()); });
  824. return builder.to_string();
  825. }
  826. ErrorOr<Records::A> Records::A::from_raw(ParseContext& ctx)
  827. {
  828. // RFC 1035, 3.4.1. A RDATA format.
  829. // | ADDRESS | a 32 bit Internet address.
  830. u32 const address = TRY(ctx.stream.read_value<LittleEndian<u32>>());
  831. return Records::A { IPv4Address { address } };
  832. }
  833. ErrorOr<Records::AAAA> Records::AAAA::from_raw(ParseContext& ctx)
  834. {
  835. // RFC 3596, 2.2. AAAA RDATA format.
  836. // | ADDRESS | a 128 bit Internet address.
  837. u128 const address = TRY(ctx.stream.read_value<LittleEndian<u128>>());
  838. return Records::AAAA { IPv6Address { bit_cast<Array<u8, 16>>(address) } };
  839. }
  840. ErrorOr<Records::TXT> Records::TXT::from_raw(ParseContext& ctx)
  841. {
  842. // RFC 1035, 3.3.14. TXT RDATA format.
  843. // | TXT-DATA | a <character-string> which is used for human readability.
  844. auto length = TRY(ctx.stream.read_value<u8>());
  845. ByteBuffer content;
  846. TRY(ctx.stream.read_until_filled(TRY(content.get_bytes_for_writing(length))));
  847. return Records::TXT { ByteString::copy(content) };
  848. }
  849. ErrorOr<Records::CNAME> Records::CNAME::from_raw(ParseContext& ctx)
  850. {
  851. // RFC 1035, 3.3.1. CNAME RDATA format.
  852. // | CNAME | a <domain-name> which specifies the canonical or primary name for the owner.
  853. auto name = TRY(DomainName::from_raw(ctx));
  854. return Records::CNAME { move(name) };
  855. }
  856. ErrorOr<Records::NS> Records::NS::from_raw(ParseContext& ctx)
  857. {
  858. // RFC 1035, 3.3.11. NS RDATA format.
  859. // | NSDNAME | a <domain-name> which specifies a host which should be authoritative for the specified class and domain.
  860. auto name = TRY(DomainName::from_raw(ctx));
  861. return Records::NS { move(name) };
  862. }
  863. ErrorOr<Records::SOA> Records::SOA::from_raw(ParseContext& ctx)
  864. {
  865. // RFC 1035, 3.3.13. SOA RDATA format.
  866. // | MNAME | <domain-name> which specifies the name of the host where the master file for the zone is maintained.
  867. // | RNAME | <domain-name> which specifies the mailbox of the person responsible for this zone.
  868. // | SERIAL | a 32-bit unsigned integer that specifies the version number of the original copy of the zone.
  869. // | REFRESH | a 32-bit unsigned integer that specifies the time interval before the zone should be refreshed.
  870. // | RETRY | a 32-bit unsigned integer that specifies the time interval that should elapse before a failed refresh should be retried.
  871. // | EXPIRE | a 32-bit unsigned integer that specifies the time value that specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative.
  872. // | MINIMUM | a 32-bit unsigned integer that specifies the minimum TTL field that should be exported with any RR from this zone.
  873. auto mname = TRY(DomainName::from_raw(ctx));
  874. auto rname = TRY(DomainName::from_raw(ctx));
  875. auto serial = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  876. auto refresh = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  877. auto retry = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  878. auto expire = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  879. auto minimum = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  880. return Records::SOA { move(mname), move(rname), serial, refresh, retry, expire, minimum };
  881. }
  882. ErrorOr<Records::MX> Records::MX::from_raw(ParseContext& ctx)
  883. {
  884. // RFC 1035, 3.3.9. MX RDATA format.
  885. // | PREFERENCE | a 16 bit integer which specifies the preference given to this RR among others at the same owner.
  886. // | EXCHANGE | a <domain-name> which specifies a host willing to act as a mail exchange for the owner name.
  887. auto preference = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  888. auto exchange = TRY(DomainName::from_raw(ctx));
  889. return Records::MX { preference, move(exchange) };
  890. }
  891. ErrorOr<Records::PTR> Records::PTR::from_raw(ParseContext& ctx)
  892. {
  893. // RFC 1035, 3.3.12. PTR RDATA format.
  894. // | PTRDNAME | a <domain-name> which points to some location in the domain name space.
  895. auto name = TRY(DomainName::from_raw(ctx));
  896. return Records::PTR { move(name) };
  897. }
  898. ErrorOr<Records::SRV> Records::SRV::from_raw(ParseContext& ctx)
  899. {
  900. // RFC 2782, 2. Service location and priority.
  901. // | PRIORITY | a 16 bit integer that specifies the priority of this target host.
  902. // | WEIGHT | a 16 bit integer that specifies a weight for this target host.
  903. // | PORT | a 16 bit integer that specifies the port on this target host.
  904. // | TARGET | a <domain-name> which specifies the target host.
  905. auto priority = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  906. auto weight = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  907. auto port = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  908. auto target = TRY(DomainName::from_raw(ctx));
  909. return Records::SRV { priority, weight, port, move(target) };
  910. }
  911. ErrorOr<Records::DNSKEY> Records::DNSKEY::from_raw(ParseContext& ctx)
  912. {
  913. // RFC 4034, 2.1. The DNSKEY Resource Record.
  914. // | FLAGS | a 16-bit value that flags the key.
  915. // | PROTOCOL | an 8-bit value that specifies the protocol for this key.
  916. // | ALGORITHM| an 8-bit value that identifies the public key's cryptographic algorithm.
  917. // | PUBLICKEY| the public key material.
  918. auto flags = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  919. auto protocol = TRY(ctx.stream.read_value<u8>());
  920. auto algorithm = static_cast<DNSSEC::Algorithm>(static_cast<u8>(TRY(ctx.stream.read_value<u8>())));
  921. auto public_key = TRY(ctx.stream.read_until_eof());
  922. return Records::DNSKEY { flags, protocol, algorithm, move(public_key) };
  923. }
  924. ErrorOr<Records::DS> Records::DS::from_raw(ParseContext& ctx)
  925. {
  926. // RFC 4034, 5.1. The DS Resource Record.
  927. // | KEYTAG | a 16-bit value that identifies the DNSKEY RR.
  928. // | ALGORITHM | an 8-bit value that identifies the DS's hash algorithm.
  929. // | DIGEST TYPE | an 8-bit value that identifies the DS's digest algorithm.
  930. // | DIGEST | Digest of the DNSKEY RDATA (Flags | Protocol | Algorithm | Pubkey).
  931. auto key_tag = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  932. auto algorithm = static_cast<DNSSEC::Algorithm>(static_cast<u8>(TRY(ctx.stream.read_value<u8>())));
  933. auto digest_type = static_cast<DNSSEC::DigestType>(static_cast<u8>(TRY(ctx.stream.read_value<u8>())));
  934. size_t digest_size;
  935. switch (digest_type) {
  936. case DNSSEC::DigestType::SHA1:
  937. digest_size = 20;
  938. break;
  939. case DNSSEC::DigestType::SHA256:
  940. case DNSSEC::DigestType::GOST3411:
  941. digest_size = 32;
  942. break;
  943. case DNSSEC::DigestType::SHA384:
  944. digest_size = 48;
  945. break;
  946. case DNSSEC::DigestType::SHA512:
  947. digest_size = 64;
  948. break;
  949. case DNSSEC::DigestType::SHA224:
  950. digest_size = 28;
  951. break;
  952. case DNSSEC::DigestType::Unknown:
  953. default:
  954. return Error::from_string_literal("Unknown digest type in DS record");
  955. }
  956. ByteBuffer digest;
  957. TRY(ctx.stream.read_until_filled(TRY(digest.get_bytes_for_writing(digest_size))));
  958. return Records::DS { key_tag, algorithm, digest_type, move(digest) };
  959. }
  960. ErrorOr<Records::SIG> Records::SIG::from_raw(ParseContext& ctx)
  961. {
  962. // RFC 4034, 2.2. The SIG Resource Record.
  963. // | TYPE-COVERED | a 16-bit value that specifies the type of the RRset that is covered by this SIG.
  964. // | ALGORITHM | an 8-bit value that specifies the algorithm used to create the signature.
  965. // | LABELS | an 8-bit value that specifies the number of labels in the original SIG RR owner name.
  966. // | ORIGINAL TTL | a 32-bit value that specifies the TTL of the covered RRset as it appears in the authoritative zone.
  967. // | SIGNATURE EXPIRATION | a 32-bit value that specifies the expiration date of the signature.
  968. // | SIGNATURE INCEPTION | a 32-bit value that specifies the inception date of the signature.
  969. // | KEY TAG | a 16-bit value that contains the key tag value of the DNSKEY RR that was used to create the signature.
  970. // | SIGNER'S NAME| a <domain-name> which specifies the domain name of the signer generating the SIG RR.
  971. // | SIGNATURE | a <signature> that authenticates the RRs.
  972. auto type_covered = static_cast<ResourceType>(static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>())));
  973. auto algorithm = static_cast<DNSSEC::Algorithm>(static_cast<u8>(TRY(ctx.stream.read_value<u8>())));
  974. auto labels = TRY(ctx.stream.read_value<u8>());
  975. auto original_ttl = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  976. auto signature_expiration = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  977. auto signature_inception = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  978. auto key_tag = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  979. auto signer_name = TRY(DomainName::from_raw(ctx));
  980. auto signature = TRY(ctx.stream.read_until_eof());
  981. return Records::SIG { type_covered, algorithm, labels, original_ttl, UnixDateTime::from_seconds_since_epoch(signature_expiration), UnixDateTime::from_seconds_since_epoch(signature_inception), key_tag, move(signer_name), move(signature) };
  982. }
  983. ErrorOr<String> Records::SIG::to_string() const
  984. {
  985. // Single line:
  986. // SIG Type covered: <type>, Algorithm: <algorithm>, Labels: <labels>, Original TTL: <ttl>, Signature expiration: <expiration>, Signature inception: <inception>, Key tag: <key tag>, Signer's name: <signer>, Signature: <signature>
  987. StringBuilder builder;
  988. builder.append("SIG "sv);
  989. builder.appendff("Type covered: {}, ", Messages::to_string(type_covered));
  990. builder.appendff("Algorithm: {}, ", DNSSEC::to_string(algorithm));
  991. builder.appendff("Labels: {}, ", label_count);
  992. builder.appendff("Original TTL: {}, ", original_ttl);
  993. builder.appendff("Signature expiration: {}, ", Core::DateTime::from_timestamp(expiration.truncated_seconds_since_epoch()));
  994. builder.appendff("Signature inception: {}, ", Core::DateTime::from_timestamp(inception.truncated_seconds_since_epoch()));
  995. builder.appendff("Key tag: {}, ", key_tag);
  996. builder.appendff("Signer's name: '{}', ", signers_name.to_string());
  997. builder.appendff("Signature: {}", TRY(encode_base64(signature)));
  998. return builder.to_string();
  999. }
  1000. ErrorOr<Records::HINFO> Records::HINFO::from_raw(ParseContext& ctx)
  1001. {
  1002. // RFC 1035, 3.3.2. HINFO RDATA format.
  1003. // | CPU | a <character-string> which specifies the CPU type.
  1004. // | OS | a <character-string> which specifies the operating system type.
  1005. auto cpu_length = TRY(ctx.stream.read_value<u8>());
  1006. ByteBuffer cpu;
  1007. TRY(ctx.stream.read_until_filled(TRY(cpu.get_bytes_for_writing(cpu_length))));
  1008. auto os_length = TRY(ctx.stream.read_value<u8>());
  1009. ByteBuffer os;
  1010. TRY(ctx.stream.read_until_filled(TRY(os.get_bytes_for_writing(os_length))));
  1011. return Records::HINFO { ByteString::copy(cpu), ByteString::copy(os) };
  1012. }
  1013. ErrorOr<Records::OPT> Records::OPT::from_raw(ParseContext& ctx)
  1014. {
  1015. // RFC 6891, 6.1. The OPT pseudo-RR.
  1016. // This RR does *not* use the standard RDATA format, `ctx` starts right after 'TYPE'.
  1017. // | NAME | empty (root domain)
  1018. // | TYPE | OPT (41)
  1019. // - we are here -
  1020. // | UDP SIZE | 16-bit max UDP payload size
  1021. // | RCODE_AND_FLAGS | 32-bit flags and response code
  1022. // | RDLENGTH | 16-bit length of the RDATA field
  1023. // | RDATA | variable length, pairs of OPTION-CODE and OPTION-DATA { length(16), data(length) }
  1024. auto udp_size = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  1025. auto rcode_and_flags = static_cast<u32>(TRY(ctx.stream.read_value<NetworkOrdered<u32>>()));
  1026. auto rd_length = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  1027. Vector<OPT::Option> options;
  1028. while (rd_length > 0 && !ctx.stream.is_eof()) {
  1029. auto option_code = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  1030. auto option_length = static_cast<u16>(TRY(ctx.stream.read_value<NetworkOrdered<u16>>()));
  1031. ByteBuffer option_data;
  1032. TRY(ctx.stream.read_until_filled(TRY(option_data.get_bytes_for_writing(option_length))));
  1033. rd_length -= 4 + option_length;
  1034. options.append(OPT::Option { option_code, move(option_data) });
  1035. }
  1036. if (rd_length != 0)
  1037. return Error::from_string_literal("Invalid OPT record");
  1038. return Records::OPT { udp_size, rcode_and_flags, move(options) };
  1039. }
  1040. ErrorOr<void> Records::OPT::to_raw(ByteBuffer& buffer) const
  1041. {
  1042. auto udp_size_bytes = TRY(buffer.get_bytes_for_writing(sizeof(udp_payload_size)));
  1043. auto net_udp_size = static_cast<NetworkOrdered<u16>>(udp_payload_size);
  1044. memcpy(udp_size_bytes.data(), &net_udp_size, 2);
  1045. auto rcode_and_flags_bytes = TRY(buffer.get_bytes_for_writing(sizeof(extended_rcode_and_flags)));
  1046. auto net_rcode_and_flags = static_cast<NetworkOrdered<u32>>(extended_rcode_and_flags);
  1047. memcpy(rcode_and_flags_bytes.data(), &net_rcode_and_flags, 4);
  1048. auto rd_length_bytes = TRY(buffer.get_bytes_for_writing(2));
  1049. u16 rd_length = 0;
  1050. for (auto const& option : options) {
  1051. rd_length += 4 + option.data.size();
  1052. }
  1053. auto net_rd_length = static_cast<NetworkOrdered<u16>>(rd_length);
  1054. memcpy(rd_length_bytes.data(), &net_rd_length, 2);
  1055. for (auto& option : options) {
  1056. auto option_code_bytes = TRY(buffer.get_bytes_for_writing(sizeof(option.code)));
  1057. auto net_option_code = static_cast<NetworkOrdered<u16>>(option.code);
  1058. memcpy(option_code_bytes.data(), &net_option_code, 2);
  1059. auto option_length_bytes = TRY(buffer.get_bytes_for_writing(2));
  1060. auto net_option_length = static_cast<NetworkOrdered<u16>>(option.data.size());
  1061. memcpy(option_length_bytes.data(), &net_option_length, 2);
  1062. TRY(buffer.try_append(option.data));
  1063. }
  1064. return {};
  1065. }
  1066. }