mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 1554976 - Run mach vendor rust; r=ng
Differential Revision: https://phabricator.services.mozilla.com/D38491 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
a17af56ba5
commit
b9e2e7f9b3
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -954,6 +954,15 @@ dependencies = [
|
||||
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dns-parser"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dogear"
|
||||
version = "0.3.3"
|
||||
@ -1277,6 +1286,7 @@ dependencies = [
|
||||
"kvstore 0.1.0",
|
||||
"lmdb-rkv-sys 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mdns_service 0.1.0",
|
||||
"mozurl 0.0.1",
|
||||
"mp4parse_capi 0.11.2",
|
||||
"netwerk_helper 0.0.1",
|
||||
@ -1735,6 +1745,17 @@ name = "matches"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "mdns_service"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"socket2 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.2"
|
||||
@ -3947,6 +3968,7 @@ dependencies = [
|
||||
"checksum devd-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d009f166c0d9e9f9909dc751630b3a6411ab7f85a153d32d01deb364ffe52a7"
|
||||
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
|
||||
"checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea"
|
||||
"checksum dogear 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57cd6ee785daa898686f3e2fb4a2b1ce490fcd6d69665c857d16fb61b48f4aae"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
"checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
|
||||
|
1
third_party/rust/dns-parser/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/dns-parser/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"7b47cb4d67f549cce93b578b0911177365055bbbc15790644251cac1856a11f7","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"71fb06f353ef01dbb828a61a74eadbfc57ab4e1b20eaae1db68229f1647c4183","README.md":"85171334a4b9e672811377819e7f178abdd1870f09d1a1250fe25a7ffaf4b5bf","bulk.yaml":"17c2548388e0cd3a63473021a2f1e4ddedee082d79d9167cb31ad06a1890d3fc","examples/sync_tcp_client.rs":"8ba349565ae9872fc3e246469eab0f7041355d38100355d07a2c1ff2cd048476","examples/sync_udp_client.rs":"ee32137e43d6ab4da6c6f1b36d956042fb74d2704ec319acd058ca74fdc489c1","src/builder.rs":"1dc20c218e5e3b8d0d0f7cdc7ab585882d9960493881be5f17ad2ea5ce8c9dd5","src/enums.rs":"0e0afe0987805ac7361bb6fcaee8a235f375312fa372a6fc8d9b36a85710a9c9","src/error.rs":"6abc85f52724ef8aa12e1ff40a747a02b018b99ae259880a9ff222959f567200","src/header.rs":"f96466c2c0c5647fab0718e9e8289aa9933e988015e454c38ecb7d3c0b6b6813","src/lib.rs":"98994eb0dfea6864d9cf26e1c6ff32f31249e9eaec4583387524dc919e4dde49","src/name.rs":"3d80f16e473e32780e60d814ea3af54094e8c813af576743b108deaf960da27e","src/parser.rs":"02af73135af936115a0ac99da7d102d5ef3c58890abe98d0cfefcd3814b98463","src/rdata/a.rs":"a66498dc4f02af5c95b53f09e2860fed69881410eb02a30bceee0b976e8f8c41","src/rdata/aaaa.rs":"0163de1dc6a691f2ede528cb865f1197511800742879bda189e65aadd682e6c4","src/rdata/all.rs":"005b8edc4aae6f140332f75420c900bae91be66dfb2fdcdd177d51280bbc3750","src/rdata/axfr.rs":"19e18099a16baf33e34ea23905ec5913834aa367a034343551fe935a367f20db","src/rdata/cname.rs":"f31f3c490b6fcd9d5300d4c3903c398cfdd7ff89154685fc3fb182b3fa553ecf","src/rdata/hinfo.rs":"3edd6e2685a048b7d35872582490cdffa90ca7aa688ecffe1d91c46b9ccede1c","src/rdata/maila.rs":"f3f5a40cebd458ed83da7d910601cab761883eee14e991c677d325e6f2fcd968","src/rdata/mailb.rs":"6e09a86dab9a516b4022eefb6a06dcb7d9b06e15d3a80e8027db285e43e5f870","src/rdata/mb.rs":"b867aa5e0f1ec0970d8d6d6406773a8b7af5291dbcf1d8d78be9d017d8cc5a81","src/rdata/mf.rs":"2494cf316f1c2bf803237ce01e7bbbdf05a736fcac2536a06a34ebaf51c815ae","src/rdata/mg.rs":"14a1c9813bc7a33811efa4855c0ac29288cbc1ec535f7c67609333a2a8a5612b","src/rdata/minfo.rs":"72bf7b87ca494865327866ddf9733fb9b137cf2cd4222338237f107b4ff5062d","src/rdata/mod.rs":"0a6f377059eee38371893d17c31d97fb214f209c89c43f5f9302e3560150a220","src/rdata/mr.rs":"0140e5a4c1b6af5e55a61027c21e1760cd2b5a8f1929604d3884225b9433054a","src/rdata/mx.rs":"a38113e7b6efbc65831582fbfacbb6ed1937e167f1b8a19a36a27b0b600ec085","src/rdata/ns.rs":"2acf2d552f3e4f94af50b1c46a6cefc99515a930b099e2d93e9a595f4e1746b5","src/rdata/nsec.rs":"0a712e38c35c60815a2b1394e4bb4f9e229311e80bc9e59b0e854354f928d5a5","src/rdata/null.rs":"0ee8104671d5238da7885b90248ffc952f1558eaa43dfe15b60292166a992a38","src/rdata/opt.rs":"24eb3346b88b3aec18985bd2c1db6498160a59ed7fabfc8b45ce174f10638653","src/rdata/ptr.rs":"9ab2459fc87f90edb2bc7d0fbb97ab008cedf3ce62c042d1b25181914a5ee5c6","src/rdata/soa.rs":"0bf7321ff2891af8f9a3d6b58199464a77b1556e705fa1e9b52f23358bb4bf47","src/rdata/srv.rs":"7d755cb64f42d3096a763739e31959ebec439855380869cd801196bb507102aa","src/rdata/txt.rs":"9e00d2b64cfc53fa8ac510a8c624f5d42320cd90f8a50d040cfc666b530fd8ad","src/rdata/wks.rs":"abfb5572d2c270838489a6ff611c76cb0d3dc7470f44a6810fb89894febd8840","src/structs.rs":"4692edebde24c3be4a7aae81f75b8dc69a9c1ed460bf80740a75bc13f5e40b82","vagga.yaml":"3662f1f49317908fd54ab7830d53074b4bdd753ae85bc3a6fcf6fabaa6b42c70"},"package":"c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea"}
|
41
third_party/rust/dns-parser/Cargo.toml
vendored
Normal file
41
third_party/rust/dns-parser/Cargo.toml
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "dns-parser"
|
||||
version = "0.8.0"
|
||||
authors = ["Paul Colomiets <paul@colomiets.name>"]
|
||||
description = " Pure-rust DNS protocol parser library. This does not support network, only\n raw protocol parser.\n"
|
||||
homepage = "https://github.com/tailhook/dns-parser"
|
||||
documentation = "https://docs.rs/dns-parser"
|
||||
readme = "README.md"
|
||||
keywords = ["dns", "domain", "name", "parser"]
|
||||
categories = ["parser-implementations"]
|
||||
license = "MIT/Apache-2.0"
|
||||
[dependencies.byteorder]
|
||||
version = "1"
|
||||
|
||||
[dependencies.quick-error]
|
||||
version = "1.0.0"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.serde_derive]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
[dev-dependencies.matches]
|
||||
version = "0.1.2"
|
||||
|
||||
[features]
|
||||
with-serde = ["serde", "serde_derive"]
|
202
third_party/rust/dns-parser/LICENSE-APACHE
vendored
Normal file
202
third_party/rust/dns-parser/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
19
third_party/rust/dns-parser/LICENSE-MIT
vendored
Normal file
19
third_party/rust/dns-parser/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2016 The dns-parser Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
31
third_party/rust/dns-parser/README.md
vendored
Normal file
31
third_party/rust/dns-parser/README.md
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
DNS Parser
|
||||
==========
|
||||
|
||||
**Status: beta**
|
||||
|
||||
[Documentation](https://docs.rs/dns-parser) |
|
||||
[Github](https://github.com/tailhook/dns-parser) |
|
||||
[Crate](https://crates.io/crates/dns-parser)
|
||||
|
||||
This is a parser of DNS protocol packets that is independent of any networking
|
||||
code.
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0,
|
||||
(./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license (./LICENSE-MIT or http://opensource.org/licenses/MIT)
|
||||
at your option.
|
||||
|
||||
Contribution
|
||||
------------
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally
|
||||
submitted for inclusion in the work by you, as defined in the Apache-2.0
|
||||
license, shall be dual licensed as above, without any additional terms or
|
||||
conditions.
|
||||
|
8
third_party/rust/dns-parser/bulk.yaml
vendored
Normal file
8
third_party/rust/dns-parser/bulk.yaml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
minimum-bulk: v0.4.5
|
||||
|
||||
versions:
|
||||
|
||||
- file: Cargo.toml
|
||||
block-start: ^\[package\]
|
||||
block-end: ^\[.*\]
|
||||
regex: ^version\s*=\s*"(\S+)"
|
77
third_party/rust/dns-parser/examples/sync_tcp_client.rs
vendored
Normal file
77
third_party/rust/dns-parser/examples/sync_tcp_client.rs
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
extern crate dns_parser;
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::TcpStream;
|
||||
use std::process;
|
||||
|
||||
|
||||
use dns_parser::{Builder, Packet, RData, ResponseCode};
|
||||
use dns_parser::rdata::a::Record;
|
||||
use dns_parser::{QueryType, QueryClass};
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut code = 0;
|
||||
for name in env::args().skip(1) {
|
||||
match resolve(&name) {
|
||||
Ok(()) => {},
|
||||
Err(e) => {
|
||||
eprintln!("Error resolving {:?}: {}", name, e);
|
||||
code = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
process::exit(code);
|
||||
}
|
||||
|
||||
fn resolve(name: &str) -> Result<(), Box<Error>> {
|
||||
let mut conn = TcpStream::connect("127.0.0.1:53")?;
|
||||
let mut builder = Builder::new_query(1, true);
|
||||
builder.add_question(name, false, QueryType::A, QueryClass::IN);
|
||||
let packet = builder.build().map_err(|_| "truncated packet")?;
|
||||
let psize = [((packet.len() >> 8) & 0xFF) as u8,
|
||||
(packet.len() & 0xFF) as u8];
|
||||
conn.write_all(&psize[..])?;
|
||||
conn.write_all(&packet)?;
|
||||
let mut buf = vec![0u8; 4096];
|
||||
let mut off = 0;
|
||||
let pkt = loop {
|
||||
if buf.len() - off < 4096 {
|
||||
buf.extend(&[0u8; 4096][..]);
|
||||
}
|
||||
match conn.read(&mut buf[off..]) {
|
||||
Ok(num) => {
|
||||
off += num;
|
||||
if off < 2 { continue; }
|
||||
let bytes = ((buf[0] as usize) << 8) | buf[1] as usize;
|
||||
if off < bytes + 2 {
|
||||
continue;
|
||||
}
|
||||
if num == 0 {
|
||||
return Err("Partial packet received".into());
|
||||
}
|
||||
break Packet::parse(&buf[2..off])?;
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(Box::new(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
if pkt.header.response_code != ResponseCode::NoError {
|
||||
return Err(pkt.header.response_code.into());
|
||||
}
|
||||
if pkt.answers.len() == 0 {
|
||||
return Err("No records received".into());
|
||||
}
|
||||
for ans in pkt.answers {
|
||||
match ans.data {
|
||||
RData::A(Record(ip)) => {
|
||||
println!("{}", ip);
|
||||
}
|
||||
_ => {} // ignore
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
53
third_party/rust/dns-parser/examples/sync_udp_client.rs
vendored
Normal file
53
third_party/rust/dns-parser/examples/sync_udp_client.rs
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
extern crate dns_parser;
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::net::UdpSocket;
|
||||
use std::process;
|
||||
|
||||
|
||||
use dns_parser::{Builder, Packet, RData, ResponseCode};
|
||||
use dns_parser::rdata::a::Record;
|
||||
use dns_parser::{QueryType, QueryClass};
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut code = 0;
|
||||
for name in env::args().skip(1) {
|
||||
match resolve(&name) {
|
||||
Ok(()) => {},
|
||||
Err(e) => {
|
||||
eprintln!("Error resolving {:?}: {}", name, e);
|
||||
code = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
process::exit(code);
|
||||
}
|
||||
|
||||
fn resolve(name: &str) -> Result<(), Box<Error>> {
|
||||
let sock = UdpSocket::bind("127.0.0.1:0")?;
|
||||
sock.connect("127.0.0.1:53")?;
|
||||
let mut builder = Builder::new_query(1, true);
|
||||
builder.add_question(name, false, QueryType::A, QueryClass::IN);
|
||||
let packet = builder.build().map_err(|_| "truncated packet")?;
|
||||
sock.send(&packet)?;
|
||||
let mut buf = vec![0u8; 4096];
|
||||
sock.recv(&mut buf)?;
|
||||
let pkt = Packet::parse(&buf)?;
|
||||
if pkt.header.response_code != ResponseCode::NoError {
|
||||
return Err(pkt.header.response_code.into());
|
||||
}
|
||||
if pkt.answers.len() == 0 {
|
||||
return Err("No records received".into());
|
||||
}
|
||||
for ans in pkt.answers {
|
||||
match ans.data {
|
||||
RData::A(Record(ip)) => {
|
||||
println!("{}", ip);
|
||||
}
|
||||
_ => {} // ignore
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
132
third_party/rust/dns-parser/src/builder.rs
vendored
Normal file
132
third_party/rust/dns-parser/src/builder.rs
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
use byteorder::{ByteOrder, BigEndian, WriteBytesExt};
|
||||
|
||||
use {Opcode, ResponseCode, Header, QueryType, QueryClass};
|
||||
|
||||
/// Allows to build a DNS packet
|
||||
///
|
||||
/// Both query and answer packets may be built with this interface, although,
|
||||
/// much of functionality is not implemented yet.
|
||||
#[derive(Debug)]
|
||||
pub struct Builder {
|
||||
buf: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Creates a new query
|
||||
///
|
||||
/// Initially all sections are empty. You're expected to fill
|
||||
/// the questions section with `add_question`
|
||||
pub fn new_query(id: u16, recursion: bool) -> Builder {
|
||||
let mut buf = Vec::with_capacity(512);
|
||||
let head = Header {
|
||||
id: id,
|
||||
query: true,
|
||||
opcode: Opcode::StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: recursion,
|
||||
recursion_available: false,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: ResponseCode::NoError,
|
||||
questions: 0,
|
||||
answers: 0,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
};
|
||||
buf.extend([0u8; 12].iter());
|
||||
head.write(&mut buf[..12]);
|
||||
Builder { buf: buf }
|
||||
}
|
||||
/// Adds a question to the packet
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * Answers, nameservers or additional section has already been written
|
||||
/// * There are already 65535 questions in the buffer.
|
||||
/// * When name is invalid
|
||||
pub fn add_question(&mut self, qname: &str, prefer_unicast: bool,
|
||||
qtype: QueryType, qclass: QueryClass)
|
||||
-> &mut Builder
|
||||
{
|
||||
if &self.buf[6..12] != b"\x00\x00\x00\x00\x00\x00" {
|
||||
panic!("Too late to add a question");
|
||||
}
|
||||
self.write_name(qname);
|
||||
self.buf.write_u16::<BigEndian>(qtype as u16).unwrap();
|
||||
let prefer_unicast: u16 = if prefer_unicast { 0x8000 } else { 0x0000 };
|
||||
self.buf.write_u16::<BigEndian>(qclass as u16 | prefer_unicast).unwrap();
|
||||
let oldq = BigEndian::read_u16(&self.buf[4..6]);
|
||||
if oldq == 65535 {
|
||||
panic!("Too many questions");
|
||||
}
|
||||
BigEndian::write_u16(&mut self.buf[4..6], oldq+1);
|
||||
self
|
||||
}
|
||||
fn write_name(&mut self, name: &str) {
|
||||
for part in name.split('.') {
|
||||
assert!(part.len() < 63);
|
||||
let ln = part.len() as u8;
|
||||
self.buf.push(ln);
|
||||
self.buf.extend(part.as_bytes());
|
||||
}
|
||||
self.buf.push(0);
|
||||
}
|
||||
/// Returns the final packet
|
||||
///
|
||||
/// When packet is not truncated method returns `Ok(packet)`. If
|
||||
/// packet is truncated the method returns `Err(packet)`. In both
|
||||
/// cases the packet is fully valid.
|
||||
///
|
||||
/// In the server implementation you may use
|
||||
/// `x.build().unwrap_or_else(|x| x)`.
|
||||
///
|
||||
/// In the client implementation it's probably unwise to send truncated
|
||||
/// packet, as it doesn't make sense. Even panicking may be more
|
||||
/// appropriate.
|
||||
// TODO(tailhook) does the truncation make sense for TCP, and how
|
||||
// to treat it for EDNS0?
|
||||
pub fn build(mut self) -> Result<Vec<u8>,Vec<u8>> {
|
||||
// TODO(tailhook) optimize labels
|
||||
if self.buf.len() > 512 {
|
||||
Header::set_truncated(&mut self.buf[..12]);
|
||||
Err(self.buf)
|
||||
} else {
|
||||
Ok(self.buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use super::Builder;
|
||||
|
||||
#[test]
|
||||
fn build_query() {
|
||||
let mut bld = Builder::new_query(1573, true);
|
||||
bld.add_question("example.com", false, QT::A, QC::IN);
|
||||
let result = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x00\x01";
|
||||
assert_eq!(&bld.build().unwrap()[..], &result[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_unicast_query() {
|
||||
let mut bld = Builder::new_query(1573, true);
|
||||
bld.add_question("example.com", true, QT::A, QC::IN);
|
||||
let result = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x80\x01";
|
||||
assert_eq!(&bld.build().unwrap()[..], &result[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_srv_query() {
|
||||
let mut bld = Builder::new_query(23513, true);
|
||||
bld.add_question("_xmpp-server._tcp.gmail.com", false, QT::SRV, QC::IN);
|
||||
let result = b"[\xd9\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01";
|
||||
assert_eq!(&bld.build().unwrap()[..], &result[..]);
|
||||
}
|
||||
}
|
299
third_party/rust/dns-parser/src/enums.rs
vendored
Normal file
299
third_party/rust/dns-parser/src/enums.rs
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
use {Error};
|
||||
use rdata::Record;
|
||||
use rdata::*;
|
||||
|
||||
/// The TYPE value according to RFC 1035
|
||||
///
|
||||
/// All "EXPERIMENTAL" markers here are from the RFC
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Type {
|
||||
/// a host addresss
|
||||
A = a::Record::TYPE,
|
||||
/// an authoritative name server
|
||||
NS = ns::Record::TYPE,
|
||||
/// a mail forwarder (Obsolete - use MX)
|
||||
MF = mf::Record::TYPE,
|
||||
/// the canonical name for an alias
|
||||
CNAME = cname::Record::TYPE,
|
||||
/// marks the start of a zone of authority
|
||||
SOA = soa::Record::TYPE,
|
||||
/// a mailbox domain name (EXPERIMENTAL)
|
||||
MB = mb::Record::TYPE,
|
||||
/// a mail group member (EXPERIMENTAL)
|
||||
MG = mg::Record::TYPE,
|
||||
/// a mail rename domain name (EXPERIMENTAL)
|
||||
MR = mr::Record::TYPE,
|
||||
/// a null RR (EXPERIMENTAL)
|
||||
NULL = null::Record::TYPE,
|
||||
/// a well known service description
|
||||
WKS = wks::Record::TYPE,
|
||||
/// a domain name pointer
|
||||
PTR = ptr::Record::TYPE,
|
||||
/// host information
|
||||
HINFO = hinfo::Record::TYPE,
|
||||
/// mailbox or mail list information
|
||||
MINFO = minfo::Record::TYPE,
|
||||
/// mail exchange
|
||||
MX = mx::Record::TYPE,
|
||||
/// text strings
|
||||
TXT = txt::Record::TYPE,
|
||||
/// IPv6 host address (RFC 2782)
|
||||
AAAA = aaaa::Record::TYPE,
|
||||
/// service record (RFC 2782)
|
||||
SRV = srv::Record::TYPE,
|
||||
/// EDNS0 options (RFC 6891)
|
||||
OPT = opt::Record::TYPE,
|
||||
/// next secure record (RFC 4034, RFC 6762)
|
||||
NSEC = nsec::Record::TYPE,
|
||||
}
|
||||
|
||||
/// The QTYPE value according to RFC 1035
|
||||
///
|
||||
/// All "EXPERIMENTAL" markers here are from the RFC
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
|
||||
pub enum QueryType {
|
||||
/// a host addresss
|
||||
A = a::Record::TYPE,
|
||||
/// an authoritative name server
|
||||
NS = ns::Record::TYPE,
|
||||
/// a mail forwarder (Obsolete - use MX)
|
||||
MF = mf::Record::TYPE,
|
||||
/// the canonical name for an alias
|
||||
CNAME = cname::Record::TYPE,
|
||||
/// marks the start of a zone of authority
|
||||
SOA = soa::Record::TYPE,
|
||||
/// a mailbox domain name (EXPERIMENTAL)
|
||||
MB = mb::Record::TYPE,
|
||||
/// a mail group member (EXPERIMENTAL)
|
||||
MG = mg::Record::TYPE,
|
||||
/// a mail rename domain name (EXPERIMENTAL)
|
||||
MR = mr::Record::TYPE,
|
||||
/// a null RR (EXPERIMENTAL)
|
||||
NULL = null::Record::TYPE,
|
||||
/// a well known service description
|
||||
WKS = wks::Record::TYPE,
|
||||
/// a domain name pointer
|
||||
PTR = ptr::Record::TYPE,
|
||||
/// host information
|
||||
HINFO = hinfo::Record::TYPE,
|
||||
/// mailbox or mail list information
|
||||
MINFO = minfo::Record::TYPE,
|
||||
/// mail exchange
|
||||
MX = mx::Record::TYPE,
|
||||
/// text strings
|
||||
TXT = txt::Record::TYPE,
|
||||
/// IPv6 host address (RFC 2782)
|
||||
AAAA = aaaa::Record::TYPE,
|
||||
/// service record (RFC 2782)
|
||||
SRV = srv::Record::TYPE,
|
||||
/// A request for a transfer of an entire zone
|
||||
AXFR = axfr::Record::TYPE,
|
||||
/// A request for mailbox-related records (MB, MG or MR)
|
||||
MAILB = mailb::Record::TYPE,
|
||||
/// A request for mail agent RRs (Obsolete - see MX)
|
||||
MAILA = maila::Record::TYPE,
|
||||
/// A request for all records
|
||||
All = all::Record::TYPE,
|
||||
}
|
||||
|
||||
|
||||
/// The CLASS value according to RFC 1035
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Class {
|
||||
/// the Internet
|
||||
IN = 1,
|
||||
/// the CSNET class (Obsolete - used only for examples in some obsolete
|
||||
/// RFCs)
|
||||
CS = 2,
|
||||
/// the CHAOS class
|
||||
CH = 3,
|
||||
/// Hesiod [Dyer 87]
|
||||
HS = 4,
|
||||
}
|
||||
|
||||
/// The QCLASS value according to RFC 1035
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum QueryClass {
|
||||
/// the Internet
|
||||
IN = 1,
|
||||
/// the CSNET class (Obsolete - used only for examples in some obsolete
|
||||
/// RFCs)
|
||||
CS = 2,
|
||||
/// the CHAOS class
|
||||
CH = 3,
|
||||
/// Hesiod [Dyer 87]
|
||||
HS = 4,
|
||||
/// Any class
|
||||
Any = 255,
|
||||
}
|
||||
|
||||
/// The OPCODE value according to RFC 1035
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Opcode {
|
||||
/// Normal query
|
||||
StandardQuery,
|
||||
/// Inverse query (query a name by IP)
|
||||
InverseQuery,
|
||||
/// Server status request
|
||||
ServerStatusRequest,
|
||||
/// Reserved opcode for future use
|
||||
Reserved(u16),
|
||||
}
|
||||
|
||||
quick_error! {
|
||||
/// The RCODE value according to RFC 1035
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[allow(missing_docs)] // names are from spec
|
||||
pub enum ResponseCode {
|
||||
NoError
|
||||
FormatError
|
||||
ServerFailure
|
||||
NameError
|
||||
NotImplemented
|
||||
Refused
|
||||
Reserved(code: u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for Opcode {
|
||||
fn from(code: u16) -> Opcode {
|
||||
use self::Opcode::*;
|
||||
match code {
|
||||
0 => StandardQuery,
|
||||
1 => InverseQuery,
|
||||
2 => ServerStatusRequest,
|
||||
x => Reserved(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Into<u16> for Opcode {
|
||||
fn into(self) -> u16 {
|
||||
use self::Opcode::*;
|
||||
match self {
|
||||
StandardQuery => 0,
|
||||
InverseQuery => 1,
|
||||
ServerStatusRequest => 2,
|
||||
Reserved(x) => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for ResponseCode {
|
||||
fn from(code: u8) -> ResponseCode {
|
||||
use self::ResponseCode::*;
|
||||
match code {
|
||||
0 => NoError,
|
||||
1 => FormatError,
|
||||
2 => ServerFailure,
|
||||
3 => NameError,
|
||||
4 => NotImplemented,
|
||||
5 => Refused,
|
||||
6...15 => Reserved(code),
|
||||
x => panic!("Invalid response code {}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Into<u8> for ResponseCode {
|
||||
fn into(self) -> u8 {
|
||||
use self::ResponseCode::*;
|
||||
match self {
|
||||
NoError => 0,
|
||||
FormatError => 1,
|
||||
ServerFailure => 2,
|
||||
NameError => 3,
|
||||
NotImplemented => 4,
|
||||
Refused => 5,
|
||||
Reserved(code) => code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryType {
|
||||
/// Parse a query type code
|
||||
pub fn parse(code: u16) -> Result<QueryType, Error> {
|
||||
use self::QueryType::*;
|
||||
match code as isize {
|
||||
a::Record::TYPE => Ok(A),
|
||||
ns::Record::TYPE => Ok(NS),
|
||||
mf::Record::TYPE => Ok(MF),
|
||||
cname::Record::TYPE => Ok(CNAME),
|
||||
soa::Record::TYPE => Ok(SOA),
|
||||
mb::Record::TYPE => Ok(MB),
|
||||
mg::Record::TYPE => Ok(MG),
|
||||
mr::Record::TYPE => Ok(MR),
|
||||
null::Record::TYPE => Ok(NULL),
|
||||
wks::Record::TYPE => Ok(WKS),
|
||||
ptr::Record::TYPE => Ok(PTR),
|
||||
hinfo::Record::TYPE => Ok(HINFO),
|
||||
minfo::Record::TYPE => Ok(MINFO),
|
||||
mx::Record::TYPE => Ok(MX),
|
||||
txt::Record::TYPE => Ok(TXT),
|
||||
aaaa::Record::TYPE => Ok(AAAA),
|
||||
srv::Record::TYPE => Ok(SRV),
|
||||
axfr::Record::TYPE => Ok(AXFR),
|
||||
mailb::Record::TYPE => Ok(MAILB),
|
||||
maila::Record::TYPE => Ok(MAILA),
|
||||
all::Record::TYPE => Ok(All),
|
||||
x => Err(Error::InvalidQueryType(x as u16)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryClass {
|
||||
/// Parse a query class code
|
||||
pub fn parse(code: u16) -> Result<QueryClass, Error> {
|
||||
use self::QueryClass::*;
|
||||
match code {
|
||||
1 => Ok(IN),
|
||||
2 => Ok(CS),
|
||||
3 => Ok(CH),
|
||||
4 => Ok(HS),
|
||||
255 => Ok(Any),
|
||||
x => Err(Error::InvalidQueryClass(x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
/// Parse a type code
|
||||
pub fn parse(code: u16) -> Result<Type, Error> {
|
||||
use self::Type::*;
|
||||
match code as isize {
|
||||
a::Record::TYPE => Ok(A),
|
||||
ns::Record::TYPE => Ok(NS),
|
||||
mf::Record::TYPE => Ok(MF),
|
||||
cname::Record::TYPE => Ok(CNAME),
|
||||
soa::Record::TYPE => Ok(SOA),
|
||||
mb::Record::TYPE => Ok(MB),
|
||||
mg::Record::TYPE => Ok(MG),
|
||||
mr::Record::TYPE => Ok(MR),
|
||||
null::Record::TYPE => Ok(NULL),
|
||||
wks::Record::TYPE => Ok(WKS),
|
||||
ptr::Record::TYPE => Ok(PTR),
|
||||
hinfo::Record::TYPE => Ok(HINFO),
|
||||
minfo::Record::TYPE => Ok(MINFO),
|
||||
mx::Record::TYPE => Ok(MX),
|
||||
txt::Record::TYPE => Ok(TXT),
|
||||
aaaa::Record::TYPE => Ok(AAAA),
|
||||
srv::Record::TYPE => Ok(SRV),
|
||||
opt::Record::TYPE => Ok(OPT),
|
||||
nsec::Record::TYPE => Ok(NSEC),
|
||||
x => Err(Error::InvalidType(x as u16)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Class {
|
||||
/// Parse a class code
|
||||
pub fn parse(code: u16) -> Result<Class, Error> {
|
||||
use self::Class::*;
|
||||
match code {
|
||||
1 => Ok(IN),
|
||||
2 => Ok(CS),
|
||||
3 => Ok(CH),
|
||||
4 => Ok(HS),
|
||||
x => Err(Error::InvalidClass(x)),
|
||||
}
|
||||
}
|
||||
}
|
71
third_party/rust/dns-parser/src/error.rs
vendored
Normal file
71
third_party/rust/dns-parser/src/error.rs
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
use std::str::Utf8Error;
|
||||
|
||||
quick_error! {
|
||||
/// Error parsing DNS packet
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Invalid compression pointer not pointing backwards
|
||||
/// when parsing label
|
||||
BadPointer {
|
||||
description("invalid compression pointer not pointing backwards \
|
||||
when parsing label")
|
||||
}
|
||||
/// Packet is smaller than header size
|
||||
HeaderTooShort {
|
||||
description("packet is smaller than header size")
|
||||
}
|
||||
/// Packet ihas incomplete data
|
||||
UnexpectedEOF {
|
||||
description("packet is has incomplete data")
|
||||
}
|
||||
/// Wrong (too short or too long) size of RDATA
|
||||
WrongRdataLength {
|
||||
description("wrong (too short or too long) size of RDATA")
|
||||
}
|
||||
/// Packet has non-zero reserved bits
|
||||
ReservedBitsAreNonZero {
|
||||
description("packet has non-zero reserved bits")
|
||||
}
|
||||
/// Label in domain name has unknown label format
|
||||
UnknownLabelFormat {
|
||||
description("label in domain name has unknown label format")
|
||||
}
|
||||
/// Query type code is invalid
|
||||
InvalidQueryType(code: u16) {
|
||||
description("query type code is invalid")
|
||||
display("query type {} is invalid", code)
|
||||
}
|
||||
/// Query class code is invalid
|
||||
InvalidQueryClass(code: u16) {
|
||||
description("query class code is invalid")
|
||||
display("query class {} is invalid", code)
|
||||
}
|
||||
/// Type code is invalid
|
||||
InvalidType(code: u16) {
|
||||
description("type code is invalid")
|
||||
display("type {} is invalid", code)
|
||||
}
|
||||
/// Class code is invalid
|
||||
InvalidClass(code: u16) {
|
||||
description("class code is invalid")
|
||||
display("class {} is invalid", code)
|
||||
}
|
||||
/// Invalid characters encountered while reading label
|
||||
LabelIsNotAscii {
|
||||
description("invalid characters encountered while reading label")
|
||||
}
|
||||
/// Invalid characters encountered while reading TXT
|
||||
TxtDataIsNotUTF8(error: Utf8Error) {
|
||||
description("invalid characters encountered while reading TXT")
|
||||
display("{:?}", error)
|
||||
}
|
||||
/// Parser is in the wrong state
|
||||
WrongState {
|
||||
description("parser is in the wrong state")
|
||||
}
|
||||
/// Additional OPT record found
|
||||
AdditionalOPT {
|
||||
description("additional OPT record found")
|
||||
}
|
||||
}
|
||||
}
|
203
third_party/rust/dns-parser/src/header.rs
vendored
Normal file
203
third_party/rust/dns-parser/src/header.rs
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
use {Error, ResponseCode, Opcode};
|
||||
|
||||
mod flag {
|
||||
pub const QUERY: u16 = 0b1000_0000_0000_0000;
|
||||
pub const OPCODE_MASK: u16 = 0b0111_1000_0000_0000;
|
||||
pub const AUTHORITATIVE: u16 = 0b0000_0100_0000_0000;
|
||||
pub const TRUNCATED: u16 = 0b0000_0010_0000_0000;
|
||||
pub const RECURSION_DESIRED: u16 = 0b0000_0001_0000_0000;
|
||||
pub const RECURSION_AVAILABLE: u16 = 0b0000_0000_1000_0000;
|
||||
pub const AUTHENTICATED_DATA: u16 = 0b0000_0000_0010_0000;
|
||||
pub const CHECKING_DISABLED: u16 = 0b0000_0000_0001_0000;
|
||||
pub const RESERVED_MASK: u16 = 0b0000_0000_0100_0000;
|
||||
pub const RESPONSE_CODE_MASK: u16 = 0b0000_0000_0000_1111;
|
||||
}
|
||||
|
||||
/// Represents parsed header of the packet
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[allow(missing_docs)] // fields are from the spec I think
|
||||
pub struct Header {
|
||||
pub id: u16,
|
||||
pub query: bool,
|
||||
pub opcode: Opcode,
|
||||
pub authoritative: bool,
|
||||
pub truncated: bool,
|
||||
pub recursion_desired: bool,
|
||||
pub recursion_available: bool,
|
||||
pub authenticated_data: bool,
|
||||
pub checking_disabled: bool,
|
||||
pub response_code: ResponseCode,
|
||||
pub questions: u16,
|
||||
pub answers: u16,
|
||||
pub nameservers: u16,
|
||||
pub additional: u16,
|
||||
}
|
||||
|
||||
impl Header {
|
||||
/// Parse the header into a header structure
|
||||
pub fn parse(data: &[u8]) -> Result<Header, Error> {
|
||||
if data.len() < 12 {
|
||||
return Err(Error::HeaderTooShort);
|
||||
}
|
||||
let flags = BigEndian::read_u16(&data[2..4]);
|
||||
if flags & flag::RESERVED_MASK != 0 {
|
||||
return Err(Error::ReservedBitsAreNonZero);
|
||||
}
|
||||
let header = Header {
|
||||
id: BigEndian::read_u16(&data[..2]),
|
||||
query: flags & flag::QUERY == 0,
|
||||
opcode: ((flags & flag::OPCODE_MASK)
|
||||
>> flag::OPCODE_MASK.trailing_zeros()).into(),
|
||||
authoritative: flags & flag::AUTHORITATIVE != 0,
|
||||
truncated: flags & flag::TRUNCATED != 0,
|
||||
recursion_desired: flags & flag::RECURSION_DESIRED != 0,
|
||||
recursion_available: flags & flag::RECURSION_AVAILABLE != 0,
|
||||
authenticated_data: flags & flag::AUTHENTICATED_DATA != 0,
|
||||
checking_disabled: flags & flag::CHECKING_DISABLED != 0,
|
||||
response_code: From::from((flags&flag::RESPONSE_CODE_MASK) as u8),
|
||||
questions: BigEndian::read_u16(&data[4..6]),
|
||||
answers: BigEndian::read_u16(&data[6..8]),
|
||||
nameservers: BigEndian::read_u16(&data[8..10]),
|
||||
additional: BigEndian::read_u16(&data[10..12]),
|
||||
};
|
||||
Ok(header)
|
||||
}
|
||||
/// Write a header to a buffer slice
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When buffer size is not exactly 12 bytes
|
||||
pub fn write(&self, data: &mut [u8]) {
|
||||
if data.len() != 12 {
|
||||
panic!("Header size is exactly 12 bytes");
|
||||
}
|
||||
let mut flags = 0u16;
|
||||
flags |= Into::<u16>::into(self.opcode)
|
||||
<< flag::OPCODE_MASK.trailing_zeros();
|
||||
flags |= Into::<u8>::into(self.response_code) as u16;
|
||||
if !self.query { flags |= flag::QUERY; }
|
||||
if self.authoritative { flags |= flag::AUTHORITATIVE; }
|
||||
if self.recursion_desired { flags |= flag::RECURSION_DESIRED; }
|
||||
if self.recursion_available { flags |= flag::RECURSION_AVAILABLE; }
|
||||
if self.truncated { flags |= flag::TRUNCATED; }
|
||||
BigEndian::write_u16(&mut data[..2], self.id);
|
||||
BigEndian::write_u16(&mut data[2..4], flags);
|
||||
BigEndian::write_u16(&mut data[4..6], self.questions);
|
||||
BigEndian::write_u16(&mut data[6..8], self.answers);
|
||||
BigEndian::write_u16(&mut data[8..10], self.nameservers);
|
||||
BigEndian::write_u16(&mut data[10..12], self.additional);
|
||||
}
|
||||
/// Set "truncated flag" in the raw data
|
||||
// shouldn't this method be non-public?
|
||||
pub fn set_truncated(data: &mut [u8]) {
|
||||
let oldflags = BigEndian::read_u16(&data[2..4]);
|
||||
BigEndian::write_u16(&mut data[2..4], oldflags & flag::TRUNCATED);
|
||||
}
|
||||
/// Returns a size of the header (always 12 bytes)
|
||||
pub fn size() -> usize { 12 }
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use {Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
|
||||
#[test]
|
||||
fn parse_example_query() {
|
||||
let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x00\x01";
|
||||
let header = Header::parse(query).unwrap();
|
||||
assert_eq!(header, Header {
|
||||
id: 1573,
|
||||
query: true,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: false,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 0,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_example_response() {
|
||||
let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x00\x01\
|
||||
\xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
|
||||
\x00\x04]\xb8\xd8\"";
|
||||
let header = Header::parse(response).unwrap();
|
||||
assert_eq!(header, Header {
|
||||
id: 1573,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 1,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_query_with_ad_set() {
|
||||
let query = b"\x06%\x01\x20\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x00\x01";
|
||||
let header = Header::parse(query).unwrap();
|
||||
assert_eq!(header, Header {
|
||||
id: 1573,
|
||||
query: true,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: false,
|
||||
authenticated_data: true,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 0,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_query_with_cd_set() {
|
||||
let query = b"\x06%\x01\x10\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x00\x01";
|
||||
let header = Header::parse(query).unwrap();
|
||||
assert_eq!(header, Header {
|
||||
id: 1573,
|
||||
query: true,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: false,
|
||||
authenticated_data: false,
|
||||
checking_disabled: true,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 0,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
}
|
||||
}
|
39
third_party/rust/dns-parser/src/lib.rs
vendored
Normal file
39
third_party/rust/dns-parser/src/lib.rs
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
#![recursion_limit="100"]
|
||||
//! The network-agnostic DNS parser library
|
||||
//!
|
||||
//! [Documentation](https://docs.rs/dns-parser) |
|
||||
//! [Github](https://github.com/tailhook/dns-parser) |
|
||||
//! [Crate](https://crates.io/crates/dns-parser)
|
||||
//!
|
||||
//! Use [`Builder`] to create a new outgoing packet.
|
||||
//!
|
||||
//! Use [`Packet::parse`] to parse a packet into a data structure.
|
||||
//!
|
||||
//! [`Builder`]: struct.Builder.html
|
||||
//! [`Packet::parse`]: struct.Packet.html#method.parse
|
||||
//!
|
||||
#![warn(missing_docs)]
|
||||
#![warn(missing_debug_implementations)]
|
||||
|
||||
extern crate byteorder;
|
||||
#[cfg(test)] #[macro_use] extern crate matches;
|
||||
#[macro_use(quick_error)] extern crate quick_error;
|
||||
#[cfg(feature = "with-serde")] #[macro_use] extern crate serde_derive;
|
||||
|
||||
mod enums;
|
||||
mod structs;
|
||||
mod name;
|
||||
mod parser;
|
||||
mod error;
|
||||
mod header;
|
||||
mod builder;
|
||||
|
||||
pub mod rdata;
|
||||
|
||||
pub use enums::{Type, QueryType, Class, QueryClass, ResponseCode, Opcode};
|
||||
pub use structs::{Question, ResourceRecord, Packet};
|
||||
pub use name::{Name};
|
||||
pub use error::{Error};
|
||||
pub use header::{Header};
|
||||
pub use rdata::{RData};
|
||||
pub use builder::{Builder};
|
183
third_party/rust/dns-parser/src/name.rs
vendored
Normal file
183
third_party/rust/dns-parser/src/name.rs
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use std::str::from_utf8;
|
||||
|
||||
// Deprecated since rustc 1.23
|
||||
#[allow(unused_imports, deprecated)]
|
||||
use std::ascii::AsciiExt;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
use {Error};
|
||||
|
||||
/// The DNS name as stored in the original packet
|
||||
///
|
||||
/// This contains just a reference to a slice that contains the data.
|
||||
/// You may turn this into a string using `.to_string()`
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Name<'a>{
|
||||
labels: &'a [u8],
|
||||
/// This is the original buffer size. The compressed names in original
|
||||
/// are calculated in this buffer
|
||||
original: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Name<'a> {
|
||||
/// Scan the data to get Name object
|
||||
///
|
||||
/// The `data` should be a part of `original` where name should start.
|
||||
/// The `original` is the data starting a the start of a packet, so
|
||||
/// that offsets in compressed name starts from the `original`.
|
||||
pub fn scan(data: &'a[u8], original: &'a[u8]) -> Result<Name<'a>, Error> {
|
||||
let mut parse_data = data;
|
||||
let mut return_pos = None;
|
||||
let mut pos = 0;
|
||||
if parse_data.len() <= pos {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
// By setting the largest_pos to be the original len, a side effect
|
||||
// is that the pos variable can move forwards in the buffer once.
|
||||
let mut largest_pos = original.len();
|
||||
let mut byte = parse_data[pos];
|
||||
while byte != 0 {
|
||||
if parse_data.len() <= pos {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
if byte & 0b1100_0000 == 0b1100_0000 {
|
||||
if parse_data.len() < pos+2 {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
let off = (BigEndian::read_u16(&parse_data[pos..pos+2])
|
||||
& !0b1100_0000_0000_0000) as usize;
|
||||
if off >= original.len() {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
// Set value for return_pos which is the pos in the original
|
||||
// data buffer that should be used to return after validating
|
||||
// the offsetted labels.
|
||||
if let None = return_pos {
|
||||
return_pos = Some(pos);
|
||||
}
|
||||
|
||||
// Check then set largest_pos to ensure we never go backwards
|
||||
// in the buffer.
|
||||
if off >= largest_pos {
|
||||
return Err(Error::BadPointer);
|
||||
}
|
||||
largest_pos = off;
|
||||
pos = 0;
|
||||
parse_data = &original[off..];
|
||||
} else if byte & 0b1100_0000 == 0 {
|
||||
let end = pos + byte as usize + 1;
|
||||
if parse_data.len() < end {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
if !parse_data[pos+1..end].is_ascii() {
|
||||
return Err(Error::LabelIsNotAscii);
|
||||
}
|
||||
pos = end;
|
||||
if parse_data.len() <= pos {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
} else {
|
||||
return Err(Error::UnknownLabelFormat);
|
||||
}
|
||||
byte = parse_data[pos];
|
||||
}
|
||||
if let Some(return_pos) = return_pos {
|
||||
return Ok(Name {labels: &data[..return_pos+2], original: original});
|
||||
} else {
|
||||
return Ok(Name {labels: &data[..pos+1], original: original });
|
||||
}
|
||||
}
|
||||
/// Number of bytes serialized name occupies
|
||||
pub fn byte_len(&self) -> usize {
|
||||
self.labels.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for Name<'a> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let data = self.labels;
|
||||
let original = self.original;
|
||||
let mut pos = 0;
|
||||
loop {
|
||||
let byte = data[pos];
|
||||
if byte == 0 {
|
||||
return Ok(());
|
||||
} else if byte & 0b1100_0000 == 0b1100_0000 {
|
||||
let off = (BigEndian::read_u16(&data[pos..pos+2])
|
||||
& !0b1100_0000_0000_0000) as usize;
|
||||
if pos != 0 {
|
||||
try!(fmt.write_char('.'));
|
||||
}
|
||||
return fmt::Display::fmt(
|
||||
&Name::scan(&original[off..], original).unwrap(), fmt)
|
||||
} else if byte & 0b1100_0000 == 0 {
|
||||
if pos != 0 {
|
||||
try!(fmt.write_char('.'));
|
||||
}
|
||||
let end = pos + byte as usize + 1;
|
||||
try!(fmt.write_str(from_utf8(&data[pos+1..end]).unwrap()));
|
||||
pos = end;
|
||||
continue;
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> fmt::Debug for Name<'a> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_tuple("Name")
|
||||
.field(&format!("{}", self))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use Error;
|
||||
use Name;
|
||||
|
||||
#[test]
|
||||
fn parse_badpointer_same_offset() {
|
||||
// A buffer where an offset points to itself,
|
||||
// which is a bad compression pointer.
|
||||
let same_offset = vec![192, 2, 192, 2];
|
||||
let is_match = matches!(Name::scan(&same_offset, &same_offset),
|
||||
Err(Error::BadPointer));
|
||||
|
||||
assert!(is_match);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_badpointer_forward_offset() {
|
||||
// A buffer where the offsets points back to each other which causes
|
||||
// infinite recursion if never checked, a bad compression pointer.
|
||||
let forwards_offset = vec![192, 2, 192, 4, 192, 2];
|
||||
let is_match = matches!(Name::scan(&forwards_offset, &forwards_offset),
|
||||
Err(Error::BadPointer));
|
||||
|
||||
assert!(is_match);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_names() {
|
||||
// A buffer where an offset points to itself, a bad compression pointer.
|
||||
let buf = b"\x02xx\x00\x02yy\xc0\x00\x02zz\xc0\x04";
|
||||
|
||||
assert_eq!(Name::scan(&buf[..], buf).unwrap().to_string(),
|
||||
"xx");
|
||||
assert_eq!(Name::scan(&buf[..], buf).unwrap().labels,
|
||||
b"\x02xx\x00");
|
||||
assert_eq!(Name::scan(&buf[4..], buf).unwrap().to_string(),
|
||||
"yy.xx");
|
||||
assert_eq!(Name::scan(&buf[4..], buf).unwrap().labels,
|
||||
b"\x02yy\xc0\x00");
|
||||
assert_eq!(Name::scan(&buf[9..], buf).unwrap().to_string(),
|
||||
"zz.yy.xx");
|
||||
assert_eq!(Name::scan(&buf[9..], buf).unwrap().labels,
|
||||
b"\x02zz\xc0\x04");
|
||||
}
|
||||
}
|
455
third_party/rust/dns-parser/src/parser.rs
vendored
Normal file
455
third_party/rust/dns-parser/src/parser.rs
vendored
Normal file
@ -0,0 +1,455 @@
|
||||
use std::i32;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
use {Header, Packet, Error, Question, Name, QueryType, QueryClass};
|
||||
use {Type, Class, ResourceRecord, RData};
|
||||
use rdata::opt::Record as Opt;
|
||||
|
||||
const OPT_RR_START: [u8; 3] = [0, 0, 41];
|
||||
|
||||
impl<'a> Packet<'a> {
|
||||
/// Parse a full DNS Packet and return a structure that has all the
|
||||
/// data borrowed from the passed buffer.
|
||||
pub fn parse(data: &[u8]) -> Result<Packet, Error> {
|
||||
let header = try!(Header::parse(data));
|
||||
let mut offset = Header::size();
|
||||
let mut questions = Vec::with_capacity(header.questions as usize);
|
||||
for _ in 0..header.questions {
|
||||
let name = try!(Name::scan(&data[offset..], data));
|
||||
offset += name.byte_len();
|
||||
if offset + 4 > data.len() {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
let qtype = try!(QueryType::parse(
|
||||
BigEndian::read_u16(&data[offset..offset+2])));
|
||||
offset += 2;
|
||||
|
||||
let (prefer_unicast, qclass) = try!(parse_qclass_code(
|
||||
BigEndian::read_u16(&data[offset..offset+2])));
|
||||
offset += 2;
|
||||
|
||||
questions.push(Question {
|
||||
qname: name,
|
||||
qtype: qtype,
|
||||
prefer_unicast: prefer_unicast,
|
||||
qclass: qclass,
|
||||
});
|
||||
}
|
||||
let mut answers = Vec::with_capacity(header.answers as usize);
|
||||
for _ in 0..header.answers {
|
||||
answers.push(try!(parse_record(data, &mut offset)));
|
||||
}
|
||||
let mut nameservers = Vec::with_capacity(header.nameservers as usize);
|
||||
for _ in 0..header.nameservers {
|
||||
nameservers.push(try!(parse_record(data, &mut offset)));
|
||||
}
|
||||
let mut additional = Vec::with_capacity(header.additional as usize);
|
||||
let mut opt = None;
|
||||
for _ in 0..header.additional {
|
||||
if offset + 3 <= data.len() && data[offset..offset+3] == OPT_RR_START {
|
||||
if opt.is_none() {
|
||||
opt = Some(try!(parse_opt_record(data, &mut offset)));
|
||||
} else {
|
||||
return Err(Error::AdditionalOPT);
|
||||
}
|
||||
} else {
|
||||
additional.push(try!(parse_record(data, &mut offset)));
|
||||
}
|
||||
}
|
||||
Ok(Packet {
|
||||
header: header,
|
||||
questions: questions,
|
||||
answers: answers,
|
||||
nameservers: nameservers,
|
||||
additional: additional,
|
||||
opt: opt,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_qclass_code(value: u16) -> Result<(bool, QueryClass), Error> {
|
||||
let prefer_unicast = value & 0x8000 == 0x8000;
|
||||
let qclass_code = value & 0x7FFF;
|
||||
|
||||
let qclass = try!(QueryClass::parse(qclass_code));
|
||||
Ok((prefer_unicast, qclass))
|
||||
}
|
||||
|
||||
fn parse_class_code(value: u16) -> Result<(bool, Class), Error> {
|
||||
let is_unique = value & 0x8000 == 0x8000;
|
||||
let class_code = value & 0x7FFF;
|
||||
|
||||
let cls = try!(Class::parse(class_code));
|
||||
Ok((is_unique, cls))
|
||||
}
|
||||
|
||||
// Generic function to parse answer, nameservers, and additional records.
|
||||
fn parse_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<ResourceRecord<'a>, Error> {
|
||||
let name = try!(Name::scan(&data[*offset..], data));
|
||||
*offset += name.byte_len();
|
||||
if *offset + 10 > data.len() {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
let typ = try!(Type::parse(
|
||||
BigEndian::read_u16(&data[*offset..*offset+2])));
|
||||
*offset += 2;
|
||||
|
||||
let class_code = BigEndian::read_u16(&data[*offset..*offset+2]);
|
||||
let (multicast_unique, cls) = try!(parse_class_code(class_code));
|
||||
*offset += 2;
|
||||
|
||||
let mut ttl = BigEndian::read_u32(&data[*offset..*offset+4]);
|
||||
if ttl > i32::MAX as u32 {
|
||||
ttl = 0;
|
||||
}
|
||||
*offset += 4;
|
||||
let rdlen = BigEndian::read_u16(&data[*offset..*offset+2]) as usize;
|
||||
*offset += 2;
|
||||
if *offset + rdlen > data.len() {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
let data = try!(RData::parse(typ,
|
||||
&data[*offset..*offset+rdlen], data));
|
||||
*offset += rdlen;
|
||||
Ok(ResourceRecord {
|
||||
name: name,
|
||||
multicast_unique: multicast_unique,
|
||||
cls: cls,
|
||||
ttl: ttl,
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// Function to parse an RFC 6891 OPT Pseudo RR
|
||||
fn parse_opt_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<Opt<'a>, Error> {
|
||||
if *offset + 11 > data.len() {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
*offset += 1;
|
||||
let typ = try!(Type::parse(
|
||||
BigEndian::read_u16(&data[*offset..*offset+2])));
|
||||
if typ != Type::OPT {
|
||||
return Err(Error::InvalidType(typ as u16));
|
||||
}
|
||||
*offset += 2;
|
||||
let udp = BigEndian::read_u16(&data[*offset..*offset+2]);
|
||||
*offset += 2;
|
||||
let extrcode = data[*offset];
|
||||
*offset += 1;
|
||||
let version = data[*offset];
|
||||
*offset += 1;
|
||||
let flags = BigEndian::read_u16(&data[*offset..*offset+2]);
|
||||
*offset += 2;
|
||||
let rdlen = BigEndian::read_u16(&data[*offset..*offset+2]) as usize;
|
||||
*offset += 2;
|
||||
if *offset + rdlen > data.len() {
|
||||
return Err(Error::UnexpectedEOF);
|
||||
}
|
||||
let data = try!(RData::parse(typ,
|
||||
&data[*offset..*offset+rdlen], data));
|
||||
*offset += rdlen;
|
||||
|
||||
Ok(Opt {
|
||||
udp: udp,
|
||||
extrcode: extrcode,
|
||||
version: version,
|
||||
flags: flags,
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use std::net::Ipv4Addr;
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
|
||||
#[test]
|
||||
fn parse_example_query() {
|
||||
let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x00\x01";
|
||||
let packet = Packet::parse(query).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 1573,
|
||||
query: true,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: false,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 0,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
|
||||
assert_eq!(packet.answers.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_example_response() {
|
||||
let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x00\x01\
|
||||
\xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
|
||||
\x00\x04]\xb8\xd8\"";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 1573,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 1,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
|
||||
assert_eq!(packet.answers.len(), 1);
|
||||
assert_eq!(&packet.answers[0].name.to_string()[..], "example.com");
|
||||
assert_eq!(packet.answers[0].multicast_unique, false);
|
||||
assert_eq!(packet.answers[0].cls, C::IN);
|
||||
assert_eq!(packet.answers[0].ttl, 1272);
|
||||
match packet.answers[0].data {
|
||||
RData::A(addr) => {
|
||||
assert_eq!(addr.0, Ipv4Addr::new(93, 184, 216, 34));
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_response_with_multicast_unique() {
|
||||
let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x00\x01\
|
||||
\xc0\x0c\x00\x01\x80\x01\x00\x00\x04\xf8\
|
||||
\x00\x04]\xb8\xd8\"";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
|
||||
assert_eq!(packet.answers.len(), 1);
|
||||
assert_eq!(packet.answers[0].multicast_unique, true);
|
||||
assert_eq!(packet.answers[0].cls, C::IN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_additional_record_response() {
|
||||
let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x01\
|
||||
\x03www\x05skype\x03com\x00\x00\x01\x00\x01\
|
||||
\xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
|
||||
\x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
|
||||
\x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
|
||||
\x72\x03\x6e\x65\x74\x00\
|
||||
\xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
|
||||
\x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
|
||||
\xc0\x42\
|
||||
\x01\x61\xc0\x55\x00\x01\x00\x01\x00\x00\xa3\x1c\
|
||||
\x00\x04\xc0\x05\x06\x1e";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 19184,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 1,
|
||||
nameservers: 1,
|
||||
additional: 1,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
|
||||
assert_eq!(packet.answers.len(), 1);
|
||||
assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
|
||||
assert_eq!(packet.answers[0].cls, C::IN);
|
||||
assert_eq!(packet.answers[0].ttl, 3600);
|
||||
match packet.answers[0].data {
|
||||
RData::CNAME(cname) => {
|
||||
assert_eq!(&cname.0.to_string()[..], "livecms.trafficmanager.net");
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
assert_eq!(packet.nameservers.len(), 1);
|
||||
assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
|
||||
assert_eq!(packet.nameservers[0].cls, C::IN);
|
||||
assert_eq!(packet.nameservers[0].ttl, 120275);
|
||||
match packet.nameservers[0].data {
|
||||
RData::NS(ns) => {
|
||||
assert_eq!(&ns.0.to_string()[..], "g.gtld-servers.net");
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
assert_eq!(packet.additional.len(), 1);
|
||||
assert_eq!(&packet.additional[0].name.to_string()[..], "a.gtld-servers.net");
|
||||
assert_eq!(packet.additional[0].cls, C::IN);
|
||||
assert_eq!(packet.additional[0].ttl, 41756);
|
||||
match packet.additional[0].data {
|
||||
RData::A(addr) => {
|
||||
assert_eq!(addr.0, Ipv4Addr::new(192, 5, 6, 30));
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_multiple_answers() {
|
||||
let response = b"\x9d\xe9\x81\x80\x00\x01\x00\x06\x00\x00\x00\x00\
|
||||
\x06google\x03com\x00\x00\x01\x00\x01\xc0\x0c\
|
||||
\x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\
|
||||
\xa4d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
|
||||
\x00\x04@\xe9\xa4\x8b\xc0\x0c\x00\x01\x00\x01\
|
||||
\x00\x00\x00\xef\x00\x04@\xe9\xa4q\xc0\x0c\x00\
|
||||
\x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\xa4f\
|
||||
\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\
|
||||
\xe9\xa4e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
|
||||
\x00\x04@\xe9\xa4\x8a";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 40425,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 6,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
|
||||
assert_eq!(packet.answers.len(), 6);
|
||||
let ips = vec![
|
||||
Ipv4Addr::new(64, 233, 164, 100),
|
||||
Ipv4Addr::new(64, 233, 164, 139),
|
||||
Ipv4Addr::new(64, 233, 164, 113),
|
||||
Ipv4Addr::new(64, 233, 164, 102),
|
||||
Ipv4Addr::new(64, 233, 164, 101),
|
||||
Ipv4Addr::new(64, 233, 164, 138),
|
||||
];
|
||||
for i in 0..6 {
|
||||
assert_eq!(&packet.answers[i].name.to_string()[..], "google.com");
|
||||
assert_eq!(packet.answers[i].cls, C::IN);
|
||||
assert_eq!(packet.answers[i].ttl, 239);
|
||||
match packet.answers[i].data {
|
||||
RData::A(addr) => {
|
||||
assert_eq!(addr.0, ips[i]);
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_srv_query() {
|
||||
let query = b"[\xd9\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01";
|
||||
let packet = Packet::parse(query).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 23513,
|
||||
query: true,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: false,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 0,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::SRV);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(packet.questions[0].prefer_unicast, false);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..],
|
||||
"_xmpp-server._tcp.gmail.com");
|
||||
assert_eq!(packet.answers.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_multicast_prefer_unicast_query() {
|
||||
let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
|
||||
\x07example\x03com\x00\x00\x01\x80\x01";
|
||||
let packet = Packet::parse(query).unwrap();
|
||||
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(packet.questions[0].prefer_unicast, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_example_query_edns() {
|
||||
let query = b"\x95\xce\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\
|
||||
\x06google\x03com\x00\x00\x01\x00\
|
||||
\x01\x00\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00";
|
||||
let packet = Packet::parse(query).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 38350,
|
||||
query: true,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: false,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 0,
|
||||
nameservers: 0,
|
||||
additional: 1,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
|
||||
assert_eq!(packet.answers.len(), 0);
|
||||
match packet.opt {
|
||||
Some(opt) => {
|
||||
assert_eq!(opt.udp, 4096);
|
||||
assert_eq!(opt.extrcode, 0);
|
||||
assert_eq!(opt.version, 0);
|
||||
assert_eq!(opt.flags, 0);
|
||||
},
|
||||
None => panic!("Missing OPT RR")
|
||||
}
|
||||
}
|
||||
}
|
21
third_party/rust/dns-parser/src/rdata/a.rs
vendored
Normal file
21
third_party/rust/dns-parser/src/rdata/a.rs
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use Error;
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record(pub Ipv4Addr);
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 1;
|
||||
|
||||
fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
if rdata.len() != 4 {
|
||||
return Err(Error::WrongRdataLength);
|
||||
}
|
||||
let address = Ipv4Addr::from(BigEndian::read_u32(rdata));
|
||||
let record = Record(address);
|
||||
Ok(super::RData::A(record))
|
||||
}
|
||||
}
|
85
third_party/rust/dns-parser/src/rdata/aaaa.rs
vendored
Normal file
85
third_party/rust/dns-parser/src/rdata/aaaa.rs
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
use std::net::Ipv6Addr;
|
||||
|
||||
use Error;
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record(pub Ipv6Addr);
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 28;
|
||||
|
||||
fn parse(rdata: &'a [u8], _record: &'a [u8]) -> super::RDataResult<'a> {
|
||||
if rdata.len() != 16 {
|
||||
return Err(Error::WrongRdataLength);
|
||||
}
|
||||
let address = Ipv6Addr::new(
|
||||
BigEndian::read_u16(&rdata[0..2]),
|
||||
BigEndian::read_u16(&rdata[2..4]),
|
||||
BigEndian::read_u16(&rdata[4..6]),
|
||||
BigEndian::read_u16(&rdata[6..8]),
|
||||
BigEndian::read_u16(&rdata[8..10]),
|
||||
BigEndian::read_u16(&rdata[10..12]),
|
||||
BigEndian::read_u16(&rdata[12..14]),
|
||||
BigEndian::read_u16(&rdata[14..16]),
|
||||
);
|
||||
let record = Record(address);
|
||||
Ok(super::RData::AAAA(record))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_response() {
|
||||
let response = b"\xa9\xd9\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06\
|
||||
google\x03com\x00\x00\x1c\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\
|
||||
\x00\x8b\x00\x10*\x00\x14P@\t\x08\x12\x00\x00\x00\x00\x00\x00 \x0e";
|
||||
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 43481,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 1,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::AAAA);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
|
||||
assert_eq!(packet.answers.len(), 1);
|
||||
assert_eq!(&packet.answers[0].name.to_string()[..], "google.com");
|
||||
assert_eq!(packet.answers[0].cls, C::IN);
|
||||
assert_eq!(packet.answers[0].ttl, 139);
|
||||
match packet.answers[0].data {
|
||||
RData::AAAA(addr) => {
|
||||
assert_eq!(addr.0, Ipv6Addr::new(
|
||||
0x2A00, 0x1450, 0x4009, 0x812, 0, 0, 0, 0x200e)
|
||||
);
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/all.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/all.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 255;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/axfr.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/axfr.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 252;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
102
third_party/rust/dns-parser/src/rdata/cname.rs
vendored
Normal file
102
third_party/rust/dns-parser/src/rdata/cname.rs
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
use Name;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Record<'a>(pub Name<'a>);
|
||||
|
||||
impl<'a> ToString for Record<'a> {
|
||||
#[inline]
|
||||
fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> super::Record<'a> for Record<'a> {
|
||||
|
||||
const TYPE: isize = 5;
|
||||
|
||||
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
let name = Name::scan(rdata, original)?;
|
||||
let record = Record(name);
|
||||
Ok(super::RData::CNAME(record))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use std::net::Ipv4Addr;
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
|
||||
#[test]
|
||||
fn parse_response() {
|
||||
let response = b"\xfc\x9d\x81\x80\x00\x01\x00\x06\x00\x02\x00\x02\x03\
|
||||
cdn\x07sstatic\x03net\x00\x00\x01\x00\x01\xc0\x0c\x00\x05\x00\x01\
|
||||
\x00\x00\x00f\x00\x02\xc0\x10\xc0\x10\x00\x01\x00\x01\x00\x00\x00\
|
||||
f\x00\x04h\x10g\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\
|
||||
\x10k\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10h\xcc\
|
||||
\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10j\xcc\xc0\x10\
|
||||
\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10i\xcc\xc0\x10\x00\x02\
|
||||
\x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns02\xc0\x10\xc0\x10\x00\x02\
|
||||
\x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns01\xc0\x10\xc0\xa2\x00\x01\
|
||||
\x00\x01\x00\x00\x99L\x00\x04\xad\xf5:5\xc0\x8b\x00\x01\x00\x01\x00\
|
||||
\x00\x99L\x00\x04\xad\xf5;\x04";
|
||||
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 64669,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 6,
|
||||
nameservers: 2,
|
||||
additional: 2,
|
||||
});
|
||||
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "cdn.sstatic.net");
|
||||
assert_eq!(packet.answers.len(), 6);
|
||||
assert_eq!(&packet.answers[0].name.to_string()[..], "cdn.sstatic.net");
|
||||
assert_eq!(packet.answers[0].cls, C::IN);
|
||||
assert_eq!(packet.answers[0].ttl, 102);
|
||||
match packet.answers[0].data {
|
||||
RData::CNAME(cname) => {
|
||||
assert_eq!(&cname.0.to_string(), "sstatic.net");
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
|
||||
let ips = vec![
|
||||
Ipv4Addr::new(104, 16, 103, 204),
|
||||
Ipv4Addr::new(104, 16, 107, 204),
|
||||
Ipv4Addr::new(104, 16, 104, 204),
|
||||
Ipv4Addr::new(104, 16, 106, 204),
|
||||
Ipv4Addr::new(104, 16, 105, 204),
|
||||
];
|
||||
for i in 1..6 {
|
||||
assert_eq!(&packet.answers[i].name.to_string()[..], "sstatic.net");
|
||||
assert_eq!(packet.answers[i].cls, C::IN);
|
||||
assert_eq!(packet.answers[i].ttl, 102);
|
||||
match packet.answers[i].data {
|
||||
RData::A(addr) => {
|
||||
assert_eq!(addr.0, ips[i-1]);
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/hinfo.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/hinfo.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 13;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/maila.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/maila.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 254;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/mailb.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/mailb.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 253;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/mb.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/mb.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 7;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/mf.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/mf.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 4;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/mg.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/mg.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 8;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/minfo.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/minfo.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 14;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
83
third_party/rust/dns-parser/src/rdata/mod.rs
vendored
Normal file
83
third_party/rust/dns-parser/src/rdata/mod.rs
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
//! Data types and methods for handling the RData field
|
||||
|
||||
#![allow(missing_docs)] // resource records are pretty self-descriptive
|
||||
|
||||
pub mod a;
|
||||
pub mod aaaa;
|
||||
pub mod all;
|
||||
pub mod axfr;
|
||||
pub mod cname;
|
||||
pub mod hinfo;
|
||||
pub mod maila;
|
||||
pub mod mailb;
|
||||
pub mod mb;
|
||||
pub mod mf;
|
||||
pub mod mg;
|
||||
pub mod minfo;
|
||||
pub mod mr;
|
||||
pub mod mx;
|
||||
pub mod ns;
|
||||
pub mod nsec;
|
||||
pub mod null;
|
||||
pub mod opt;
|
||||
pub mod ptr;
|
||||
pub mod soa;
|
||||
pub mod srv;
|
||||
pub mod txt;
|
||||
pub mod wks;
|
||||
|
||||
use {Type, Error};
|
||||
|
||||
pub use self::a::Record as A;
|
||||
pub use self::aaaa::Record as Aaaa;
|
||||
pub use self::cname::Record as Cname;
|
||||
pub use self::mx::Record as Mx;
|
||||
pub use self::ns::Record as Ns;
|
||||
pub use self::nsec::Record as Nsec;
|
||||
pub use self::opt::Record as Opt;
|
||||
pub use self::ptr::Record as Ptr;
|
||||
pub use self::soa::Record as Soa;
|
||||
pub use self::srv::Record as Srv;
|
||||
pub use self::txt::Record as Txt;
|
||||
|
||||
pub type RDataResult<'a> = Result<RData<'a>, Error>;
|
||||
|
||||
/// The enumeration that represents known types of DNS resource records data
|
||||
#[derive(Debug)]
|
||||
pub enum RData<'a> {
|
||||
A(A),
|
||||
AAAA(Aaaa),
|
||||
CNAME(Cname<'a>),
|
||||
MX(Mx<'a>),
|
||||
NS(Ns<'a>),
|
||||
PTR(Ptr<'a>),
|
||||
SOA(Soa<'a>),
|
||||
SRV(Srv<'a>),
|
||||
TXT(Txt<'a>),
|
||||
/// Anything that can't be parsed yet
|
||||
Unknown(&'a [u8]),
|
||||
}
|
||||
|
||||
pub (crate) trait Record<'a> {
|
||||
const TYPE: isize;
|
||||
|
||||
fn parse(rdata: &'a [u8], original: &'a [u8]) -> RDataResult<'a>;
|
||||
}
|
||||
|
||||
impl<'a> RData<'a> {
|
||||
/// Parse an RR data and return RData enumeration
|
||||
pub fn parse(typ: Type, rdata: &'a [u8], original: &'a [u8]) -> RDataResult<'a> {
|
||||
match typ {
|
||||
Type::A => A::parse(rdata, original),
|
||||
Type::AAAA => Aaaa::parse(rdata, original),
|
||||
Type::CNAME => Cname::parse(rdata, original),
|
||||
Type::NS => Ns::parse(rdata, original),
|
||||
Type::MX => Mx::parse(rdata, original),
|
||||
Type::PTR => Ptr::parse(rdata, original),
|
||||
Type::SOA => Soa::parse(rdata, original),
|
||||
Type::SRV => Srv::parse(rdata, original),
|
||||
Type::TXT => Txt::parse(rdata, original),
|
||||
_ => Ok(RData::Unknown(rdata)),
|
||||
}
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/mr.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/mr.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 9;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
92
third_party/rust/dns-parser/src/rdata/mx.rs
vendored
Normal file
92
third_party/rust/dns-parser/src/rdata/mx.rs
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
use {Name, Error};
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Record<'a> {
|
||||
pub preference: u16,
|
||||
pub exchange: Name<'a>,
|
||||
}
|
||||
|
||||
impl<'a> super::Record<'a> for Record<'a> {
|
||||
|
||||
const TYPE: isize = 15;
|
||||
|
||||
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
if rdata.len() < 3 {
|
||||
return Err(Error::WrongRdataLength);
|
||||
}
|
||||
let record = Record {
|
||||
preference: BigEndian::read_u16(&rdata[..2]),
|
||||
exchange: Name::scan(&rdata[2..], original)?,
|
||||
};
|
||||
Ok(super::RData::MX(record))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_response() {
|
||||
let response = b"\xe3\xe8\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
|
||||
\x05gmail\x03com\x00\x00\x0f\x00\x01\xc0\x0c\x00\x0f\x00\x01\
|
||||
\x00\x00\x04|\x00\x1b\x00\x05\rgmail-smtp-in\x01l\x06google\xc0\
|
||||
\x12\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\x00\t\x00\
|
||||
\n\x04alt1\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\
|
||||
\x00\t\x00(\x04alt4\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\
|
||||
\x00\x04|\x00\t\x00\x14\x04alt2\xc0)\xc0\x0c\x00\x0f\
|
||||
\x00\x01\x00\x00\x04|\x00\t\x00\x1e\x04alt3\xc0)";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 58344,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 5,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::MX);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..],
|
||||
"gmail.com");
|
||||
assert_eq!(packet.answers.len(), 5);
|
||||
let items = vec![
|
||||
( 5, "gmail-smtp-in.l.google.com"),
|
||||
(10, "alt1.gmail-smtp-in.l.google.com"),
|
||||
(40, "alt4.gmail-smtp-in.l.google.com"),
|
||||
(20, "alt2.gmail-smtp-in.l.google.com"),
|
||||
(30, "alt3.gmail-smtp-in.l.google.com"),
|
||||
];
|
||||
for i in 0..5 {
|
||||
assert_eq!(&packet.answers[i].name.to_string()[..],
|
||||
"gmail.com");
|
||||
assert_eq!(packet.answers[i].cls, C::IN);
|
||||
assert_eq!(packet.answers[i].ttl, 1148);
|
||||
match *&packet.answers[i].data {
|
||||
RData::MX( Record { preference, exchange }) => {
|
||||
assert_eq!(preference, items[i].0);
|
||||
assert_eq!(exchange.to_string(), (items[i].1).to_string());
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
88
third_party/rust/dns-parser/src/rdata/ns.rs
vendored
Normal file
88
third_party/rust/dns-parser/src/rdata/ns.rs
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
use Name;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Record<'a>(pub Name<'a>);
|
||||
|
||||
impl<'a> ToString for Record<'a> {
|
||||
#[inline]
|
||||
fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> super::Record<'a> for Record<'a> {
|
||||
|
||||
const TYPE: isize = 2;
|
||||
|
||||
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
let name = Name::scan(rdata, original)?;
|
||||
let record = Record(name);
|
||||
Ok(super::RData::NS(record))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
|
||||
#[test]
|
||||
fn parse_response() {
|
||||
let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x00\
|
||||
\x03www\x05skype\x03com\x00\x00\x01\x00\x01\
|
||||
\xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
|
||||
\x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
|
||||
\x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
|
||||
\x72\x03\x6e\x65\x74\x00\
|
||||
\xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
|
||||
\x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
|
||||
\xc0\x42";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 19184,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 1,
|
||||
nameservers: 1,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
|
||||
assert_eq!(packet.answers.len(), 1);
|
||||
assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
|
||||
assert_eq!(packet.answers[0].cls, C::IN);
|
||||
assert_eq!(packet.answers[0].ttl, 3600);
|
||||
match packet.answers[0].data {
|
||||
RData::CNAME(cname) => {
|
||||
assert_eq!(&cname.0.to_string()[..], "livecms.trafficmanager.net");
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
assert_eq!(packet.nameservers.len(), 1);
|
||||
assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
|
||||
assert_eq!(packet.nameservers[0].cls, C::IN);
|
||||
assert_eq!(packet.nameservers[0].ttl, 120275);
|
||||
match packet.nameservers[0].data {
|
||||
RData::NS(ns) => {
|
||||
assert_eq!(&ns.0.to_string()[..], "g.gtld-servers.net");
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/nsec.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/nsec.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 47;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/null.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/null.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 10;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
18
third_party/rust/dns-parser/src/rdata/opt.rs
vendored
Normal file
18
third_party/rust/dns-parser/src/rdata/opt.rs
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/// RFC 6891 OPT RR
|
||||
#[derive(Debug)]
|
||||
pub struct Record<'a> {
|
||||
pub udp: u16,
|
||||
pub extrcode: u8,
|
||||
pub version: u8,
|
||||
pub flags: u16,
|
||||
pub data: super::RData<'a>,
|
||||
}
|
||||
|
||||
impl<'a> super::Record<'a> for Record<'a> {
|
||||
|
||||
const TYPE: isize = 41;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
74
third_party/rust/dns-parser/src/rdata/ptr.rs
vendored
Normal file
74
third_party/rust/dns-parser/src/rdata/ptr.rs
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
use Name;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Record<'a>(pub Name<'a>);
|
||||
|
||||
impl<'a> ToString for Record<'a> {
|
||||
#[inline]
|
||||
fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> super::Record<'a> for Record<'a> {
|
||||
|
||||
const TYPE: isize = 12;
|
||||
|
||||
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
let name = Name::scan(rdata, original)?;
|
||||
let record = Record(name);
|
||||
Ok(super::RData::PTR(record))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
|
||||
#[test]
|
||||
fn parse_response() {
|
||||
let response = b"\x53\xd6\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
|
||||
\x0269\x0293\x0275\x0272\x07in-addr\x04arpa\x00\
|
||||
\x00\x0c\x00\x01\
|
||||
\xc0\x0c\x00\x0c\x00\x01\x00\x01\x51\x80\x00\x1e\
|
||||
\x10pool-72-75-93-69\x07verizon\x03net\x00";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 21462,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 1,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::PTR);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "69.93.75.72.in-addr.arpa");
|
||||
assert_eq!(packet.answers.len(), 1);
|
||||
assert_eq!(&packet.answers[0].name.to_string()[..], "69.93.75.72.in-addr.arpa");
|
||||
assert_eq!(packet.answers[0].cls, C::IN);
|
||||
assert_eq!(packet.answers[0].ttl, 86400);
|
||||
match packet.answers[0].data {
|
||||
RData::PTR(name) => {
|
||||
assert_eq!(&name.0.to_string()[..], "pool-72-75-93-69.verizon.net");
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
101
third_party/rust/dns-parser/src/rdata/soa.rs
vendored
Normal file
101
third_party/rust/dns-parser/src/rdata/soa.rs
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
use {Name, Error};
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
/// The SOA (Start of Authority) record
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Record<'a> {
|
||||
pub primary_ns: Name<'a>,
|
||||
pub mailbox: Name<'a>,
|
||||
pub serial: u32,
|
||||
pub refresh: u32,
|
||||
pub retry: u32,
|
||||
pub expire: u32,
|
||||
pub minimum_ttl: u32,
|
||||
}
|
||||
|
||||
impl<'a> super::Record<'a> for Record<'a> {
|
||||
|
||||
const TYPE: isize = 6;
|
||||
|
||||
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
let mut pos = 0;
|
||||
let primary_name_server = try!(Name::scan(rdata, original));
|
||||
pos += primary_name_server.byte_len();
|
||||
let mailbox = try!(Name::scan(&rdata[pos..], original));
|
||||
pos += mailbox.byte_len();
|
||||
if rdata[pos..].len() < 20 {
|
||||
return Err(Error::WrongRdataLength);
|
||||
}
|
||||
let record = Record {
|
||||
primary_ns: primary_name_server,
|
||||
mailbox: mailbox,
|
||||
serial: BigEndian::read_u32(&rdata[pos..(pos+4)]),
|
||||
refresh: BigEndian::read_u32(&rdata[(pos+4)..(pos+8)]),
|
||||
retry: BigEndian::read_u32(&rdata[(pos+8)..(pos+12)]),
|
||||
expire: BigEndian::read_u32(&rdata[(pos+12)..(pos+16)]),
|
||||
minimum_ttl: BigEndian::read_u32(&rdata[(pos+16)..(pos+20)]),
|
||||
};
|
||||
Ok(super::RData::SOA(record))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NameError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
|
||||
#[test]
|
||||
fn parse_response() {
|
||||
let response = b"\x9f\xc5\x85\x83\x00\x01\x00\x00\x00\x01\x00\x00\
|
||||
\x0edlkfjkdjdslfkj\x07youtube\x03com\x00\x00\x01\x00\x01\
|
||||
\xc0\x1b\x00\x06\x00\x01\x00\x00\x2a\x30\x00\x1e\xc0\x1b\
|
||||
\x05admin\xc0\x1b\x77\xed\x2a\x73\x00\x00\x51\x80\x00\x00\
|
||||
\x0e\x10\x00\x00\x3a\x80\x00\x00\x2a\x30";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 40901,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: true,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NameError,
|
||||
questions: 1,
|
||||
answers: 0,
|
||||
nameservers: 1,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::A);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "dlkfjkdjdslfkj.youtube.com");
|
||||
assert_eq!(packet.answers.len(), 0);
|
||||
|
||||
assert_eq!(packet.nameservers.len(), 1);
|
||||
assert_eq!(&packet.nameservers[0].name.to_string()[..], "youtube.com");
|
||||
assert_eq!(packet.nameservers[0].cls, C::IN);
|
||||
assert_eq!(packet.nameservers[0].multicast_unique, false);
|
||||
assert_eq!(packet.nameservers[0].ttl, 10800);
|
||||
match packet.nameservers[0].data {
|
||||
RData::SOA(ref soa_rec) => {
|
||||
assert_eq!(&soa_rec.primary_ns.to_string()[..], "youtube.com");
|
||||
assert_eq!(&soa_rec.mailbox.to_string()[..], "admin.youtube.com");
|
||||
assert_eq!(soa_rec.serial, 2012031603);
|
||||
assert_eq!(soa_rec.refresh, 20864);
|
||||
assert_eq!(soa_rec.retry, 3600);
|
||||
assert_eq!(soa_rec.expire, 14976);
|
||||
assert_eq!(soa_rec.minimum_ttl, 10800);
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
102
third_party/rust/dns-parser/src/rdata/srv.rs
vendored
Normal file
102
third_party/rust/dns-parser/src/rdata/srv.rs
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
use {Name, Error};
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Record<'a> {
|
||||
pub priority: u16,
|
||||
pub weight: u16,
|
||||
pub port: u16,
|
||||
pub target: Name<'a>,
|
||||
}
|
||||
|
||||
impl<'a> super::Record<'a> for Record<'a> {
|
||||
|
||||
const TYPE: isize = 33;
|
||||
|
||||
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
if rdata.len() < 7 {
|
||||
return Err(Error::WrongRdataLength);
|
||||
}
|
||||
let record = Record {
|
||||
priority: BigEndian::read_u16(&rdata[..2]),
|
||||
weight: BigEndian::read_u16(&rdata[2..4]),
|
||||
port: BigEndian::read_u16(&rdata[4..6]),
|
||||
target: Name::scan(&rdata[6..], original)?,
|
||||
};
|
||||
Ok(super::RData::SRV(record))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_response() {
|
||||
let response = b"[\xd9\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
|
||||
\x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01\
|
||||
\xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00 \x00\x05\x00\x00\
|
||||
\x14\x95\x0bxmpp-server\x01l\x06google\x03com\x00\xc0\x0c\x00!\
|
||||
\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\x14\x95\
|
||||
\x04alt3\x0bxmpp-server\x01l\x06google\x03com\x00\
|
||||
\xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
|
||||
\x14\x95\x04alt1\x0bxmpp-server\x01l\x06google\x03com\x00\
|
||||
\xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
|
||||
\x14\x95\x04alt2\x0bxmpp-server\x01l\x06google\x03com\x00\
|
||||
\xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
|
||||
\x14\x95\x04alt4\x0bxmpp-server\x01l\x06google\x03com\x00";
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 23513,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 5,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::SRV);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..],
|
||||
"_xmpp-server._tcp.gmail.com");
|
||||
assert_eq!(packet.answers.len(), 5);
|
||||
let items = vec![
|
||||
(5, 0, 5269, "xmpp-server.l.google.com"),
|
||||
(20, 0, 5269, "alt3.xmpp-server.l.google.com"),
|
||||
(20, 0, 5269, "alt1.xmpp-server.l.google.com"),
|
||||
(20, 0, 5269, "alt2.xmpp-server.l.google.com"),
|
||||
(20, 0, 5269, "alt4.xmpp-server.l.google.com"),
|
||||
];
|
||||
for i in 0..5 {
|
||||
assert_eq!(&packet.answers[i].name.to_string()[..],
|
||||
"_xmpp-server._tcp.gmail.com");
|
||||
assert_eq!(packet.answers[i].cls, C::IN);
|
||||
assert_eq!(packet.answers[i].ttl, 900);
|
||||
match *&packet.answers[i].data {
|
||||
RData::SRV(Record { priority, weight, port, target }) => {
|
||||
assert_eq!(priority, items[i].0);
|
||||
assert_eq!(weight, items[i].1);
|
||||
assert_eq!(port, items[i].2);
|
||||
assert_eq!(target.to_string(), (items[i].3).to_string());
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
125
third_party/rust/dns-parser/src/rdata/txt.rs
vendored
Normal file
125
third_party/rust/dns-parser/src/rdata/txt.rs
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
use Error;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Record<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RecordIter<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Iterator for RecordIter<'a> {
|
||||
type Item = &'a [u8];
|
||||
fn next(&mut self) -> Option<&'a [u8]> {
|
||||
if self.bytes.len() >= 1 {
|
||||
let len = self.bytes[0] as usize;
|
||||
debug_assert!(self.bytes.len() >= len+1);
|
||||
let (head, tail) = self.bytes[1..].split_at(len);
|
||||
self.bytes = tail;
|
||||
return Some(head);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Record<'a> {
|
||||
|
||||
// Returns iterator over text chunks
|
||||
pub fn iter(&self) -> RecordIter<'a> {
|
||||
RecordIter {
|
||||
bytes: self.bytes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> super::Record<'a> for Record<'a> {
|
||||
|
||||
const TYPE: isize = 16;
|
||||
|
||||
fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
// Just a quick check that record is valid
|
||||
let len = rdata.len();
|
||||
if len < 1 {
|
||||
return Err(Error::WrongRdataLength);
|
||||
}
|
||||
let mut pos = 0;
|
||||
while pos < len {
|
||||
let rdlen = rdata[pos] as usize;
|
||||
pos += 1;
|
||||
if len < rdlen + pos {
|
||||
return Err(Error::WrongRdataLength);
|
||||
}
|
||||
pos += rdlen;
|
||||
}
|
||||
Ok(super::RData::TXT(Record {
|
||||
bytes: rdata,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use std::str::from_utf8;
|
||||
|
||||
use {Packet, Header};
|
||||
use Opcode::*;
|
||||
use ResponseCode::NoError;
|
||||
use QueryType as QT;
|
||||
use QueryClass as QC;
|
||||
use Class as C;
|
||||
use RData;
|
||||
|
||||
#[test]
|
||||
fn parse_response_multiple_strings() {
|
||||
let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
|
||||
\x08facebook\x03com\x00\x00\x10\x00\x01\
|
||||
\xc0\x0c\x00\x10\x00\x01\x00\x01\x51\x3d\x00\x23\
|
||||
\x15\x76\x3d\x73\x70\x66\x31\x20\x72\x65\x64\x69\
|
||||
\x72\x65\x63\x74\x3d\x5f\x73\x70\x66\x2e\
|
||||
\x0c\x66\x61\x63\x65\x62\x6f\x6f\x6b\x2e\x63\x6f\x6d";
|
||||
|
||||
let packet = Packet::parse(response).unwrap();
|
||||
assert_eq!(packet.header, Header {
|
||||
id: 1573,
|
||||
query: false,
|
||||
opcode: StandardQuery,
|
||||
authoritative: false,
|
||||
truncated: false,
|
||||
recursion_desired: true,
|
||||
recursion_available: true,
|
||||
authenticated_data: false,
|
||||
checking_disabled: false,
|
||||
response_code: NoError,
|
||||
questions: 1,
|
||||
answers: 1,
|
||||
nameservers: 0,
|
||||
additional: 0,
|
||||
});
|
||||
assert_eq!(packet.questions.len(), 1);
|
||||
assert_eq!(packet.questions[0].qtype, QT::TXT);
|
||||
assert_eq!(packet.questions[0].qclass, QC::IN);
|
||||
assert_eq!(&packet.questions[0].qname.to_string()[..], "facebook.com");
|
||||
assert_eq!(packet.answers.len(), 1);
|
||||
assert_eq!(&packet.answers[0].name.to_string()[..], "facebook.com");
|
||||
assert_eq!(packet.answers[0].multicast_unique, false);
|
||||
assert_eq!(packet.answers[0].cls, C::IN);
|
||||
assert_eq!(packet.answers[0].ttl, 86333);
|
||||
match packet.answers[0].data {
|
||||
RData::TXT(ref text) => {
|
||||
assert_eq!(text.iter()
|
||||
.map(|x| from_utf8(x).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
.concat(), "v=spf1 redirect=_spf.facebook.com");
|
||||
|
||||
// also assert boundaries are kept
|
||||
assert_eq!(text.iter().collect::<Vec<_>>(),
|
||||
["v=spf1 redirect=_spf.".as_bytes(),
|
||||
"facebook.com".as_bytes()]);
|
||||
}
|
||||
ref x => panic!("Wrong rdata {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
11
third_party/rust/dns-parser/src/rdata/wks.rs
vendored
Normal file
11
third_party/rust/dns-parser/src/rdata/wks.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Record;
|
||||
|
||||
impl<'a> super::Record<'a> for Record {
|
||||
|
||||
const TYPE: isize = 11;
|
||||
|
||||
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
50
third_party/rust/dns-parser/src/structs.rs
vendored
Normal file
50
third_party/rust/dns-parser/src/structs.rs
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
use {QueryType, QueryClass, Name, Class, Header, RData};
|
||||
use rdata::opt;
|
||||
|
||||
|
||||
/// Parsed DNS packet
|
||||
#[derive(Debug)]
|
||||
#[allow(missing_docs)] // should be covered by spec
|
||||
pub struct Packet<'a> {
|
||||
pub header: Header,
|
||||
pub questions: Vec<Question<'a>>,
|
||||
pub answers: Vec<ResourceRecord<'a>>,
|
||||
pub nameservers: Vec<ResourceRecord<'a>>,
|
||||
pub additional: Vec<ResourceRecord<'a>>,
|
||||
/// Optional Pseudo-RR
|
||||
/// When present it is sent as an RR in the additional section. In this RR
|
||||
/// the `class` and `ttl` fields store max udp packet size and flags
|
||||
/// respectively. To keep `ResourceRecord` clean we store the OPT record
|
||||
/// here.
|
||||
pub opt: Option<opt::Record<'a>>,
|
||||
}
|
||||
|
||||
/// A parsed chunk of data in the Query section of the packet
|
||||
#[derive(Debug)]
|
||||
#[allow(missing_docs)] // should be covered by spec
|
||||
pub struct Question<'a> {
|
||||
pub qname: Name<'a>,
|
||||
/// Whether or not we prefer unicast responses.
|
||||
/// This is used in multicast DNS.
|
||||
pub prefer_unicast: bool,
|
||||
pub qtype: QueryType,
|
||||
pub qclass: QueryClass,
|
||||
}
|
||||
|
||||
/// A single DNS record
|
||||
///
|
||||
/// We aim to provide whole range of DNS records available. But as time is
|
||||
/// limited we have some types of packets which are parsed and other provided
|
||||
/// as unparsed slice of bytes.
|
||||
#[derive(Debug)]
|
||||
#[allow(missing_docs)] // should be covered by spec
|
||||
pub struct ResourceRecord<'a> {
|
||||
pub name: Name<'a>,
|
||||
/// Whether or not the set of resource records is fully contained in the
|
||||
/// packet, or whether there will be more resource records in future
|
||||
/// packets. Only used for multicast DNS.
|
||||
pub multicast_unique: bool,
|
||||
pub cls: Class,
|
||||
pub ttl: u32,
|
||||
pub data: RData<'a>,
|
||||
}
|
44
third_party/rust/dns-parser/vagga.yaml
vendored
Normal file
44
third_party/rust/dns-parser/vagga.yaml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
commands:
|
||||
|
||||
cargo: !Command
|
||||
description: Run any cargo command
|
||||
container: ubuntu
|
||||
run: [cargo]
|
||||
|
||||
make: !Command
|
||||
description: Build the library
|
||||
container: ubuntu
|
||||
run: [cargo, build]
|
||||
|
||||
test: !Command
|
||||
description: Run the tests
|
||||
container: ubuntu
|
||||
environ:
|
||||
RUST_BACKTRACE: 1
|
||||
run: [cargo, test]
|
||||
|
||||
_bulk: !Command
|
||||
description: Run `bulk` command (for version bookkeeping)
|
||||
container: ubuntu
|
||||
run: [bulk]
|
||||
|
||||
containers:
|
||||
|
||||
ubuntu:
|
||||
setup:
|
||||
- !Ubuntu xenial
|
||||
- !UbuntuUniverse
|
||||
- !Install [ca-certificates, build-essential, vim]
|
||||
|
||||
- !TarInstall
|
||||
url: "https://static.rust-lang.org/dist/rust-1.28.0-x86_64-unknown-linux-gnu.tar.gz"
|
||||
script: "./install.sh --prefix=/usr \
|
||||
--components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo"
|
||||
- &bulk !Tar
|
||||
url: "https://github.com/tailhook/bulk/releases/download/v0.4.11/bulk-v0.4.11.tar.gz"
|
||||
sha256: b718bb8448e726690c94d98d004bf7575f7a429106ec26ad3faf11e0fd9a7978
|
||||
path: /
|
||||
|
||||
environ:
|
||||
HOME: /work/target
|
||||
USER: pc
|
Loading…
Reference in New Issue
Block a user