summaryrefslogtreecommitdiffstats
path: root/rust/vendor/ipsec-parser
diff options
context:
space:
mode:
Diffstat (limited to 'rust/vendor/ipsec-parser')
-rw-r--r--rust/vendor/ipsec-parser/.cargo-checksum.json1
-rw-r--r--rust/vendor/ipsec-parser/.travis.yml33
-rw-r--r--rust/vendor/ipsec-parser/Cargo.toml32
-rw-r--r--rust/vendor/ipsec-parser/LICENSE-APACHE201
-rw-r--r--rust/vendor/ipsec-parser/LICENSE-MIT25
-rw-r--r--rust/vendor/ipsec-parser/assets/ike-sa-init-req.binbin0 -> 256 bytes
-rw-r--r--rust/vendor/ipsec-parser/assets/ike-sa-init-resp.binbin0 -> 281 bytes
-rw-r--r--rust/vendor/ipsec-parser/src/error.rs19
-rw-r--r--rust/vendor/ipsec-parser/src/esp.rs61
-rw-r--r--rust/vendor/ipsec-parser/src/ikev2.rs622
-rw-r--r--rust/vendor/ipsec-parser/src/ikev2_debug.rs68
-rw-r--r--rust/vendor/ipsec-parser/src/ikev2_notify.rs90
-rw-r--r--rust/vendor/ipsec-parser/src/ikev2_parser.rs600
-rw-r--r--rust/vendor/ipsec-parser/src/ikev2_transforms.rs271
-rw-r--r--rust/vendor/ipsec-parser/src/lib.rs80
15 files changed, 2103 insertions, 0 deletions
diff --git a/rust/vendor/ipsec-parser/.cargo-checksum.json b/rust/vendor/ipsec-parser/.cargo-checksum.json
new file mode 100644
index 0000000..861d7e8
--- /dev/null
+++ b/rust/vendor/ipsec-parser/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{".travis.yml":"abbc9c4fe3fd7457191640c6e5ff798affdfb8652c1e2f2f0e86d041591b4cc0","Cargo.toml":"ec1a53966170b18a06ccaa184381bb7038f09efc5043ed0df931f619e30f9dad","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a5c61b93b6ee1d104af9920cf020ff3c7efe818e31fe562c72261847a728f513","assets/ike-sa-init-req.bin":"6e58dcd7b73fc4e0196dd940c8b31c8ccfeb4fe52645f942df1254ffd91e8636","assets/ike-sa-init-resp.bin":"ae8e26165ba9187931c6933b6bc8b42df366b011d8bed1f8eb3ef6d8aa7c8cde","src/error.rs":"f94c6920931d0bd3f25c36e9bd0f54710c5d4f18b4e395240f29cfc5e8d99cd6","src/esp.rs":"bd43e7b3f0ca4482849b04490eade4d8abf4ab580fca160b63cb85af2c7be072","src/ikev2.rs":"b83a2af7f2f92f005ec03a23c5cadc3c1598c0d5893052b2338d6e0ac15f8278","src/ikev2_debug.rs":"b0df475275fa0b475fd220eef151b4f580c3585ffa9427c5ae58715019fbac63","src/ikev2_notify.rs":"2d00cabb66e09a9ec0a098f0466be854a0d125324314928757f47271d9a812f4","src/ikev2_parser.rs":"3715c4ab909d1bd028cb63e2620a3022c5a40c70602a89e80150f381ef292823","src/ikev2_transforms.rs":"63650f99848ed9363b743ab0279c22e48c431bfeb97959645f49836965300ca5","src/lib.rs":"2c80fd4752d4e4bb8337c679f08f5c43babd168b3c37d324e79f1b2afb577438"},"package":"2cf8413e5de78bcbc51880ff71f4b64105719abe6efb8b4b877d3c7dc494ddd1"} \ No newline at end of file
diff --git a/rust/vendor/ipsec-parser/.travis.yml b/rust/vendor/ipsec-parser/.travis.yml
new file mode 100644
index 0000000..2c411ac
--- /dev/null
+++ b/rust/vendor/ipsec-parser/.travis.yml
@@ -0,0 +1,33 @@
+language: rust
+sudo: false
+matrix:
+ include:
+ - rust: stable
+ env:
+ - NAME="stable"
+ - FEATURES=''
+ - rust: stable
+ env:
+ - NAME="stable,fmt"
+ - FEATURES=''
+ - RUSTFMT=yes
+ - rust: stable
+ env:
+ - NAME="stable,clippy"
+ - FEATURES=''
+ - CLIPPY=yes
+ - rust: nightly
+ env:
+ - NAME="nightly"
+ - FEATURES=''
+before_script:
+ - rustc --version
+ - ([ "$CLIPPY" != yes ] || rustup component add clippy)
+ - ([ "$RUSTFMT" != yes ] || rustup component add rustfmt)
+script:
+ - ([ "$RUSTFMT" != yes ] || cargo fmt --all -- --check)
+ - ([ "$CLIPPY" != yes ] || cargo clippy -- -D clippy::all)
+ - |
+ cargo build --verbose --features "$FEATURES" &&
+ cargo test --verbose --features "$FEATURES" &&
+ ([ "$BENCH" != 1 ] || cargo bench --verbose --features "$FEATURES")
diff --git a/rust/vendor/ipsec-parser/Cargo.toml b/rust/vendor/ipsec-parser/Cargo.toml
new file mode 100644
index 0000000..a75757d
--- /dev/null
+++ b/rust/vendor/ipsec-parser/Cargo.toml
@@ -0,0 +1,32 @@
+# 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 are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "ipsec-parser"
+version = "0.7.0"
+authors = ["Pierre Chifflier <chifflier@wzdftpd.net>"]
+include = ["LICENSE-*", ".gitignore", ".travis.yml", "Cargo.toml", "src/*.rs", "assets/*"]
+description = "Parser for the IKEv2 protocol"
+homepage = "https://github.com/rusticata/ipsec-parser"
+documentation = "https://docs.rs/ipsec-parser"
+readme = "README.md"
+keywords = ["IPsec", "IKEv2", "protocol", "parser", "nom"]
+categories = ["parser-implementations"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/rusticata/ipsec-parser.git"
+[dependencies.nom]
+version = "7.0"
+
+[dependencies.rusticata-macros]
+version = "4.0"
+[badges.travis-ci]
+repository = "rusticata/ipsec-parser"
diff --git a/rust/vendor/ipsec-parser/LICENSE-APACHE b/rust/vendor/ipsec-parser/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/rust/vendor/ipsec-parser/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ 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.
diff --git a/rust/vendor/ipsec-parser/LICENSE-MIT b/rust/vendor/ipsec-parser/LICENSE-MIT
new file mode 100644
index 0000000..290e7b9
--- /dev/null
+++ b/rust/vendor/ipsec-parser/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2017 Pierre Chifflier
+
+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.
diff --git a/rust/vendor/ipsec-parser/assets/ike-sa-init-req.bin b/rust/vendor/ipsec-parser/assets/ike-sa-init-req.bin
new file mode 100644
index 0000000..7d77876
--- /dev/null
+++ b/rust/vendor/ipsec-parser/assets/ike-sa-init-req.bin
Binary files differ
diff --git a/rust/vendor/ipsec-parser/assets/ike-sa-init-resp.bin b/rust/vendor/ipsec-parser/assets/ike-sa-init-resp.bin
new file mode 100644
index 0000000..65688a9
--- /dev/null
+++ b/rust/vendor/ipsec-parser/assets/ike-sa-init-resp.bin
Binary files differ
diff --git a/rust/vendor/ipsec-parser/src/error.rs b/rust/vendor/ipsec-parser/src/error.rs
new file mode 100644
index 0000000..4d753fa
--- /dev/null
+++ b/rust/vendor/ipsec-parser/src/error.rs
@@ -0,0 +1,19 @@
+use nom::error::{ErrorKind, ParseError};
+
+#[derive(Debug)]
+pub enum IPsecError {
+ PayloadTooSmall,
+ ExtraBytesInPayload,
+ PayloadParseError,
+
+ NomError(ErrorKind),
+}
+
+impl<I> ParseError<I> for IPsecError {
+ fn from_error_kind(_input: I, kind: ErrorKind) -> Self {
+ IPsecError::NomError(kind)
+ }
+ fn append(_input: I, _kind: ErrorKind, other: Self) -> Self {
+ other
+ }
+}
diff --git a/rust/vendor/ipsec-parser/src/esp.rs b/rust/vendor/ipsec-parser/src/esp.rs
new file mode 100644
index 0000000..fdfb03e
--- /dev/null
+++ b/rust/vendor/ipsec-parser/src/esp.rs
@@ -0,0 +1,61 @@
+use crate::ikev2::IkeV2Header;
+use crate::ikev2_parser::parse_ikev2_header;
+use nom::bytes::streaming::take;
+use nom::combinator::rest;
+use nom::number::streaming::be_u32;
+use nom::IResult;
+
+/// Encapsulating Security Payload Packet Format
+///
+/// Defined in [RFC2406](https://tools.ietf.org/html/rfc2406) section 2
+#[derive(Debug)]
+pub struct ESPHeader<'a> {
+ pub spi_index: &'a [u8],
+ pub seq: u32,
+ pub data: &'a [u8],
+}
+
+/// UDP-encapsulated Packet Formats
+///
+/// Defined in [RFC3948](https://tools.ietf.org/html/rfc3948) section 2
+#[derive(Debug)]
+pub enum ESPData<'a> {
+ ESP(ESPHeader<'a>),
+ IKE(IkeV2Header),
+}
+
+/// Parse an encapsulated ESP packet
+///
+/// The type of encapsulated data depends on the first field (`spi_index`): 0 is a forbidden SPI
+/// index, and indicates that the header is an IKE header.
+/// Any other value indicates an ESP header.
+///
+/// *Note: input is entirely consumed*
+pub fn parse_esp_encapsulated(i: &[u8]) -> IResult<&[u8], ESPData> {
+ if be_u32(i)?.1 == 0 {
+ parse_ikev2_header(i).map(|x| (x.0, ESPData::IKE(x.1)))
+ } else {
+ parse_esp_header(i).map(|x| (x.0, ESPData::ESP(x.1)))
+ }
+}
+
+/// Parse an ESP packet
+///
+/// The ESP header contains:
+///
+/// - the SPI index
+/// - the sequence number
+/// - the payload data (which can be encrypted)
+///
+/// *Note: input is entirely consumed*
+pub fn parse_esp_header(i: &[u8]) -> IResult<&[u8], ESPHeader> {
+ let (i, spi_index) = take(4usize)(i)?;
+ let (i, seq) = be_u32(i)?;
+ let (i, data) = rest(i)?;
+ let hdr = ESPHeader {
+ spi_index,
+ seq,
+ data,
+ };
+ Ok((i, hdr))
+}
diff --git a/rust/vendor/ipsec-parser/src/ikev2.rs b/rust/vendor/ipsec-parser/src/ikev2.rs
new file mode 100644
index 0000000..400f4a1
--- /dev/null
+++ b/rust/vendor/ipsec-parser/src/ikev2.rs
@@ -0,0 +1,622 @@
+use crate::ikev2_notify::NotifyType;
+use crate::ikev2_transforms::*;
+use rusticata_macros::newtype_enum;
+use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+
+/// Payload exchange type: SA, Auth, CreateChildSA, etc.
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct IkeExchangeType(pub u8);
+
+newtype_enum! {
+impl debug IkeExchangeType {
+ IKE_SA_INIT = 34,
+ IKE_AUTH = 35,
+ CREATE_CHILD_SA = 36,
+ INFORMATIONAL = 37,
+}
+}
+
+/// Protocol type: IKE, AH or ESP
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3.1
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct ProtocolID(pub u8);
+
+newtype_enum! {
+impl debug ProtocolID {
+ IKE = 1,
+ AH = 2,
+ ESP = 3,
+}
+}
+
+pub const IKEV2_FLAG_INITIATOR: u8 = 0b1000;
+pub const IKEV2_FLAG_VERSION: u8 = 0b1_0000;
+pub const IKEV2_FLAG_RESPONSE: u8 = 0b10_0000;
+
+/// The IKE Header
+///
+/// IKE messages use UDP ports 500 and/or 4500, with one IKE message per
+/// UDP datagram. Information from the beginning of the packet through
+/// the UDP header is largely ignored except that the IP addresses and
+/// UDP ports from the headers are reversed and used for return packets.
+/// When sent on UDP port 500, IKE messages begin immediately following
+/// the UDP header. When sent on UDP port 4500, IKE messages have
+/// prepended four octets of zeros. These four octets of zeros are not
+/// part of the IKE message and are not included in any of the length
+/// fields or checksums defined by IKE. Each IKE message begins with the
+/// IKE header, denoted HDR in this document. Following the header are
+/// one or more IKE payloads each identified by a Next Payload field in
+/// the preceding payload. Payloads are identified in the order in which
+/// they appear in an IKE message by looking in the Next Payload field in
+/// the IKE header, and subsequently according to the Next Payload field
+/// in the IKE payload itself until a Next Payload field of zero
+/// indicates that no payloads follow. If a payload of type "Encrypted"
+/// is found, that payload is decrypted and its contents parsed as
+/// additional payloads. An Encrypted payload MUST be the last payload
+/// in a packet and an Encrypted payload MUST NOT contain another
+/// Encrypted payload.
+///
+/// The responder's SPI in the header identifies an instance of an IKE
+/// Security Association. It is therefore possible for a single instance
+/// of IKE to multiplex distinct sessions with multiple peers, including
+/// multiple sessions per peer.
+///
+/// All multi-octet fields representing integers are laid out in big
+/// endian order (also known as "most significant byte first", or
+/// "network byte order").
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.1
+#[derive(Clone, Debug, PartialEq)]
+pub struct IkeV2Header {
+ pub init_spi: u64,
+ pub resp_spi: u64,
+ pub next_payload: IkePayloadType,
+ pub maj_ver: u8,
+ pub min_ver: u8,
+ pub exch_type: IkeExchangeType,
+ pub flags: u8,
+ pub msg_id: u32,
+ pub length: u32,
+}
+
+/// Payload type
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct IkePayloadType(pub u8);
+
+newtype_enum! {
+impl debug IkePayloadType {
+ NoNextPayload = 0,
+ SecurityAssociation = 33,
+ KeyExchange = 34,
+ IdentInitiator = 35,
+ IdentResponder = 36,
+ Certificate = 37,
+ CertificateRequest = 38,
+ Authentication = 39,
+ Nonce = 40,
+ Notify = 41,
+ Delete = 42,
+ VendorID = 43,
+ TrafficSelectorInitiator = 44,
+ TrafficSelectorResponder = 45,
+ EncryptedAndAuthenticated = 46,
+ Configuration = 47,
+ ExtensibleAuthentication = 48,
+}
+}
+
+/// Generic (unparsed payload)
+///
+/// Defined in [RFC7296]
+#[derive(Debug, PartialEq)]
+pub struct IkeV2GenericPayload<'a> {
+ pub hdr: IkeV2PayloadHeader,
+ pub payload: &'a [u8],
+}
+
+/// Ciphersuite Proposal
+///
+/// The Proposal structure contains within it a Proposal Num and an IPsec
+/// protocol ID. Each structure MUST have a proposal number one (1)
+/// greater than the previous structure. The first Proposal in the
+/// initiator's SA payload MUST have a Proposal Num of one (1). One
+/// reason to use multiple proposals is to propose both standard crypto
+/// ciphers and combined-mode ciphers. Combined-mode ciphers include
+/// both integrity and encryption in a single encryption algorithm, and
+/// MUST either offer no integrity algorithm or a single integrity
+/// algorithm of "NONE", with no integrity algorithm being the
+/// RECOMMENDED method. If an initiator wants to propose both combined-
+/// mode ciphers and normal ciphers, it must include two proposals: one
+/// will have all the combined-mode ciphers, and the other will have all
+/// the normal ciphers with the integrity algorithms. For example, one
+/// such proposal would have two proposal structures. Proposal 1 is ESP
+/// with AES-128, AES-192, and AES-256 bits in Cipher Block Chaining
+/// (CBC) mode, with either HMAC-SHA1-96 or XCBC-96 as the integrity
+/// algorithm; Proposal 2 is AES-128 or AES-256 in GCM mode with an
+/// 8-octet Integrity Check Value (ICV). Both proposals allow but do not
+/// require the use of ESNs (Extended Sequence Numbers). This can be
+/// illustrated as:
+///
+/// ```ignore
+/// SA Payload
+/// |
+/// +--- Proposal #1 ( Proto ID = ESP(3), SPI size = 4,
+/// | | 7 transforms, SPI = 0x052357bb )
+/// | |
+/// | +-- Transform ENCR ( Name = ENCR_AES_CBC )
+/// | | +-- Attribute ( Key Length = 128 )
+/// | |
+/// | +-- Transform ENCR ( Name = ENCR_AES_CBC )
+/// | | +-- Attribute ( Key Length = 192 )
+/// | |
+/// | +-- Transform ENCR ( Name = ENCR_AES_CBC )
+/// | | +-- Attribute ( Key Length = 256 )
+/// | |
+/// | +-- Transform INTEG ( Name = AUTH_HMAC_SHA1_96 )
+/// | +-- Transform INTEG ( Name = AUTH_AES_XCBC_96 )
+/// | +-- Transform ESN ( Name = ESNs )
+/// | +-- Transform ESN ( Name = No ESNs )
+/// |
+/// +--- Proposal #2 ( Proto ID = ESP(3), SPI size = 4,
+/// | 4 transforms, SPI = 0x35a1d6f2 )
+/// |
+/// +-- Transform ENCR ( Name = AES-GCM with a 8 octet ICV )
+/// | +-- Attribute ( Key Length = 128 )
+/// |
+/// +-- Transform ENCR ( Name = AES-GCM with a 8 octet ICV )
+/// | +-- Attribute ( Key Length = 256 )
+/// |
+/// +-- Transform ESN ( Name = ESNs )
+/// +-- Transform ESN ( Name = No ESNs )
+/// ```
+///
+/// Each Proposal/Protocol structure is followed by one or more transform
+/// structures. The number of different transforms is generally
+/// determined by the Protocol. AH generally has two transforms:
+/// Extended Sequence Numbers (ESNs) and an integrity check algorithm.
+/// ESP generally has three: ESN, an encryption algorithm, and an
+/// integrity check algorithm. IKE generally has four transforms: a
+/// Diffie-Hellman group, an integrity check algorithm, a PRF algorithm,
+/// and an encryption algorithm. For each Protocol, the set of
+/// permissible transforms is assigned Transform ID numbers, which appear
+/// in the header of each transform.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3.1
+#[derive(Clone, Debug, PartialEq)]
+pub struct IkeV2Proposal<'a> {
+ pub last: u8,
+ pub reserved: u8,
+ pub proposal_length: u16,
+ pub proposal_num: u8,
+ pub protocol_id: ProtocolID,
+ pub spi_size: u8,
+ pub num_transforms: u8,
+ pub spi: Option<&'a [u8]>,
+ pub transforms: Vec<IkeV2RawTransform<'a>>,
+}
+
+/// Key Exchange Payload
+///
+/// The Key Exchange payload, denoted KE in this document, is used to
+/// exchange Diffie-Hellman public numbers as part of a Diffie-Hellman
+/// key exchange. The Key Exchange payload consists of the IKE generic
+/// payload header followed by the Diffie-Hellman public value itself.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.4
+#[derive(Debug, PartialEq)]
+pub struct KeyExchangePayload<'a> {
+ pub dh_group: IkeTransformDHType,
+ pub reserved: u16,
+ pub kex_data: &'a [u8],
+}
+
+/// Identification Payloads
+///
+/// The Identification payloads, denoted IDi and IDr in this document,
+/// allow peers to assert an identity to one another. This identity may
+/// be used for policy lookup, but does not necessarily have to match
+/// anything in the CERT payload; both fields may be used by an
+/// implementation to perform access control decisions. When using the
+/// ID_IPV4_ADDR/ID_IPV6_ADDR identity types in IDi/IDr payloads, IKEv2
+/// does not require this address to match the address in the IP header
+/// of IKEv2 packets, or anything in the TSi/TSr payloads. The contents
+/// of IDi/IDr are used purely to fetch the policy and authentication
+/// data related to the other party.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.5
+#[derive(Debug, PartialEq)]
+pub struct IdentificationPayload<'a> {
+ pub id_type: IdentificationType,
+ pub reserved1: u8,
+ pub reserved2: u16,
+ pub ident_data: &'a [u8],
+}
+
+/// Type of Identification
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct IdentificationType(pub u8);
+
+#[rustfmt::skip]
+impl IdentificationType {
+ /// A single four (4) octet IPv4 address.
+ pub const ID_IPV4_ADDR : IdentificationType = IdentificationType(1);
+ /// A fully-qualified domain name string. An example of an ID_FQDN
+ /// is "example.com". The string MUST NOT contain any terminators
+ /// (e.g., NULL, CR, etc.). All characters in the ID_FQDN are ASCII;
+ /// for an "internationalized domain name", the syntax is as defined
+ /// in [IDNA], for example "xn--tmonesimerkki-bfbb.example.net".
+ pub const ID_FQDN : IdentificationType = IdentificationType(2);
+ /// A fully-qualified RFC 822 email address string. An example of a
+ /// ID_RFC822_ADDR is "jsmith@example.com". The string MUST NOT
+ /// contain any terminators. Because of [EAI], implementations would
+ /// be wise to treat this field as UTF-8 encoded text, not as
+ /// pure ASCII.
+ pub const ID_RFC822_ADDR : IdentificationType = IdentificationType(3);
+ /// A single sixteen (16) octet IPv6 address.
+ pub const ID_IPV6_ADDR : IdentificationType = IdentificationType(5);
+ /// The binary Distinguished Encoding Rules (DER) encoding of an ASN.1 X.500 Distinguished
+ /// Name.
+ pub const ID_DER_ASN1_DN : IdentificationType = IdentificationType(9);
+ /// The binary DER encoding of an ASN.1 X.509 GeneralName.
+ pub const ID_DER_ASN1_GN : IdentificationType = IdentificationType(10);
+ /// An opaque octet stream that may be used to pass vendor-specific information necessary to do
+ /// certain proprietary types of identification.
+ pub const ID_KEY_ID : IdentificationType = IdentificationType(11);
+}
+
+/// Certificate Payload
+///
+/// The Certificate payload, denoted CERT in this document, provides a
+/// means to transport certificates or other authentication-related
+/// information via IKE. Certificate payloads SHOULD be included in an
+/// exchange if certificates are available to the sender. The Hash and
+/// URL formats of the Certificate payloads should be used in case the
+/// peer has indicated an ability to retrieve this information from
+/// elsewhere using an HTTP_CERT_LOOKUP_SUPPORTED Notify payload. Note
+/// that the term "Certificate payload" is somewhat misleading, because
+/// not all authentication mechanisms use certificates and data other
+/// than certificates may be passed in this payload.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.6
+#[derive(Debug, PartialEq)]
+pub struct CertificatePayload<'a> {
+ pub cert_encoding: CertificateEncoding,
+ pub cert_data: &'a [u8],
+}
+
+/// Certificate Encoding
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.6
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct CertificateEncoding(pub u8);
+
+#[allow(non_upper_case_globals)]
+#[rustfmt::skip]
+impl CertificateEncoding {
+ /// PKCS #7 wrapped X.509 certificate
+ pub const Pkcs7_X509 : CertificateEncoding = CertificateEncoding(1);
+ /// PGP Certificate
+ pub const PgpCert : CertificateEncoding = CertificateEncoding(2);
+ /// DNS Signed Key
+ pub const DnsKey : CertificateEncoding = CertificateEncoding(3);
+ /// X.509 Certificate - Signature
+ pub const X509Sig : CertificateEncoding = CertificateEncoding(4);
+ /// Kerberos Token
+ pub const Kerberos : CertificateEncoding = CertificateEncoding(6);
+ /// Certificate Revocation List (CRL)
+ pub const Crl : CertificateEncoding = CertificateEncoding(7);
+ /// Authority Revocation List (ARL)
+ pub const Arl : CertificateEncoding = CertificateEncoding(8);
+ /// SPKI Certificate
+ pub const SpkiCert : CertificateEncoding = CertificateEncoding(9);
+ /// X.509 Certificate - Attribute
+ pub const X509CertAttr : CertificateEncoding = CertificateEncoding(10);
+ /// Deprecated (was Raw RSA Key)
+ pub const OldRsaKey : CertificateEncoding = CertificateEncoding(11);
+ /// Hash and URL of X.509 certificate
+ pub const X509Cert_HashUrl : CertificateEncoding = CertificateEncoding(12);
+ /// Hash and URL of X.509 bundle
+ pub const X509Bundle_HashUrl : CertificateEncoding = CertificateEncoding(13);
+ /// OCSP Content ([RFC4806](https://tools.ietf.org/html/rfc4806))
+ pub const OCSPContent : CertificateEncoding = CertificateEncoding(14);
+ /// Raw Public Key ([RFC7670](https://tools.ietf.org/html/rfc7670))
+ pub const RawPublicKey : CertificateEncoding = CertificateEncoding(15);
+}
+
+/// Certificate Request Payload
+///
+/// The Certificate Request payload, denoted CERTREQ in this document,
+/// provides a means to request preferred certificates via IKE and can
+/// appear in the IKE_INIT_SA response and/or the IKE_AUTH request.
+/// Certificate Request payloads MAY be included in an exchange when the
+/// sender needs to get the certificate of the receiver.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.7
+#[derive(Debug, PartialEq)]
+pub struct CertificateRequestPayload<'a> {
+ pub cert_encoding: CertificateEncoding,
+ pub ca_data: &'a [u8],
+}
+
+/// Authentication Payload
+///
+/// The Authentication payload, denoted AUTH in this document, contains
+/// data used for authentication purposes.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.8
+#[derive(Debug, PartialEq)]
+pub struct AuthenticationPayload<'a> {
+ pub auth_method: AuthenticationMethod,
+ pub auth_data: &'a [u8],
+}
+
+/// Method of authentication used.
+///
+/// See also [IKEV2IANA](https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml) for the latest values.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct AuthenticationMethod(pub u8);
+
+#[allow(non_upper_case_globals)]
+#[rustfmt::skip]
+impl AuthenticationMethod {
+ /// RSA Digital Signature
+ pub const RsaSig : AuthenticationMethod = AuthenticationMethod(1);
+ /// Shared Key Message Integrity Code
+ pub const SharedKeyMIC : AuthenticationMethod = AuthenticationMethod(2);
+ /// DSS Digital Signature
+ pub const DssSig : AuthenticationMethod = AuthenticationMethod(3);
+ /// ECDSA with SHA-256 on the P-256 curve
+ pub const EcdsaSha256P256 : AuthenticationMethod = AuthenticationMethod(9);
+ /// ECDSA with SHA-384 on the P-384 curve
+ pub const EcdsaSha384P384 : AuthenticationMethod = AuthenticationMethod(10);
+ /// ECDSA with SHA-512 on the P-512 curve
+ pub const EcdsaSha512P512 : AuthenticationMethod = AuthenticationMethod(11);
+ /// Generic Secure Password Authentication Method
+ pub const GenericPass : AuthenticationMethod = AuthenticationMethod(12);
+ /// NULL Authentication
+ pub const Null : AuthenticationMethod = AuthenticationMethod(13);
+ /// Digital Signature
+ pub const DigitalSig : AuthenticationMethod = AuthenticationMethod(14);
+
+ /// Test if value is in unassigned range
+ pub fn is_unassigned(self) -> bool {
+ (self.0 >= 4 && self.0 <= 8) ||
+ (self.0 >= 15 && self.0 <= 200)
+ }
+
+ /// Test if value is in private use range
+ pub fn is_private_use(self) -> bool {
+ self.0 >= 201
+ }
+}
+
+/// Nonce Payload
+///
+/// The Nonce payload, denoted as Ni and Nr in this document for the
+/// initiator's and responder's nonce, respectively, contains random data used to guarantee
+/// liveness during an exchange and protect against replay attacks.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.9
+#[derive(PartialEq)]
+pub struct NoncePayload<'a> {
+ pub nonce_data: &'a [u8],
+}
+
+/// Notify Payload
+///
+/// The Notify payload, denoted N in this document, is used to transmit informational data, such as
+/// error conditions and state transitions, to an IKE peer. A Notify payload may appear in a
+/// response message (usually specifying why a request was rejected), in an INFORMATIONAL exchange
+/// (to report an error not in an IKE request), or in any other message to indicate sender
+/// capabilities or to modify the meaning of the request.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.10
+#[derive(PartialEq)]
+pub struct NotifyPayload<'a> {
+ pub protocol_id: ProtocolID,
+ pub spi_size: u8,
+ pub notify_type: NotifyType,
+ pub spi: Option<&'a [u8]>,
+ pub notify_data: Option<&'a [u8]>,
+}
+
+/// Delete Payload
+///
+/// The Delete payload, denoted D in this document, contains a
+/// protocol-specific Security Association identifier that the sender has
+/// removed from its Security Association database and is, therefore, no
+/// longer valid. Figure 17 shows the format of the Delete payload. It
+/// is possible to send multiple SPIs in a Delete payload; however, each
+/// SPI MUST be for the same protocol. Mixing of protocol identifiers
+/// MUST NOT be performed in the Delete payload. It is permitted,
+/// however, to include multiple Delete payloads in a single
+/// INFORMATIONAL exchange where each Delete payload lists SPIs for a
+/// different protocol.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.11
+#[derive(Debug, PartialEq)]
+pub struct DeletePayload<'a> {
+ pub protocol_id: ProtocolID,
+ pub spi_size: u8,
+ pub num_spi: u16,
+ pub spi: &'a [u8],
+}
+
+/// Vendor ID Payload
+///
+/// The Vendor ID payload, denoted V in this document, contains a vendor-
+/// defined constant. The constant is used by vendors to identify and
+/// recognize remote instances of their implementations. This mechanism
+/// allows a vendor to experiment with new features while maintaining
+/// backward compatibility.
+///
+/// A Vendor ID payload MAY announce that the sender is capable of
+/// accepting certain extensions to the protocol, or it MAY simply
+/// identify the implementation as an aid in debugging. A Vendor ID
+/// payload MUST NOT change the interpretation of any information defined
+/// in this specification (i.e., the critical bit MUST be set to 0).
+/// Multiple Vendor ID payloads MAY be sent. An implementation is not
+/// required to send any Vendor ID payload at all.
+///
+/// A Vendor ID payload may be sent as part of any message. Reception of
+/// a familiar Vendor ID payload allows an implementation to make use of
+/// private use numbers described throughout this document, such as
+/// private payloads, private exchanges, private notifications, etc.
+/// Unfamiliar Vendor IDs MUST be ignored.
+///
+/// Writers of documents who wish to extend this protocol MUST define a
+/// Vendor ID payload to announce the ability to implement the extension
+/// in the document. It is expected that documents that gain acceptance
+/// and are standardized will be given "magic numbers" out of the Future
+/// Use range by IANA, and the requirement to use a Vendor ID will go
+/// away.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.12
+#[derive(Debug, PartialEq)]
+pub struct VendorIDPayload<'a> {
+ pub vendor_id: &'a [u8],
+}
+
+/// Type of Traffic Selector
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.13.1
+///
+/// See also [IKEV2IANA](https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml) for the latest values.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct TSType(pub u8);
+
+#[allow(non_upper_case_globals)]
+impl TSType {
+ /// A range of IPv4 addresses
+ pub const IPv4AddrRange: TSType = TSType(7);
+ /// A range of IPv6 addresses
+ pub const IPv6AddrRange: TSType = TSType(8);
+ /// Fibre Channel Traffic Selectors ([RFC4595](https://tools.ietf.org/html/rfc4595))
+ pub const FcAddrRange: TSType = TSType(9);
+}
+
+/// Traffic Selector
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.13.1
+#[derive(Debug, PartialEq)]
+pub struct TrafficSelector<'a> {
+ pub ts_type: TSType,
+ pub ip_proto_id: u8,
+ pub sel_length: u16,
+ pub start_port: u16,
+ pub end_port: u16,
+ pub start_addr: &'a [u8],
+ pub end_addr: &'a [u8],
+}
+
+fn ipv4_from_slice(b: &[u8]) -> Ipv4Addr {
+ Ipv4Addr::new(b[0], b[1], b[2], b[3])
+}
+
+fn ipv6_from_slice(b: &[u8]) -> Ipv6Addr {
+ Ipv6Addr::new(
+ (b[0] as u16) << 8 | (b[1] as u16),
+ (b[2] as u16) << 8 | (b[3] as u16),
+ (b[4] as u16) << 8 | (b[5] as u16),
+ (b[6] as u16) << 8 | (b[7] as u16),
+ (b[8] as u16) << 8 | (b[9] as u16),
+ (b[10] as u16) << 8 | (b[11] as u16),
+ (b[12] as u16) << 8 | (b[13] as u16),
+ (b[14] as u16) << 8 | (b[15] as u16),
+ )
+}
+
+impl<'a> TrafficSelector<'a> {
+ pub fn get_ts_type(&self) -> TSType {
+ self.ts_type
+ }
+
+ pub fn get_start_addr(&self) -> Option<IpAddr> {
+ match self.ts_type {
+ TSType::IPv4AddrRange => Some(IpAddr::V4(ipv4_from_slice(self.start_addr))),
+ TSType::IPv6AddrRange => Some(IpAddr::V6(ipv6_from_slice(self.start_addr))),
+ _ => None,
+ }
+ }
+
+ pub fn get_end_addr(&self) -> Option<IpAddr> {
+ match self.ts_type {
+ TSType::IPv4AddrRange => Some(IpAddr::V4(ipv4_from_slice(self.end_addr))),
+ TSType::IPv6AddrRange => Some(IpAddr::V6(ipv6_from_slice(self.end_addr))),
+ _ => None,
+ }
+ }
+}
+
+/// Traffic Selector Payload
+///
+/// The Traffic Selector payload, denoted TS in this document, allows
+/// peers to identify packet flows for processing by IPsec security
+/// services. The Traffic Selector payload consists of the IKE generic
+/// payload header followed by individual Traffic Selectors.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.13
+#[derive(Debug, PartialEq)]
+pub struct TrafficSelectorPayload<'a> {
+ pub num_ts: u8,
+ pub reserved: &'a [u8], // 3 bytes
+ pub ts: Vec<TrafficSelector<'a>>,
+}
+
+/// Encrypted Payload
+///
+/// The Encrypted payload, denoted SK {...} in this document, contains
+/// other payloads in encrypted form. The Encrypted payload, if present
+/// in a message, MUST be the last payload in the message. Often, it is
+/// the only payload in the message. This payload is also called the
+/// "Encrypted and Authenticated" payload.
+#[derive(Debug, PartialEq)]
+pub struct EncryptedPayload<'a>(pub &'a [u8]);
+
+/// IKE Message Payload Content
+///
+/// The content of an IKE message is one of the defined payloads.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.2
+#[derive(Debug, PartialEq)]
+pub enum IkeV2PayloadContent<'a> {
+ SA(Vec<IkeV2Proposal<'a>>),
+ KE(KeyExchangePayload<'a>),
+ IDi(IdentificationPayload<'a>),
+ IDr(IdentificationPayload<'a>),
+ Certificate(CertificatePayload<'a>),
+ CertificateRequest(CertificateRequestPayload<'a>),
+ Authentication(AuthenticationPayload<'a>),
+ Nonce(NoncePayload<'a>),
+ Notify(NotifyPayload<'a>),
+ Delete(DeletePayload<'a>),
+ VendorID(VendorIDPayload<'a>),
+ TSi(TrafficSelectorPayload<'a>),
+ TSr(TrafficSelectorPayload<'a>),
+ Encrypted(EncryptedPayload<'a>),
+
+ Unknown(&'a [u8]),
+
+ Dummy,
+}
+
+/// Generic Payload Header
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.2
+#[derive(Clone, Debug, PartialEq)]
+pub struct IkeV2PayloadHeader {
+ pub next_payload_type: IkePayloadType,
+ pub critical: bool,
+ pub reserved: u8,
+ pub payload_length: u16,
+}
+
+/// IKE Message Payload
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3
+#[derive(Debug, PartialEq)]
+pub struct IkeV2Payload<'a> {
+ pub hdr: IkeV2PayloadHeader,
+ pub content: IkeV2PayloadContent<'a>,
+}
diff --git a/rust/vendor/ipsec-parser/src/ikev2_debug.rs b/rust/vendor/ipsec-parser/src/ikev2_debug.rs
new file mode 100644
index 0000000..9daded4
--- /dev/null
+++ b/rust/vendor/ipsec-parser/src/ikev2_debug.rs
@@ -0,0 +1,68 @@
+use crate::ikev2::*;
+use crate::ikev2_transforms::*;
+use rusticata_macros::debug::HexSlice;
+use std::fmt;
+
+// ------------------------- ikev2_transforms.rs ------------------------------
+//
+impl<'a> fmt::Debug for IkeV2RawTransform<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let (tf_type, tf_id) = match self.transform_type {
+ IkeTransformType::EncryptionAlgorithm => (
+ "EncryptionAlgorithm".to_string(),
+ format!("{:?}", self.transform_id),
+ ),
+ IkeTransformType::PseudoRandomFunction => (
+ "PseudoRandomFunction".to_string(),
+ format!("{:?}", self.transform_id),
+ ),
+ IkeTransformType::IntegrityAlgorithm => (
+ "IntegrityAlgorithm".to_string(),
+ format!("{:?}", self.transform_id),
+ ),
+ IkeTransformType::DiffieHellmanGroup => (
+ "DiffieHellmanGroup".to_string(),
+ format!("{:?}", self.transform_id),
+ ),
+ IkeTransformType::ExtendedSequenceNumbers => (
+ "ExtendedSequenceNumbers".to_string(),
+ format!("{:?}", self.transform_id),
+ ),
+ _ => (
+ format!("<Unknown transform type {}>", self.transform_type.0),
+ "".to_string(),
+ ),
+ };
+ fmt.debug_struct("IkeV2RawTransform")
+ .field("last", &self.last)
+ .field("reserved1", &self.reserved1)
+ .field("transform_length", &self.transform_length)
+ .field("transform_type", &tf_type)
+ .field("reserved2", &self.reserved2)
+ .field("transform_id", &tf_id)
+ .field("attributes", &self.attributes)
+ .finish()
+ }
+}
+
+// ------------------------- ikev2.rs ------------------------------
+
+impl<'a> fmt::Debug for NoncePayload<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("NoncePayload")
+ .field("nonce_data", &HexSlice(self.nonce_data))
+ .finish()
+ }
+}
+
+impl<'a> fmt::Debug for NotifyPayload<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("NotifyPayload")
+ .field("protocol_id", &self.protocol_id)
+ .field("spi_size", &self.spi_size)
+ .field("notify_type", &self.notify_type)
+ .field("spi", &self.spi)
+ .field("notify_data", &self.notify_data.map(HexSlice))
+ .finish()
+ }
+}
diff --git a/rust/vendor/ipsec-parser/src/ikev2_notify.rs b/rust/vendor/ipsec-parser/src/ikev2_notify.rs
new file mode 100644
index 0000000..cef4e76
--- /dev/null
+++ b/rust/vendor/ipsec-parser/src/ikev2_notify.rs
@@ -0,0 +1,90 @@
+use rusticata_macros::newtype_enum;
+
+/// Notify Message Type
+///
+/// Notification information can be error messages specifying why an SA
+/// could not be established. It can also be status data that a process
+/// managing an SA database wishes to communicate with a peer process.
+///
+/// The table below lists the notification messages and their
+/// corresponding values. The number of different error statuses was
+/// greatly reduced from IKEv1 both for simplification and to avoid
+/// giving configuration information to probers.
+///
+/// Types in the range 0 - 16383 are intended for reporting errors. An
+/// implementation receiving a Notify payload with one of these types
+/// that it does not recognize in a response MUST assume that the
+/// corresponding request has failed entirely. Unrecognized error types
+/// in a request and status types in a request or response MUST be
+/// ignored, and they should be logged.
+///
+/// Notify payloads with status types MAY be added to any message and
+/// MUST be ignored if not recognized. They are intended to indicate
+/// capabilities, and as part of SA negotiation, are used to negotiate
+/// non-cryptographic parameters.
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.10.1
+///
+/// Extensions:
+///
+/// - [RFC4555](https://tools.ietf.org/html/rfc4555) IKEv2 Mobility and Multihoming Protocol (MOBIKE)
+/// - [RFC4739](https://tools.ietf.org/html/rfc4739) Multiple Authentication Exchanges in the Internet Key Exchange (IKEv2) Protocol
+/// - [RFC5685](https://tools.ietf.org/html/rfc5685) Redirect Mechanism for the Internet Key Exchange Protocol Version 2 (IKEv2)
+/// - [RFC5723](https://tools.ietf.org/html/rfc5723) Internet Key Exchange Protocol Version 2 (IKEv2) Session Resumption
+/// - [RFC7427](https://tools.ietf.org/html/rfc7427) Signature Authentication in the Internet Key Exchange Version 2 (IKEv2)
+///
+/// See also [IKEV2IANA](https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml) for the latest values.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct NotifyType(pub u16);
+
+newtype_enum! {
+impl debug NotifyType {
+ // error types
+ UNSUPPORTED_CRITICAL_PAYLOAD = 1,
+ INVALID_IKE_SPI = 4,
+ INVALID_MAJOR_VERSION = 5,
+ INVALID_SYNTAX = 7,
+ INVALID_MESSAGE_ID = 9,
+ INVALID_SPI = 11,
+ NO_PROPOSAL_CHOSEN = 14,
+ INVALID_KE_PAYLOAD = 17,
+ AUTHENTICATION_FAILED = 24,
+ SINGLE_PAIR_REQUIRED = 34,
+ NO_ADDITIONAL_SAS = 35,
+ INTERNAL_ADDRESS_FAILURE = 36,
+ FAILED_CP_REQUIRED = 37,
+ TS_UNACCEPTABLE = 38,
+ INVALID_SELECTORS = 39,
+ TEMPORARY_FAILURE = 43,
+ CHILD_SA_NOT_FOUND = 44,
+ // status types
+ INITIAL_CONTACT = 16384,
+ SET_WINDOW_SIZE = 16385,
+ ADDITIONAL_TS_POSSIBLE = 16386,
+ IPCOMP_SUPPORTED = 16387,
+ NAT_DETECTION_SOURCE_IP = 16388,
+ NAT_DETECTION_DESTINATION_IP = 16389,
+ COOKIE = 16390,
+ USE_TRANSPORT_MODE = 16391,
+ HTTP_CERT_LOOKUP_SUPPORTED = 16392,
+ REKEY_SA = 16393,
+ ESP_TFC_PADDING_NOT_SUPPORTED = 16394,
+ NON_FIRST_FRAGMENTS_ALSO = 16395,
+ //
+ MULTIPLE_AUTH_SUPPORTED = 16404,
+ ANOTHER_AUTH_FOLLOWS = 16405,
+ REDIRECT_SUPPORTED = 16406,
+ //
+ IKEV2_FRAGMENTATION_SUPPORTED = 16430,
+ SIGNATURE_HASH_ALGORITHMS = 16431,
+}
+}
+
+impl NotifyType {
+ pub fn is_error(self) -> bool {
+ self.0 < 16384
+ }
+ pub fn is_status(self) -> bool {
+ self.0 > 16384
+ }
+}
diff --git a/rust/vendor/ipsec-parser/src/ikev2_parser.rs b/rust/vendor/ipsec-parser/src/ikev2_parser.rs
new file mode 100644
index 0000000..c1dd0a1
--- /dev/null
+++ b/rust/vendor/ipsec-parser/src/ikev2_parser.rs
@@ -0,0 +1,600 @@
+use crate::error::IPsecError;
+use crate::ikev2::*;
+use crate::ikev2_notify::NotifyType;
+use crate::ikev2_transforms::*;
+use nom::bytes::streaming::take;
+use nom::combinator::{complete, cond, map, map_parser, verify};
+use nom::error::{make_error, ErrorKind};
+use nom::multi::{count, many1};
+use nom::number::streaming::{be_u16, be_u32, be_u64, be_u8};
+use nom::{Err, IResult, Needed};
+
+pub fn parse_ikev2_header(i: &[u8]) -> IResult<&[u8], IkeV2Header> {
+ if i.len() < 28 {
+ return Err(Err::Incomplete(Needed::new(28)));
+ }
+ let (i, init_spi) = be_u64(i)?;
+ let (i, resp_spi) = be_u64(i)?;
+ let (i, next_payload) = map(be_u8, IkePayloadType)(i)?;
+ let (i, vers) = be_u8(i)?;
+ let maj_ver = vers >> 4;
+ let min_ver = vers & 0b1111;
+ let (i, exch_type) = map(be_u8, IkeExchangeType)(i)?;
+ let (i, flags) = be_u8(i)?;
+ let (i, msg_id) = be_u32(i)?;
+ let (i, length) = be_u32(i)?;
+ let hdr = IkeV2Header {
+ init_spi,
+ resp_spi,
+ next_payload,
+ maj_ver,
+ min_ver,
+ exch_type,
+ flags,
+ msg_id,
+ length,
+ };
+ Ok((i, hdr))
+}
+
+#[inline]
+fn bits_split_1(i: &[u8]) -> IResult<&[u8], (u8, u8)> {
+ let (i, b) = be_u8(i)?;
+ let b1 = b >> 7;
+ let b2_7 = b & 0b_0111_1111;
+ Ok((i, (b1, b2_7)))
+}
+
+pub fn parse_ikev2_payload_generic(i: &[u8]) -> IResult<&[u8], IkeV2GenericPayload> {
+ let (i, next_payload_type) = map(be_u8, IkePayloadType)(i)?;
+ let (i, b) = bits_split_1(i)?;
+ let (i, payload_length) = verify(be_u16, |&n| n >= 4)(i)?;
+ let (i, payload) = take(payload_length - 4)(i)?;
+ let hdr = IkeV2PayloadHeader {
+ next_payload_type,
+ critical: b.0 == 1,
+ reserved: b.1,
+ payload_length,
+ };
+ let payload = IkeV2GenericPayload { hdr, payload };
+ Ok((i, payload))
+}
+
+pub fn parse_ikev2_transform(i: &[u8]) -> IResult<&[u8], IkeV2RawTransform> {
+ let (i, last) = be_u8(i)?;
+ let (i, reserved1) = be_u8(i)?;
+ let (i, transform_length) = be_u16(i)?;
+ let (i, transform_type) = be_u8(i)?;
+ let (i, reserved2) = be_u8(i)?;
+ let (i, transform_id) = be_u16(i)?;
+ // we have to specify a callback here to force lazy evaluation,
+ // because the function arguments are evaluated *before* the test (causing underflow)
+ let (i, attributes) = cond(transform_length > 8, |d| take(transform_length - 8)(d))(i)?;
+ let transform = IkeV2RawTransform {
+ last,
+ reserved1,
+ transform_length,
+ transform_type: IkeTransformType(transform_type),
+ reserved2,
+ transform_id,
+ attributes,
+ };
+ Ok((i, transform))
+}
+
+pub fn parse_ikev2_proposal(i: &[u8]) -> IResult<&[u8], IkeV2Proposal> {
+ if i.len() < 8 {
+ return Err(Err::Incomplete(Needed::new(8)));
+ }
+ let (i, last) = be_u8(i)?;
+ let (i, reserved) = be_u8(i)?;
+ let (i, proposal_length) = be_u16(i)?;
+ let (i, proposal_num) = be_u8(i)?;
+ let (i, protocol_id) = map(be_u8, ProtocolID)(i)?;
+ let (i, spi_size) = be_u8(i)?;
+ let (i, num_transforms) = be_u8(i)?;
+ let (i, spi) = cond(spi_size > 0, take(spi_size))(i)?;
+ if proposal_length < (8u16 + spi_size as u16) {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, transforms) = map_parser(
+ take(proposal_length - 8 - (spi_size as u16)),
+ count(parse_ikev2_transform, num_transforms as usize),
+ )(i)?;
+ let proposal = IkeV2Proposal {
+ last,
+ reserved,
+ proposal_length,
+ proposal_num,
+ protocol_id,
+ spi_size,
+ num_transforms,
+ spi,
+ transforms,
+ };
+ Ok((i, proposal))
+}
+
+pub fn parse_ikev2_payload_sa(i: &[u8], _length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ map(
+ many1(complete(parse_ikev2_proposal)),
+ IkeV2PayloadContent::SA,
+ )(i)
+}
+
+pub fn parse_ikev2_payload_kex(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ if length < 4 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, dh_group) = map(be_u16, IkeTransformDHType)(i)?;
+ let (i, reserved) = be_u16(i)?;
+ let (i, kex_data) = take(length - 4)(i)?;
+ let payload = KeyExchangePayload {
+ dh_group,
+ reserved,
+ kex_data,
+ };
+ Ok((i, IkeV2PayloadContent::KE(payload)))
+}
+
+pub fn parse_ikev2_payload_ident_init(
+ i: &[u8],
+ length: u16,
+) -> IResult<&[u8], IkeV2PayloadContent> {
+ if length < 4 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, id_type) = map(be_u8, IdentificationType)(i)?;
+ let (i, reserved1) = be_u8(i)?;
+ let (i, reserved2) = be_u16(i)?;
+ let (i, ident_data) = take(length - 4)(i)?;
+ let payload = IdentificationPayload {
+ id_type,
+ reserved1,
+ reserved2,
+ ident_data,
+ };
+ Ok((i, IkeV2PayloadContent::IDi(payload)))
+}
+
+pub fn parse_ikev2_payload_ident_resp(
+ i: &[u8],
+ length: u16,
+) -> IResult<&[u8], IkeV2PayloadContent> {
+ if length < 4 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, id_type) = map(be_u8, IdentificationType)(i)?;
+ let (i, reserved1) = be_u8(i)?;
+ let (i, reserved2) = be_u16(i)?;
+ let (i, ident_data) = take(length - 4)(i)?;
+ let payload = IdentificationPayload {
+ id_type,
+ reserved1,
+ reserved2,
+ ident_data,
+ };
+ Ok((i, IkeV2PayloadContent::IDr(payload)))
+}
+
+pub fn parse_ikev2_payload_certificate(
+ i: &[u8],
+ length: u16,
+) -> IResult<&[u8], IkeV2PayloadContent> {
+ if length < 1 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, cert_encoding) = map(be_u8, CertificateEncoding)(i)?;
+ let (i, cert_data) = take(length - 1)(i)?;
+ let payload = CertificatePayload {
+ cert_encoding,
+ cert_data,
+ };
+ Ok((i, IkeV2PayloadContent::Certificate(payload)))
+}
+
+pub fn parse_ikev2_payload_certificate_request(
+ i: &[u8],
+ length: u16,
+) -> IResult<&[u8], IkeV2PayloadContent> {
+ if length < 1 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, cert_encoding) = map(be_u8, CertificateEncoding)(i)?;
+ let (i, ca_data) = take(length - 1)(i)?;
+ let payload = CertificateRequestPayload {
+ cert_encoding,
+ ca_data,
+ };
+ Ok((i, IkeV2PayloadContent::CertificateRequest(payload)))
+}
+
+pub fn parse_ikev2_payload_authentication(
+ i: &[u8],
+ length: u16,
+) -> IResult<&[u8], IkeV2PayloadContent> {
+ if length < 4 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, auth_method) = map(be_u8, AuthenticationMethod)(i)?;
+ let (i, auth_data) = take(length - 4)(i)?;
+ let payload = AuthenticationPayload {
+ auth_method,
+ auth_data,
+ };
+ Ok((i, IkeV2PayloadContent::Authentication(payload)))
+}
+
+pub fn parse_ikev2_payload_nonce(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ let (i, nonce_data) = take(length)(i)?;
+ Ok((i, IkeV2PayloadContent::Nonce(NoncePayload { nonce_data })))
+}
+
+pub fn parse_ikev2_payload_notify(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ let (i, protocol_id) = map(be_u8, ProtocolID)(i)?;
+ let (i, spi_size) = be_u8(i)?;
+ let (i, notify_type) = map(be_u16, NotifyType)(i)?;
+ let (i, spi) = cond(spi_size > 0, take(spi_size))(i)?;
+ let (i, notify_data) = cond(
+ length > 8 + spi_size as u16,
+ // we have to specify a callback here to force lazy evaluation,
+ // because the function arguments are evaluated *before* the test (causing underflow)
+ |d| take(length - (8 + spi_size as u16))(d),
+ )(i)?;
+ let payload = NotifyPayload {
+ protocol_id,
+ spi_size,
+ notify_type,
+ spi,
+ notify_data,
+ };
+ Ok((i, IkeV2PayloadContent::Notify(payload)))
+}
+
+pub fn parse_ikev2_payload_vendor_id(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ if length < 8 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, vendor_id) = take(length - 8)(i)?;
+ Ok((
+ i,
+ IkeV2PayloadContent::VendorID(VendorIDPayload { vendor_id }),
+ ))
+}
+
+pub fn parse_ikev2_payload_delete(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ if length < 8 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, protocol_id) = map(be_u8, ProtocolID)(i)?;
+ let (i, spi_size) = be_u8(i)?;
+ let (i, num_spi) = be_u16(i)?;
+ let (i, spi) = take(length - 8)(i)?;
+ let payload = DeletePayload {
+ protocol_id,
+ spi_size,
+ num_spi,
+ spi,
+ };
+ Ok((i, IkeV2PayloadContent::Delete(payload)))
+}
+
+fn parse_ts_addr(i: &[u8], t: TSType) -> IResult<&[u8], &[u8]> {
+ match t {
+ TSType::IPv4AddrRange => take(4usize)(i),
+ TSType::IPv6AddrRange => take(16usize)(i),
+ _ => Err(nom::Err::Error(make_error(i, ErrorKind::Switch))),
+ }
+}
+
+fn parse_ikev2_ts(i: &[u8]) -> IResult<&[u8], TrafficSelector> {
+ let (i, ts_type) = map(be_u8, TSType)(i)?;
+ let (i, ip_proto_id) = be_u8(i)?;
+ let (i, sel_length) = be_u16(i)?;
+ let (i, start_port) = be_u16(i)?;
+ let (i, end_port) = be_u16(i)?;
+ let (i, start_addr) = parse_ts_addr(i, ts_type)?;
+ let (i, end_addr) = parse_ts_addr(i, ts_type)?;
+ let ts = TrafficSelector {
+ ts_type,
+ ip_proto_id,
+ sel_length,
+ start_port,
+ end_port,
+ start_addr,
+ end_addr,
+ };
+ Ok((i, ts))
+}
+
+pub fn parse_ikev2_payload_ts(i: &[u8], length: u16) -> IResult<&[u8], TrafficSelectorPayload> {
+ if length < 4 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, num_ts) = be_u8(i)?;
+ let (i, reserved) = take(3usize)(i)?;
+ let (i, ts) = map_parser(take(length - 4), many1(complete(parse_ikev2_ts)))(i)?;
+ let payload = TrafficSelectorPayload {
+ num_ts,
+ reserved,
+ ts,
+ };
+ Ok((i, payload))
+}
+
+pub fn parse_ikev2_payload_ts_init(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ map(
+ |d| parse_ikev2_payload_ts(d, length),
+ IkeV2PayloadContent::TSi,
+ )(i)
+}
+
+pub fn parse_ikev2_payload_ts_resp(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ map(
+ |d| parse_ikev2_payload_ts(d, length),
+ IkeV2PayloadContent::TSr,
+ )(i)
+}
+
+pub fn parse_ikev2_payload_encrypted(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ map(take(length), |d| {
+ IkeV2PayloadContent::Encrypted(EncryptedPayload(d))
+ })(i)
+}
+
+pub fn parse_ikev2_payload_unknown(i: &[u8], length: u16) -> IResult<&[u8], IkeV2PayloadContent> {
+ map(take(length), IkeV2PayloadContent::Unknown)(i)
+}
+
+#[rustfmt::skip]
+pub fn parse_ikev2_payload_with_type(
+ i: &[u8],
+ length: u16,
+ next_payload_type: IkePayloadType,
+) -> IResult<&[u8], IkeV2PayloadContent> {
+ let f = match next_payload_type {
+ // IkePayloadType::NoNextPayload => parse_ikev2_payload_unknown, // XXX ?
+ IkePayloadType::SecurityAssociation => parse_ikev2_payload_sa,
+ IkePayloadType::KeyExchange => parse_ikev2_payload_kex,
+ IkePayloadType::IdentInitiator => parse_ikev2_payload_ident_init,
+ IkePayloadType::IdentResponder => parse_ikev2_payload_ident_resp,
+ IkePayloadType::Certificate => parse_ikev2_payload_certificate,
+ IkePayloadType::CertificateRequest => parse_ikev2_payload_certificate_request,
+ IkePayloadType::Authentication => parse_ikev2_payload_authentication,
+ IkePayloadType::Nonce => parse_ikev2_payload_nonce,
+ IkePayloadType::Notify => parse_ikev2_payload_notify,
+ IkePayloadType::Delete => parse_ikev2_payload_delete,
+ IkePayloadType::VendorID => parse_ikev2_payload_vendor_id,
+ IkePayloadType::TrafficSelectorInitiator => parse_ikev2_payload_ts_init,
+ IkePayloadType::TrafficSelectorResponder => parse_ikev2_payload_ts_resp,
+ IkePayloadType::EncryptedAndAuthenticated => parse_ikev2_payload_encrypted,
+ // None => parse_ikev2_payload_unknown,
+ _ => parse_ikev2_payload_unknown,
+ // _ => panic!("unknown type {}",next_payload_type),
+ };
+ map_parser(take(length),move |d| f(d, length))(i)
+}
+
+fn parse_ikev2_payload_list_fold<'a>(
+ res_v: Result<Vec<IkeV2Payload<'a>>, IPsecError>,
+ p: IkeV2GenericPayload<'a>,
+) -> Result<Vec<IkeV2Payload<'a>>, IPsecError> {
+ let mut v = res_v?;
+ // println!("parse_payload_list_fold: v.len={} p={:?}",v.len(),p);
+ debug_assert!(!v.is_empty());
+ let last_payload = v
+ .last()
+ .expect("parse_payload_list_fold: called with empty input");
+ let next_payload_type = last_payload.hdr.next_payload_type;
+ if p.hdr.payload_length < 4 {
+ return Err(IPsecError::PayloadTooSmall);
+ }
+ match parse_ikev2_payload_with_type(p.payload, p.hdr.payload_length - 4, next_payload_type) {
+ Ok((rem, p2)) => {
+ // let (rem, p2) = parse_ikev2_payload_with_type(p.payload, p.hdr.payload_length - 4, next_payload_type)?;
+ if !rem.is_empty() {
+ return Err(IPsecError::ExtraBytesInPayload); // XXX should this be only a warning?
+ }
+ let payload = IkeV2Payload {
+ hdr: p.hdr.clone(),
+ content: p2,
+ };
+ v.push(payload);
+ Ok(v)
+ }
+ Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(IPsecError::NomError(e.code)),
+ Err(nom::Err::Incomplete(_)) => Err(IPsecError::NomError(ErrorKind::Complete)),
+ }
+}
+
+pub fn parse_ikev2_payload_list(
+ i: &[u8],
+ initial_type: IkePayloadType,
+) -> IResult<&[u8], Result<Vec<IkeV2Payload>, IPsecError>> {
+ // XXX fold manually, because fold_many1 requires accumulator to have Clone, and we don't want
+ // XXX to implement that for IkeV2Payload
+ let mut acc = Ok(vec![IkeV2Payload {
+ hdr: IkeV2PayloadHeader {
+ next_payload_type: initial_type,
+ critical: false,
+ reserved: 0,
+ payload_length: 0,
+ },
+ content: IkeV2PayloadContent::Dummy,
+ }]);
+ #[allow(clippy::clone_double_ref)]
+ let mut i = i.clone();
+ loop {
+ if i.is_empty() {
+ break;
+ }
+
+ let (rem, p) = complete(parse_ikev2_payload_generic)(i)?;
+
+ acc = parse_ikev2_payload_list_fold(acc, p);
+
+ i = rem;
+ }
+ Ok((i, acc))
+ // XXX should we split_first() the vector and return all but the first element ?
+}
+
+/// Parse an IKEv2 message
+///
+/// Parse the IKEv2 header and payload list
+#[allow(clippy::type_complexity)]
+pub fn parse_ikev2_message(
+ i: &[u8],
+) -> IResult<&[u8], (IkeV2Header, Result<Vec<IkeV2Payload>, IPsecError>)> {
+ let (i, hdr) = parse_ikev2_header(i)?;
+ if hdr.length < 28 {
+ return Err(Err::Error(make_error(i, ErrorKind::Verify)));
+ }
+ let (i, msg) = map_parser(take(hdr.length - 28), |d| {
+ parse_ikev2_payload_list(d, hdr.next_payload)
+ })(i)?;
+ Ok((i, (hdr, msg)))
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::ikev2_parser::*;
+
+ #[rustfmt::skip]
+static IKEV2_INIT_REQ: &[u8] = &[
+ 0x01, 0xf8, 0xc3, 0xd4, 0xbb, 0x77, 0x3f, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x21, 0x20, 0x22, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x48, 0x22, 0x00, 0x00, 0x30,
+ 0x00, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00, 0x04, 0x03, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x14,
+ 0x80, 0x0e, 0x00, 0x80, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x08,
+ 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1e, 0x28, 0x00, 0x00, 0x88,
+ 0x00, 0x1e, 0x00, 0x00, 0x8f, 0xe6, 0xf3, 0x6e, 0x88, 0x7b, 0x18, 0x9b, 0x5e, 0xce, 0xf2, 0x56,
+ 0xf9, 0x8d, 0x76, 0xaa, 0xcb, 0x07, 0xb3, 0xb9, 0x58, 0xee, 0x73, 0xea, 0x7b, 0x73, 0xb1, 0x04,
+ 0x7e, 0xa4, 0x2a, 0x4e, 0x44, 0x1f, 0xb9, 0x3e, 0xf9, 0xa9, 0xab, 0x0c, 0x54, 0x5a, 0xa7, 0x46,
+ 0x2e, 0x58, 0x3c, 0x06, 0xb2, 0xed, 0x91, 0x8d, 0x11, 0xca, 0x67, 0xdb, 0x21, 0x6b, 0xb8, 0xad,
+ 0xbf, 0x57, 0x3f, 0xba, 0x5a, 0xa6, 0x7d, 0x49, 0x83, 0x4b, 0xa9, 0x93, 0x6f, 0x4c, 0xe9, 0x66,
+ 0xcd, 0x57, 0x5c, 0xba, 0x07, 0x42, 0xfa, 0x0b, 0xe8, 0xb9, 0xd0, 0x25, 0xc4, 0xb9, 0xdf, 0x29,
+ 0xd7, 0xe4, 0x6e, 0xd6, 0x54, 0x78, 0xaa, 0x95, 0x02, 0xbf, 0x25, 0x55, 0x71, 0xfa, 0x9e, 0xcb,
+ 0x05, 0xea, 0x8f, 0x7b, 0x14, 0x0e, 0x1d, 0xdf, 0xb4, 0x03, 0x5f, 0x2d, 0x21, 0x66, 0x58, 0x6e,
+ 0x42, 0x72, 0x32, 0x03, 0x29, 0x00, 0x00, 0x24, 0xe3, 0x3b, 0x52, 0xaa, 0x6f, 0x6d, 0x62, 0x87,
+ 0x16, 0xd7, 0xab, 0xc6, 0x45, 0xa6, 0xcc, 0x97, 0x07, 0x43, 0x3d, 0x85, 0x83, 0xde, 0xab, 0x97,
+ 0xdb, 0xbf, 0x08, 0xce, 0x0f, 0xad, 0x59, 0x71, 0x29, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x40, 0x04,
+ 0xcc, 0xc0, 0x64, 0x5c, 0x1e, 0xeb, 0xc2, 0x1d, 0x09, 0x2b, 0xf0, 0x7f, 0xca, 0x34, 0xc3, 0xe6,
+ 0x2b, 0x20, 0xec, 0x8f, 0x29, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x40, 0x05, 0x15, 0x39, 0x75, 0x77,
+ 0xf5, 0x54, 0x87, 0xa3, 0x8f, 0xd8, 0xaf, 0x70, 0xb0, 0x9c, 0x20, 0x9c, 0xff, 0x4a, 0x37, 0xd1,
+ 0x29, 0x00, 0x00, 0x10, 0x00, 0x00, 0x40, 0x2f, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x40, 0x16
+];
+
+ #[test]
+ fn test_ikev2_init_req() {
+ let empty = &b""[..];
+ let bytes = &IKEV2_INIT_REQ[0..28];
+ let expected = Ok((
+ empty,
+ IkeV2Header {
+ init_spi: 0x01f8c3d4bb773f2f,
+ resp_spi: 0x0,
+ next_payload: IkePayloadType::SecurityAssociation,
+ maj_ver: 2,
+ min_ver: 0,
+ exch_type: IkeExchangeType::IKE_SA_INIT,
+ flags: 0x8,
+ msg_id: 0,
+ length: 328,
+ },
+ ));
+ let res = parse_ikev2_header(bytes);
+ assert_eq!(res, expected);
+ }
+
+ static IKEV2_INIT_RESP: &[u8] = include_bytes!("../assets/ike-sa-init-resp.bin");
+
+ #[test]
+ fn test_ikev2_init_resp() {
+ let bytes = IKEV2_INIT_RESP;
+ let (rem, ref hdr) = parse_ikev2_header(bytes).expect("parsing header failed");
+ let (rem2, res_p) =
+ parse_ikev2_payload_list(rem, hdr.next_payload).expect("parsing payload failed");
+ assert!(rem2.is_empty());
+ let p = res_p.expect("parsing payload failed");
+ // there are 5 items + dummy => 6
+ assert_eq!(p.len(), 6);
+ // first one is always dummy
+ assert_eq!(p[0].content, IkeV2PayloadContent::Dummy);
+ }
+
+ #[rustfmt::skip]
+static IKEV2_PAYLOAD_SA: &[u8] = &[
+ 0x22, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x01, 0x01, 0x00, 0x03, 0x03, 0x00, 0x00, 0x0c,
+ 0x01, 0x00, 0x00, 0x14, 0x80, 0x0e, 0x00, 0x80, 0x03, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1e
+];
+
+ #[test]
+ fn test_ikev2_payload_sa() {
+ let bytes = IKEV2_PAYLOAD_SA;
+ let expected1 = IkeV2GenericPayload {
+ hdr: IkeV2PayloadHeader {
+ next_payload_type: IkePayloadType::KeyExchange,
+ critical: false,
+ reserved: 0,
+ payload_length: 40,
+ },
+ payload: &bytes[4..],
+ };
+ let (_, res) = parse_ikev2_payload_generic(bytes).expect("Failed to parse");
+ assert_eq!(res, expected1);
+ let attrs1 = &[0x80, 0x0e, 0x00, 0x80];
+ let expected2 = IkeV2PayloadContent::SA(vec![IkeV2Proposal {
+ last: 0,
+ reserved: 0,
+ proposal_length: 36,
+ proposal_num: 1,
+ protocol_id: ProtocolID::IKE,
+ spi_size: 0,
+ num_transforms: 3,
+ spi: None,
+ transforms: vec![
+ IkeV2RawTransform {
+ last: 3,
+ reserved1: 0,
+ transform_length: 12,
+ transform_type: IkeTransformType::EncryptionAlgorithm,
+ reserved2: 0,
+ transform_id: 20,
+ attributes: Some(attrs1),
+ },
+ IkeV2RawTransform {
+ last: 3,
+ reserved1: 0,
+ transform_length: 8,
+ transform_type: IkeTransformType::PseudoRandomFunction,
+ reserved2: 0,
+ transform_id: 5,
+ attributes: None,
+ },
+ IkeV2RawTransform {
+ last: 0,
+ reserved1: 0,
+ transform_length: 8,
+ transform_type: IkeTransformType::DiffieHellmanGroup,
+ reserved2: 0,
+ transform_id: 30,
+ attributes: None,
+ },
+ ],
+ }]);
+
+ let (rem, res2) = parse_ikev2_payload_sa(res.payload, 0).expect("Failed to parse");
+ assert!(rem.is_empty());
+ assert_eq!(res2, expected2);
+ }
+
+ #[test]
+ fn test_ikev2_parse_payload_many() {
+ // let empty = &b""[..];
+ let bytes = &IKEV2_INIT_REQ[28..];
+ let res = parse_ikev2_payload_list(bytes, IkePayloadType::SecurityAssociation);
+ println!("{:?}", res);
+ }
+}
diff --git a/rust/vendor/ipsec-parser/src/ikev2_transforms.rs b/rust/vendor/ipsec-parser/src/ikev2_transforms.rs
new file mode 100644
index 0000000..589c996
--- /dev/null
+++ b/rust/vendor/ipsec-parser/src/ikev2_transforms.rs
@@ -0,0 +1,271 @@
+use rusticata_macros::newtype_enum;
+use std::convert::From;
+
+/// Transform (cryptographic algorithm) type
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3.2
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct IkeTransformType(pub u8);
+
+newtype_enum! {
+impl debug IkeTransformType {
+ EncryptionAlgorithm = 1,
+ PseudoRandomFunction = 2,
+ IntegrityAlgorithm = 3,
+ DiffieHellmanGroup = 4,
+ ExtendedSequenceNumbers = 5,
+}
+}
+
+/// Encryption values
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3.2
+///
+/// See also [IKEV2IANA](https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml) for the latest values.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct IkeTransformEncType(pub u16);
+
+newtype_enum! {
+impl debug IkeTransformEncType {
+ // 0 is reserved
+ ENCR_DES_IV64 = 1,
+ ENCR_DES = 2,
+ ENCR_3DES = 3,
+ ENCR_RC5 = 4,
+ ENCR_IDEA = 5,
+ ENCR_CAST = 6,
+ ENCR_BLOWFISH = 7,
+ ENCR_3IDEA = 8,
+ ENCR_DES_IV32 = 9,
+ // 10 is reserved
+ ENCR_NULL = 11,
+ ENCR_AES_CBC = 12,
+ ENCR_AES_CTR = 13,
+ ENCR_AES_CCM_8 = 14,
+ ENCR_AES_CCM_12 = 15,
+ ENCR_AES_CCM_16 = 16,
+ // 17 is unassigned
+ ENCR_AES_GCM_8 = 18,
+ ENCR_AES_GCM_12 = 19,
+ ENCR_AES_GCM_16 = 20,
+ ENCR_NULL_AUTH_AES_GMAC = 21,
+ // 22 is reserved for IEEE P1619 XTS-AES
+ ENCR_CAMELLIA_CBC = 23,
+ ENCR_CAMELLIA_CTR = 24,
+ ENCR_CAMELLIA_CCM_8 = 25,
+ ENCR_CAMELLIA_CCM_12 = 26,
+ ENCR_CAMELLIA_CCM_16 = 27,
+ ENCR_CHACHA20_POLY1305 = 28, // [RFC7634]
+}
+}
+
+impl IkeTransformEncType {
+ pub fn is_aead(self) -> bool {
+ matches!(
+ self,
+ IkeTransformEncType::ENCR_AES_CCM_8
+ | IkeTransformEncType::ENCR_AES_CCM_12
+ | IkeTransformEncType::ENCR_AES_CCM_16
+ | IkeTransformEncType::ENCR_AES_GCM_8
+ | IkeTransformEncType::ENCR_AES_GCM_12
+ | IkeTransformEncType::ENCR_AES_GCM_16
+ | IkeTransformEncType::ENCR_CAMELLIA_CCM_8
+ | IkeTransformEncType::ENCR_CAMELLIA_CCM_12
+ | IkeTransformEncType::ENCR_CAMELLIA_CCM_16
+ | IkeTransformEncType::ENCR_CHACHA20_POLY1305
+ )
+ }
+
+ pub fn is_unassigned(self) -> bool {
+ self.0 >= 23 && self.0 <= 1023
+ }
+ pub fn is_private_use(self) -> bool {
+ self.0 >= 1024
+ }
+}
+
+/// Pseudo-Random Function values
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3.2
+///
+/// See also [IKEV2IANA](https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml) for the latest values.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct IkeTransformPRFType(pub u16);
+
+newtype_enum! {
+impl debug IkeTransformPRFType {
+ PRF_NULL = 0,
+ PRF_HMAC_MD5 = 1,
+ PRF_HMAC_SHA1 = 2,
+ PRF_HMAC_TIGER = 3,
+ PRF_AES128_XCBC = 4,
+ PRF_HMAC_SHA2_256 = 5,
+ PRF_HMAC_SHA2_384 = 6,
+ PRF_HMAC_SHA2_512 = 7,
+ PRF_AES128_CMAC = 8,
+}
+}
+
+impl IkeTransformPRFType {
+ pub fn is_unassigned(self) -> bool {
+ self.0 >= 9 && self.0 <= 1023
+ }
+ pub fn is_private_use(self) -> bool {
+ self.0 >= 1024
+ }
+}
+
+/// Authentication / Integrity values
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3.2
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct IkeTransformAuthType(pub u16);
+
+newtype_enum! {
+impl debug IkeTransformAuthType {
+ NONE = 0,
+ AUTH_HMAC_MD5_96 = 1,
+ AUTH_HMAC_SHA1_96 = 2,
+ AUTH_DES_MAC = 3,
+ AUTH_KPDK_MD5 = 4,
+ AUTH_AES_XCBC_96 = 5,
+ AUTH_HMAC_MD5_128 = 6,
+ AUTH_HMAC_SHA1_160 = 7,
+ AUTH_AES_CMAC_96 = 8,
+ AUTH_AES_128_GMAC = 9,
+ AUTH_AES_192_GMAC = 10,
+ AUTH_AES_256_GMAC = 11,
+ AUTH_HMAC_SHA2_256_128 = 12,
+ AUTH_HMAC_SHA2_384_192 = 13,
+ AUTH_HMAC_SHA2_512_256 = 14,
+}
+}
+
+impl IkeTransformAuthType {
+ pub fn is_unassigned(self) -> bool {
+ self.0 >= 15 && self.0 <= 1023
+ }
+ pub fn is_private_use(self) -> bool {
+ self.0 >= 1024
+ }
+}
+
+/// Diffie-Hellman values
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3.2
+///
+/// See also [IKEV2IANA](https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml) for the latest values.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct IkeTransformDHType(pub u16);
+
+newtype_enum! {
+impl debug IkeTransformDHType {
+ None = 0,
+ Modp768 = 1,
+ Modp1024 = 2,
+ Modp1536 = 5,
+ Modp2048 = 14,
+ Modp3072 = 15,
+ Modp4096 = 16,
+ Modp6144 = 17,
+ Modp8192 = 18,
+ Ecp256 = 19,
+ Ecp384 = 20,
+ Ecp521 = 21,
+ Modp1024s160 = 22,
+ Modp2048s224 = 23,
+ Modp2048s256 = 24,
+ Ecp192 = 25,
+ Ecp224 = 26,
+ BrainpoolP224r1 = 27,
+ BrainpoolP256r1 = 28,
+ BrainpoolP384r1 = 29,
+ BrainpoolP512r1 = 30,
+ Curve25519 = 31,
+ Curve448 = 32,
+}
+}
+
+impl IkeTransformDHType {
+ pub fn is_unassigned(self) -> bool {
+ self.0 >= 15 && self.0 <= 1023
+ }
+ pub fn is_private_use(self) -> bool {
+ self.0 >= 1024
+ }
+}
+
+/// Extended Sequence Number values
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3.2
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct IkeTransformESNType(pub u16);
+
+newtype_enum! {
+impl debug IkeTransformESNType {
+ NoESN = 0,
+ ESN = 1,
+}
+}
+
+/// Raw representation of a transform (cryptographic algorithm) and parameters
+///
+/// Use the `From` method to convert it to a [`IkeV2Transform`](enum.IkeV2Transform.html)
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3
+#[derive(Clone, PartialEq)]
+pub struct IkeV2RawTransform<'a> {
+ pub last: u8,
+ pub reserved1: u8,
+ pub transform_length: u16,
+ pub transform_type: IkeTransformType,
+ pub reserved2: u8,
+ pub transform_id: u16,
+ pub attributes: Option<&'a [u8]>,
+}
+
+/// IKEv2 Transform (cryptographic algorithm)
+///
+/// This structure is a simple representation of a transform, containing only the type (encryption,
+/// etc.). To store the parameters, use [`IkeV2RawTransform`](struct.IkeV2RawTransform.html).
+///
+/// Defined in [RFC7296](https://tools.ietf.org/html/rfc7296) section 3.3
+#[derive(Debug, PartialEq)]
+pub enum IkeV2Transform {
+ Encryption(IkeTransformEncType),
+ PRF(IkeTransformPRFType),
+ Auth(IkeTransformAuthType),
+ DH(IkeTransformDHType),
+ ESN(IkeTransformESNType),
+ /// Unknown tranform (type,id)
+ Unknown(IkeTransformType, u16),
+}
+
+impl<'a> From<&'a IkeV2RawTransform<'a>> for IkeV2Transform {
+ fn from(r: &IkeV2RawTransform) -> IkeV2Transform {
+ match r.transform_type {
+ IkeTransformType::EncryptionAlgorithm => {
+ IkeV2Transform::Encryption(IkeTransformEncType(r.transform_id))
+ }
+ IkeTransformType::PseudoRandomFunction => {
+ IkeV2Transform::PRF(IkeTransformPRFType(r.transform_id))
+ }
+ IkeTransformType::IntegrityAlgorithm => {
+ IkeV2Transform::Auth(IkeTransformAuthType(r.transform_id))
+ }
+ IkeTransformType::DiffieHellmanGroup => {
+ IkeV2Transform::DH(IkeTransformDHType(r.transform_id))
+ }
+ IkeTransformType::ExtendedSequenceNumbers => {
+ IkeV2Transform::ESN(IkeTransformESNType(r.transform_id))
+ }
+ _ => IkeV2Transform::Unknown(r.transform_type, r.transform_id),
+ }
+ }
+}
+
+impl<'a> From<IkeV2RawTransform<'a>> for IkeV2Transform {
+ fn from(r: IkeV2RawTransform) -> IkeV2Transform {
+ (&r).into()
+ }
+}
diff --git a/rust/vendor/ipsec-parser/src/lib.rs b/rust/vendor/ipsec-parser/src/lib.rs
new file mode 100644
index 0000000..62ddac6
--- /dev/null
+++ b/rust/vendor/ipsec-parser/src/lib.rs
@@ -0,0 +1,80 @@
+//! # IPsec parsers
+//!
+//! This crate contains several parsers using for IPsec: IKEv2, and reading the envelope of ESP
+//! encapsulated messages.
+//! This parser provides the base functions to read and analyze messages, but does not handle the
+//! interpretation of messages.
+//!
+//! ESP is supported, but only to read the envelope of the payload.
+//!
+//! Encapsulated ESP is supported, to differentiate between IKE and ESP headers.
+//!
+//! # IKEv2 parser
+//!
+//! An IKEv2 (RFC7296) parser, implemented with the [nom](https://github.com/Geal/nom)
+//! parser combinator framework.
+//!
+//! The code is available on [Github](https://github.com/rusticata/ipsec-parser)
+//! and is part of the [Rusticata](https://github.com/rusticata) project.
+//!
+//! To parse an IKE packet, first read the header using `parse_ikev2_header`, then use the type
+//! from the header to parse the remaining part:
+//!
+//!
+//! ```rust
+//! # extern crate nom;
+//! # extern crate ipsec_parser;
+//! use ipsec_parser::*;
+//! use nom::IResult;
+//!
+//! static IKEV2_INIT_RESP: &'static [u8] = include_bytes!("../assets/ike-sa-init-resp.bin");
+//!
+//! # fn main() {
+//! fn test_ikev2_init_resp() {
+//! let bytes = IKEV2_INIT_RESP;
+//! match parse_ikev2_header(&bytes) {
+//! Ok( (rem, ref hdr) ) => {
+//! match parse_ikev2_payload_list(rem,hdr.next_payload) {
+//! Ok( (_, Ok(ref p)) ) => {
+//! // p is a list of payloads
+//! // first one is always dummy
+//! assert!(p.len() > 0);
+//! assert_eq!(p[0].content, IkeV2PayloadContent::Dummy);
+//! for payload in p {
+//! match payload.content {
+//! IkeV2PayloadContent::SA(ref sa) => { /* .. */ },
+//! _ => ()
+//! }
+//! }
+//! },
+//! e => { eprintln!("Parsing payload failed: {:?}", e); },
+//! }
+//! },
+//! _ => { eprintln!("Parsing header failed"); },
+//! }
+//! }
+//! # }
+//! ```
+
+#![deny(/*missing_docs,*/
+ unstable_features,
+ unused_import_braces, unused_qualifications)]
+#![forbid(unsafe_code)]
+
+mod error;
+mod esp;
+mod ikev2;
+mod ikev2_debug;
+mod ikev2_notify;
+mod ikev2_parser;
+mod ikev2_transforms;
+pub use error::*;
+pub use esp::*;
+pub use ikev2::*;
+pub use ikev2_debug::*;
+pub use ikev2_notify::*;
+pub use ikev2_parser::*;
+pub use ikev2_transforms::*;
+
+// re-export modules
+pub use nom;