diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-10-11 10:06:35 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-10-11 10:06:35 +0200 |
| commit | 9c3b434bd4a087a15a98e67d270efb3f50fddb20 (patch) | |
| tree | ee91bc405287a57b83c44eebb911524e986ea3f6 | |
| parent | 6aa2b5ce21d3b3f740ed241b5f659b022e4f9790 (diff) | |
| parent | 2d31b521c6807f3f71562bda1963872f11797295 (diff) | |
| download | mullvadvpn-9c3b434bd4a087a15a98e67d270efb3f50fddb20.tar.xz mullvadvpn-9c3b434bd4a087a15a98e67d270efb3f50fddb20.zip | |
Merge branch 'win-fix-fw-ndp'
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | Cargo.lock | 4 | ||||
| -rw-r--r-- | docs/security.md | 15 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid-core/src/firewall/linux.rs | 98 | ||||
| -rw-r--r-- | talpid-core/src/firewall/macos.rs | 106 | ||||
| -rw-r--r-- | talpid-core/src/firewall/mod.rs | 1 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/mullvadguids.cpp | 60 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/mullvadguids.h | 4 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/rules/baseline/permitndp.cpp | 97 |
10 files changed, 321 insertions, 68 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e3d205723..517944c068 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,8 @@ Line wrap the file at 100 chars. Th - Read macOS scrollbar visibility settings to decide wheter or not the scrollbars should hide when not scrolling. - Fix desktop app showing a future date for when WireGuard key was generated. +- Fix IPv6 connections to WireGuard servers by not dropping select neighbor advertisements and + solicitations. #### Linux - Make offline monitor aware of routing table changes. diff --git a/Cargo.lock b/Cargo.lock index ee564d9d2f..a0ed359d31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1737,9 +1737,9 @@ dependencies = [ [[package]] name = "pfctl" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d091ecb01c905b5a31757cd43a6d00b484c835831e41e8b20385dec08514fc" +checksum = "52063325d6b0de17051e72275d44f96c5b73a75029fcdd7e05e54a62ff216437" dependencies = [ "derive_builder", "errno", diff --git a/docs/security.md b/docs/security.md index c34a7d73a0..2f0b09e31c 100644 --- a/docs/security.md +++ b/docs/security.md @@ -64,10 +64,14 @@ The following network traffic is allowed or blocked independent of state: server) * Incoming UDP from `[fe80::]/10:547` to `[fe80::]/10:546` (server to client) -1. Router solicitation, advertisement and redirects (subset of NDP) is always allowed: +1. A subset of NDP is allowed: * Outgoing to `ff02::2`, but only ICMPv6 with type 133 and code 0 (Router solicitation) - * Incoming from `[fe80::]/10`, but only ICMPv6 type 134 and code 0 (Router advertisement) - * Incoming from `[fe80::]/10`, but only ICMPv6 type 137 and code 0 (Redirect) + * Incoming from `fe80::/10`, but only ICMPv6 type 134 and code 0 (Router advertisement) + * Incoming from `fe80::/10`, but only ICMPv6 type 137 and code 0 (Redirect) + * Outgoing to `ff02::1:ff00:0/104` and `fe80::/10`, but only ICMPv6 with type 135 and code 0 (Neighbor solicitation). + * Incoming from `fe80::/10`, but only ICMPv6 with type 135 and code 0 (Neighbor solicitation). + * Outgoing to `fe80::/10`, but only ICMPv6 with type 136 and code 0 (Neighbor advertisement). + * Incoming from `*`, but only ICMPv6 with type 136 and code 0 (Neighbor advertisement). 1. If the "Allow LAN" setting is enabled, the following is also allowed: * Outgoing to, and incoming from, any IP in an unroutable network, that means: @@ -95,11 +99,6 @@ The following network traffic is allowed or blocked independent of state: On Linux, any situation that permits incoming or outgoing traffic also allows that traffic to be forwarded. All other forward traffic is rejected. -#### macOS deviations - -* The app does not look at ICMPv6 type and code headers. So all ICMPv6 is allowed between the - specified IP networks. - ### Disconnected This is the default state that the `mullvad-daemon` starts in when the device boots, unless diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index f8ebc64564..21c308f1ac 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -68,7 +68,7 @@ internet-checksum = "0.2" [target.'cfg(target_os = "macos")'.dependencies] -pfctl = "0.4.1" +pfctl = "0.4.4" system-configuration = "0.4" tun = "0.5.1" diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs index 674a95c9b6..f584df4475 100644 --- a/talpid-core/src/firewall/linux.rs +++ b/talpid-core/src/firewall/linux.rs @@ -319,6 +319,7 @@ impl<'a> PolicyBatch<'a> { self.add_loopback_rules()?; self.add_split_tunneling_rules(policy)?; self.add_dhcp_client_rules(); + self.add_ndp_rules(); self.add_policy_specific_rules(policy)?; Ok(self.batch.finalize()) @@ -480,6 +481,9 @@ impl<'a> PolicyBatch<'a> { add_verdict(&mut in_v6, &Verdict::Accept); self.batch.add(&in_v6, nftnl::MsgType::Add); } + } + + fn add_ndp_rules(&mut self) { // Outgoing Router solicitation (part of NDP) for chain in &[&self.out_chain, &self.forward_chain] { let mut rule = Rule::new(chain); @@ -488,19 +492,7 @@ impl<'a> PolicyBatch<'a> { End::Dst, *super::ROUTER_SOLICITATION_OUT_DST_ADDR, ); - - rule.add_expr(&nft_expr!(meta l4proto)); - rule.add_expr(&nft_expr!(cmp == libc::IPPROTO_ICMPV6 as u8)); - - rule.add_expr(&Payload::Transport( - nftnl::expr::TransportHeaderField::Icmpv6(nftnl::expr::Icmpv6HeaderField::Type), - )); - rule.add_expr(&nft_expr!(cmp == 133u8)); - rule.add_expr(&nftnl::expr::Payload::Transport( - nftnl::expr::TransportHeaderField::Icmpv6(nftnl::expr::Icmpv6HeaderField::Code), - )); - rule.add_expr(&nft_expr!(cmp == 0u8)); - + check_icmpv6(&mut rule, 133, 0); add_verdict(&mut rule, &Verdict::Accept); self.batch.add(&rule, nftnl::MsgType::Add); } @@ -508,19 +500,7 @@ impl<'a> PolicyBatch<'a> { for chain in &[&self.in_chain, &self.forward_chain] { let mut rule = Rule::new(chain); check_net(&mut rule, End::Src, *super::IPV6_LINK_LOCAL); - - rule.add_expr(&nft_expr!(meta l4proto)); - rule.add_expr(&nft_expr!(cmp == libc::IPPROTO_ICMPV6 as u8)); - - rule.add_expr(&Payload::Transport( - nftnl::expr::TransportHeaderField::Icmpv6(nftnl::expr::Icmpv6HeaderField::Type), - )); - rule.add_expr(&nft_expr!(cmp == 134u8)); - rule.add_expr(&nftnl::expr::Payload::Transport( - nftnl::expr::TransportHeaderField::Icmpv6(nftnl::expr::Icmpv6HeaderField::Code), - )); - rule.add_expr(&nft_expr!(cmp == 0u8)); - + check_icmpv6(&mut rule, 134, 0); add_verdict(&mut rule, &Verdict::Accept); self.batch.add(&rule, nftnl::MsgType::Add); } @@ -528,19 +508,45 @@ impl<'a> PolicyBatch<'a> { for chain in &[&self.in_chain, &self.forward_chain] { let mut rule = Rule::new(chain); check_net(&mut rule, End::Src, *super::IPV6_LINK_LOCAL); - - rule.add_expr(&nft_expr!(meta l4proto)); - rule.add_expr(&nft_expr!(cmp == libc::IPPROTO_ICMPV6 as u8)); - - rule.add_expr(&Payload::Transport( - nftnl::expr::TransportHeaderField::Icmpv6(nftnl::expr::Icmpv6HeaderField::Type), - )); - rule.add_expr(&nft_expr!(cmp == 137u8)); - rule.add_expr(&nftnl::expr::Payload::Transport( - nftnl::expr::TransportHeaderField::Icmpv6(nftnl::expr::Icmpv6HeaderField::Code), - )); - rule.add_expr(&nft_expr!(cmp == 0u8)); - + check_icmpv6(&mut rule, 137, 0); + add_verdict(&mut rule, &Verdict::Accept); + self.batch.add(&rule, nftnl::MsgType::Add); + } + // Outgoing Neighbor solicitation (part of NDP) + for chain in &[&self.out_chain, &self.forward_chain] { + let mut rule = Rule::new(chain); + check_net(&mut rule, End::Dst, *super::SOLICITED_NODE_MULTICAST); + check_icmpv6(&mut rule, 135, 0); + add_verdict(&mut rule, &Verdict::Accept); + self.batch.add(&rule, nftnl::MsgType::Add); + } + for chain in &[&self.out_chain, &self.forward_chain] { + let mut rule = Rule::new(chain); + check_net(&mut rule, End::Dst, *super::IPV6_LINK_LOCAL); + check_icmpv6(&mut rule, 135, 0); + add_verdict(&mut rule, &Verdict::Accept); + self.batch.add(&rule, nftnl::MsgType::Add); + } + // Incoming Neighbor solicitation (part of NDP) + for chain in &[&self.in_chain, &self.forward_chain] { + let mut rule = Rule::new(chain); + check_net(&mut rule, End::Src, *super::IPV6_LINK_LOCAL); + check_icmpv6(&mut rule, 135, 0); + add_verdict(&mut rule, &Verdict::Accept); + self.batch.add(&rule, nftnl::MsgType::Add); + } + // Outgoing Neighbor advertisement (part of NDP) + for chain in &[&self.out_chain, &self.forward_chain] { + let mut rule = Rule::new(chain); + check_net(&mut rule, End::Dst, *super::IPV6_LINK_LOCAL); + check_icmpv6(&mut rule, 136, 0); + add_verdict(&mut rule, &Verdict::Accept); + self.batch.add(&rule, nftnl::MsgType::Add); + } + // Incoming Neighbor advertisement (part of NDP) + for chain in &[&self.in_chain, &self.forward_chain] { + let mut rule = Rule::new(chain); + check_icmpv6(&mut rule, 136, 0); add_verdict(&mut rule, &Verdict::Accept); self.batch.add(&rule, nftnl::MsgType::Add); } @@ -934,6 +940,20 @@ fn check_net(rule: &mut Rule<'_>, end: End, net: impl Into<IpNetwork>) { rule.add_expr(&nft_expr!(cmp == net.ip())); } +fn check_icmpv6(rule: &mut Rule<'_>, r#type: u8, code: u8) { + rule.add_expr(&nft_expr!(meta l4proto)); + rule.add_expr(&nft_expr!(cmp == libc::IPPROTO_ICMPV6 as u8)); + + rule.add_expr(&Payload::Transport( + nftnl::expr::TransportHeaderField::Icmpv6(nftnl::expr::Icmpv6HeaderField::Type), + )); + rule.add_expr(&nft_expr!(cmp == r#type)); + rule.add_expr(&nftnl::expr::Payload::Transport( + nftnl::expr::TransportHeaderField::Icmpv6(nftnl::expr::Icmpv6HeaderField::Code), + )); + rule.add_expr(&nft_expr!(cmp == code)); +} + fn check_endpoint(rule: &mut Rule<'_>, end: End, endpoint: &Endpoint) { check_ip(rule, end, endpoint.address.ip()); check_port(rule, endpoint.protocol, end, endpoint.address.port()); diff --git a/talpid-core/src/firewall/macos.rs b/talpid-core/src/firewall/macos.rs index 1a899279ed..4057d03a05 100644 --- a/talpid-core/src/firewall/macos.rs +++ b/talpid-core/src/firewall/macos.rs @@ -70,6 +70,7 @@ impl Firewall { new_filter_rules.append(&mut self.get_allow_loopback_rules()?); new_filter_rules.append(&mut self.get_allow_dhcp_client_rules()?); + new_filter_rules.append(&mut self.get_allow_ndp_rules()?); new_filter_rules.append(&mut self.get_policy_specific_rules(policy)?); let return_out_rule = self @@ -420,23 +421,96 @@ impl Firewall { .build()?; rules.push(allow_incoming_dhcp_v6); - // NDP (router solicitation, advertisement and redirect) - let allow_router_solicitation = self - .create_rule_builder(FilterRuleAction::Pass) - .quick(true) - .proto(pfctl::Proto::IcmpV6) - .direction(pfctl::Direction::Out) - .to(*super::ROUTER_SOLICITATION_OUT_DST_ADDR) - .build()?; - let allow_router_advertisement_and_redirect = self - .create_rule_builder(FilterRuleAction::Pass) + Ok(rules) + } + + fn get_allow_ndp_rules(&self) -> Result<Vec<pfctl::FilterRule>> { + let mut ndp_rule_builder = self.create_rule_builder(FilterRuleAction::Pass); + ndp_rule_builder .quick(true) - .proto(pfctl::Proto::IcmpV6) - .direction(pfctl::Direction::In) - .from(pfctl::Ip::from(IpNetwork::V6(*super::IPV6_LINK_LOCAL))) - .build()?; - rules.push(allow_router_solicitation); - rules.push(allow_router_advertisement_and_redirect); + .af(pfctl::AddrFamily::Ipv6) + .proto(pfctl::Proto::IcmpV6); + + let mut rules = Vec::new(); + + // Outgoing router solicitation to `ff02::2` + rules.push( + ndp_rule_builder + .clone() + .direction(pfctl::Direction::Out) + .icmp_type(pfctl::IcmpType::Icmp6(pfctl::Icmp6Type::RouterSol)) + .to(*super::ROUTER_SOLICITATION_OUT_DST_ADDR) + .build()?, + ); + + // Incoming router advertisement from `fe80::/10` + rules.push( + ndp_rule_builder + .clone() + .direction(pfctl::Direction::In) + .icmp_type(pfctl::IcmpType::Icmp6(pfctl::Icmp6Type::RouterAdv)) + .from(pfctl::Ip::from(IpNetwork::V6(*super::IPV6_LINK_LOCAL))) + .build()?, + ); + + // Incoming Redirect from `fe80::/10` + rules.push( + ndp_rule_builder + .clone() + .direction(pfctl::Direction::In) + .icmp_type(pfctl::IcmpType::Icmp6(pfctl::Icmp6Type::Redir)) + .from(pfctl::Ip::from(IpNetwork::V6(*super::IPV6_LINK_LOCAL))) + .build()?, + ); + + // Outgoing neighbor solicitation to `ff02::1:ff00:0/104` and `fe80::/10` + rules.push( + ndp_rule_builder + .clone() + .direction(pfctl::Direction::Out) + .icmp_type(pfctl::IcmpType::Icmp6(pfctl::Icmp6Type::NeighbrSol)) + .to(pfctl::Ip::from(IpNetwork::V6( + *super::SOLICITED_NODE_MULTICAST, + ))) + .build()?, + ); + rules.push( + ndp_rule_builder + .clone() + .direction(pfctl::Direction::Out) + .icmp_type(pfctl::IcmpType::Icmp6(pfctl::Icmp6Type::NeighbrSol)) + .to(pfctl::Ip::from(IpNetwork::V6(*super::IPV6_LINK_LOCAL))) + .build()?, + ); + + // Incoming neighbor solicitation from `fe80::/10` + rules.push( + ndp_rule_builder + .clone() + .direction(pfctl::Direction::In) + .icmp_type(pfctl::IcmpType::Icmp6(pfctl::Icmp6Type::NeighbrSol)) + .from(pfctl::Ip::from(IpNetwork::V6(*super::IPV6_LINK_LOCAL))) + .build()?, + ); + + // Outgoing neigbor advertisement to fe80::/10` + rules.push( + ndp_rule_builder + .clone() + .direction(pfctl::Direction::Out) + .icmp_type(pfctl::IcmpType::Icmp6(pfctl::Icmp6Type::NeighbrAdv)) + .to(pfctl::Ip::from(IpNetwork::V6(*super::IPV6_LINK_LOCAL))) + .build()?, + ); + + // Incoming neigbor advertisement from anywhere + rules.push( + ndp_rule_builder + .clone() + .direction(pfctl::Direction::In) + .icmp_type(pfctl::IcmpType::Icmp6(pfctl::Icmp6Type::NeighbrAdv)) + .build()?, + ); Ok(rules) } diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs index 557ae01412..e3ece0cbfe 100644 --- a/talpid-core/src/firewall/mod.rs +++ b/talpid-core/src/firewall/mod.rs @@ -67,6 +67,7 @@ lazy_static! { Ipv6Addr::new(0xff05, 0, 0, 0, 0, 0, 1, 3), ]; static ref ROUTER_SOLICITATION_OUT_DST_ADDR: Ipv6Addr = Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 2); + static ref SOLICITED_NODE_MULTICAST: Ipv6Network = Ipv6Network::new(Ipv6Addr::new(0xff02, 0, 0, 0, 0, 1, 0xFF00, 0), 104).unwrap(); static ref LOOPBACK_NETS: [IpNetwork; 2] = [ IpNetwork::V4(ipnetwork::Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 0), 8).unwrap()), IpNetwork::V6(ipnetwork::Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 128).unwrap()), diff --git a/windows/winfw/src/winfw/mullvadguids.cpp b/windows/winfw/src/winfw/mullvadguids.cpp index f5693d7751..8a9de5fe0f 100644 --- a/windows/winfw/src/winfw/mullvadguids.cpp +++ b/windows/winfw/src/winfw/mullvadguids.cpp @@ -136,6 +136,10 @@ MullvadGuids::DetailedIdentityRegistry MullvadGuids::DetailedRegistry(IdentityQu registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitVpnTunnelService_Ipv6())); registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitNdp_Outbound_Router_Solicitation())); registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitNdp_Inbound_Router_Advertisement())); + registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitNdp_Outbound_Neighbor_Solicitation())); + registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitNdp_Inbound_Neighbor_Solicitation())); + registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitNdp_Outbound_Neighbor_Advertisement())); + registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitNdp_Inbound_Neighbor_Advertisement())); registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitNdp_Inbound_Redirect())); registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitDns_Outbound_Ipv4())); registry.insert(std::make_pair(WfpObjectType::Filter, Filter_Baseline_PermitDns_Outbound_Ipv6())); @@ -741,6 +745,62 @@ const GUID &MullvadGuids::Filter_Baseline_PermitNdp_Inbound_Router_Advertisement } //static +const GUID &MullvadGuids::Filter_Baseline_PermitNdp_Outbound_Neighbor_Solicitation() +{ + static const GUID g = + { + 0x8cc5348a, + 0xf736, + 0x4ec4, + { 0x8e, 0x8f, 0xd7, 0x13, 0x17, 0xd4, 0xc2, 0xb8 } + }; + + return g; +} + +//static +const GUID &MullvadGuids::Filter_Baseline_PermitNdp_Inbound_Neighbor_Solicitation() +{ + static const GUID g = + { + 0x0c95bb19, + 0x40a2, + 0x48ee, + { 0xa7, 0xca, 0x5b, 0x61, 0x2c, 0xab, 0x5f, 0x9d } + }; + + return g; +} + +//static +const GUID &MullvadGuids::Filter_Baseline_PermitNdp_Outbound_Neighbor_Advertisement() +{ + static const GUID g = + { + 0x932042c4, + 0x2275, + 0x4c3e, + { 0x85, 0xe8, 0xf9, 0xa2, 0x77, 0x18, 0x19, 0x5c } + }; + + return g; +} + +//static +const GUID &MullvadGuids::Filter_Baseline_PermitNdp_Inbound_Neighbor_Advertisement() +{ + static const GUID g = + { + 0xc0e39478, + 0x7920, + 0x4632, + { 0x82, 0x12, 0x2a, 0xe5, 0xd2, 0x6f, 0x39, 0x5c } + }; + + return g; +} + +//static const GUID &MullvadGuids::Filter_Baseline_PermitNdp_Inbound_Redirect() { static const GUID g = diff --git a/windows/winfw/src/winfw/mullvadguids.h b/windows/winfw/src/winfw/mullvadguids.h index f8b9fbb770..ed064a9409 100644 --- a/windows/winfw/src/winfw/mullvadguids.h +++ b/windows/winfw/src/winfw/mullvadguids.h @@ -79,6 +79,10 @@ public: static const GUID &Filter_Baseline_PermitNdp_Outbound_Router_Solicitation(); static const GUID &Filter_Baseline_PermitNdp_Inbound_Router_Advertisement(); + static const GUID &Filter_Baseline_PermitNdp_Outbound_Neighbor_Solicitation(); + static const GUID &Filter_Baseline_PermitNdp_Inbound_Neighbor_Solicitation(); + static const GUID &Filter_Baseline_PermitNdp_Outbound_Neighbor_Advertisement(); + static const GUID &Filter_Baseline_PermitNdp_Inbound_Neighbor_Advertisement(); static const GUID &Filter_Baseline_PermitNdp_Inbound_Redirect(); static const GUID &Filter_Baseline_PermitDns_Outbound_Ipv4(); diff --git a/windows/winfw/src/winfw/rules/baseline/permitndp.cpp b/windows/winfw/src/winfw/rules/baseline/permitndp.cpp index 60c95ec8e9..3c5bb32d76 100644 --- a/windows/winfw/src/winfw/rules/baseline/permitndp.cpp +++ b/windows/winfw/src/winfw/rules/baseline/permitndp.cpp @@ -18,6 +18,7 @@ bool PermitNdp::apply(IObjectInstaller &objectInstaller) { const wfp::IpNetwork linkLocal(wfp::IpAddress::Literal6({ 0xFE80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }), 10); const wfp::IpAddress::Literal6 linkLocalRouterMulticast{ 0xFF02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 }; + const wfp::IpNetwork solicitedNodeMulticast(wfp::IpAddress::Literal6({ 0xFF02, 0, 0, 0, 0, 1, 0xFF00, 0 }), 104); wfp::FilterBuilder filterBuilder; @@ -81,12 +82,104 @@ bool PermitNdp::apply(IObjectInstaller &objectInstaller) .name(L"Permit inbound NDP redirect") .layer(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); + { + wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); + + conditionBuilder.add_condition(ConditionProtocol::IcmpV6()); + conditionBuilder.add_condition(ConditionIcmp::Type(137)); + conditionBuilder.add_condition(ConditionIcmp::Code(0)); + conditionBuilder.add_condition(ConditionIp::Remote(linkLocal)); + + if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) + { + return false; + } + } + + // + // #4 Permit outbound neighbor solicitation. + // + + filterBuilder + .key(MullvadGuids::Filter_Baseline_PermitNdp_Outbound_Neighbor_Solicitation()) + .name(L"Permit outbound NDP neighbor solicitation") + .layer(FWPM_LAYER_ALE_AUTH_CONNECT_V6); + + { + wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V6); + + conditionBuilder.add_condition(ConditionProtocol::IcmpV6()); + conditionBuilder.add_condition(ConditionIcmp::Type(135)); + conditionBuilder.add_condition(ConditionIcmp::Code(0)); + conditionBuilder.add_condition(ConditionIp::Remote(solicitedNodeMulticast)); + conditionBuilder.add_condition(ConditionIp::Remote(linkLocal)); + + if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) + { + return false; + } + } + + // + // #5 Permit inbound neighbor solicitation. + // + + filterBuilder + .key(MullvadGuids::Filter_Baseline_PermitNdp_Inbound_Neighbor_Solicitation()) + .name(L"Permit inbound NDP neighbor solicitation") + .layer(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); + + { + wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); + + conditionBuilder.add_condition(ConditionProtocol::IcmpV6()); + conditionBuilder.add_condition(ConditionIcmp::Type(135)); + conditionBuilder.add_condition(ConditionIcmp::Code(0)); + conditionBuilder.add_condition(ConditionIp::Remote(linkLocal)); + + if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) + { + return false; + } + } + + // + // #6 Permit outbound neighbor advertisement. + // + + filterBuilder + .key(MullvadGuids::Filter_Baseline_PermitNdp_Outbound_Neighbor_Advertisement()) + .name(L"Permit outbound NDP neighbor advertisement") + .layer(FWPM_LAYER_ALE_AUTH_CONNECT_V6); + + { + wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_CONNECT_V6); + + conditionBuilder.add_condition(ConditionProtocol::IcmpV6()); + conditionBuilder.add_condition(ConditionIcmp::Type(136)); + conditionBuilder.add_condition(ConditionIcmp::Code(0)); + conditionBuilder.add_condition(ConditionIp::Remote(linkLocal)); + + if (!objectInstaller.addFilter(filterBuilder, conditionBuilder)) + { + return false; + } + } + + // + // #7 Permit inbound neighbor advertisement. + // + + filterBuilder + .key(MullvadGuids::Filter_Baseline_PermitNdp_Inbound_Neighbor_Advertisement()) + .name(L"Permit inbound NDP neighbor advertisement") + .layer(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); + wfp::ConditionBuilder conditionBuilder(FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6); conditionBuilder.add_condition(ConditionProtocol::IcmpV6()); - conditionBuilder.add_condition(ConditionIcmp::Type(137)); + conditionBuilder.add_condition(ConditionIcmp::Type(136)); conditionBuilder.add_condition(ConditionIcmp::Code(0)); - conditionBuilder.add_condition(ConditionIp::Remote(linkLocal)); return objectInstaller.addFilter(filterBuilder, conditionBuilder); } |
