Skip to content

Commit 7833bbe

Browse files
authored
Merge pull request #15 from smdn/ipv4-mapped-ipv6-addrs
Improve verification of IPv4-mapped IPv6 addresses in IAccessRule
2 parents 170b35e + 1748536 commit 7833bbe

File tree

4 files changed

+107
-6
lines changed

4 files changed

+107
-6
lines changed

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/AddressListAccessRule.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ namespace Smdn.Net.MuninNode;
99

1010
internal sealed class AddressListAccessRule : IAccessRule {
1111
private readonly IReadOnlyList<IPAddress> addressListAllowFrom;
12+
private readonly bool shouldConsiderIPv4MappedIPv6Address;
1213

13-
public AddressListAccessRule(IReadOnlyList<IPAddress> addressListAllowFrom)
14+
public AddressListAccessRule(
15+
IReadOnlyList<IPAddress> addressListAllowFrom,
16+
bool shouldConsiderIPv4MappedIPv6Address
17+
)
1418
{
1519
this.addressListAllowFrom = addressListAllowFrom ?? throw new ArgumentNullException(nameof(addressListAllowFrom));
20+
this.shouldConsiderIPv4MappedIPv6Address = shouldConsiderIPv4MappedIPv6Address;
1621
}
1722

1823
public bool IsAcceptable(IPEndPoint remoteEndPoint)
@@ -23,10 +28,22 @@ public bool IsAcceptable(IPEndPoint remoteEndPoint)
2328
var remoteAddress = remoteEndPoint.Address;
2429

2530
foreach (var addressAllowFrom in addressListAllowFrom) {
26-
if (addressAllowFrom.AddressFamily == AddressFamily.InterNetwork) {
27-
// test for client acceptability by IPv4 address
28-
if (remoteAddress.IsIPv4MappedToIPv6)
31+
if (shouldConsiderIPv4MappedIPv6Address) {
32+
if (
33+
remoteAddress.IsIPv4MappedToIPv6 &&
34+
addressAllowFrom.AddressFamily == AddressFamily.InterNetwork
35+
) {
36+
// test for client acceptability by IPv4 address
2937
remoteAddress = remoteAddress.MapToIPv4();
38+
}
39+
40+
if (
41+
remoteAddress.AddressFamily == AddressFamily.InterNetwork &&
42+
addressAllowFrom.AddressFamily == AddressFamily.InterNetworkV6
43+
) {
44+
// test for client acceptability by IPv6 address
45+
remoteAddress = remoteAddress.MapToIPv6();
46+
}
3047
}
3148

3249
if (addressAllowFrom.Equals(remoteAddress))

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/IAccessRuleServiceCollectionExtensions.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,29 @@ public static class IAccessRuleServiceCollectionExtensions {
1515
public static IServiceCollection AddMuninNodeAccessRule(
1616
this IServiceCollection services,
1717
IReadOnlyList<IPAddress> addressListAllowFrom
18+
)
19+
=> AddMuninNodeAccessRule(
20+
services: services,
21+
addressListAllowFrom: addressListAllowFrom ?? throw new ArgumentNullException(nameof(addressListAllowFrom)),
22+
shouldConsiderIPv4MappedIPv6Address: true
23+
);
24+
25+
/// <param name="services">The <see cref="IServiceCollection"/> to add services to.</param>
26+
/// <param name="addressListAllowFrom">The <see cref="IReadOnlyList{IPAddress}"/> indicates the read-only list of addresses allowed to access <see cref="NodeBase"/>.</param>
27+
/// <param name="shouldConsiderIPv4MappedIPv6Address">
28+
/// The value indicating whether the address resolution to be aware or not to be aware that
29+
/// the IP address is an IPv4-mapped IPv6 address when comparing IP address.
30+
/// </param>
31+
public static IServiceCollection AddMuninNodeAccessRule(
32+
this IServiceCollection services,
33+
IReadOnlyList<IPAddress> addressListAllowFrom,
34+
bool shouldConsiderIPv4MappedIPv6Address
1835
)
1936
=> AddMuninNodeAccessRule(
2037
services: services ?? throw new ArgumentNullException(nameof(services)),
2138
accessRule: new AddressListAccessRule(
22-
addressListAllowFrom: addressListAllowFrom ?? throw new ArgumentNullException(nameof(addressListAllowFrom))
39+
addressListAllowFrom: addressListAllowFrom ?? throw new ArgumentNullException(nameof(addressListAllowFrom)),
40+
shouldConsiderIPv4MappedIPv6Address: shouldConsiderIPv4MappedIPv6Address
2341
)
2442
);
2543

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/LocalNode.Create.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public static LocalNode Create(
128128
pluginProvider: pluginProvider ?? throw new ArgumentNullException(nameof(pluginProvider)),
129129
hostName: string.IsNullOrEmpty(hostName) ? DefaultHostName : hostName,
130130
port: port,
131-
accessRule: addressListAllowFrom is null ? null : new AddressListAccessRule(addressListAllowFrom),
131+
accessRule: addressListAllowFrom is null ? null : new AddressListAccessRule(addressListAllowFrom, shouldConsiderIPv4MappedIPv6Address: true),
132132
serviceProvider: serviceProvider
133133
);
134134
}

tests/Smdn.Net.MuninNode/Smdn.Net.MuninNode/IAccessRuleServiceCollectionExtensions.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,70 @@ public void AddMuninNodeAccessRule_IAccessRule_ArgumentNull()
4949
() => services.AddMuninNodeAccessRule((IAccessRule)null!)
5050
);
5151
}
52+
53+
private static System.Collections.IEnumerable YieldTestCases_AddMuninNodeAccessRule_IReadOnlyListOfIPAddress_ShouldConsiderIPv4MappedIPv6Address()
54+
{
55+
var addressIPv4 = IPAddress.Parse("192.0.2.255");
56+
var addressIPv6MappedIPv4 = IPAddress.Parse("::ffff:192.0.2.255");
57+
58+
foreach (var shouldConsiderIPv4MappedIPv6Address in new[] { true, false }) {
59+
yield return new object[] {
60+
new[] { addressIPv4 },
61+
shouldConsiderIPv4MappedIPv6Address,
62+
addressIPv6MappedIPv4,
63+
shouldConsiderIPv4MappedIPv6Address
64+
};
65+
66+
yield return new object[] {
67+
new[] { addressIPv6MappedIPv4 },
68+
shouldConsiderIPv4MappedIPv6Address,
69+
addressIPv4,
70+
shouldConsiderIPv4MappedIPv6Address
71+
};
72+
73+
yield return new object[] {
74+
new[] { addressIPv4, addressIPv6MappedIPv4 },
75+
shouldConsiderIPv4MappedIPv6Address,
76+
addressIPv6MappedIPv4,
77+
true
78+
};
79+
80+
yield return new object[] {
81+
new[] { addressIPv4, addressIPv6MappedIPv4 },
82+
shouldConsiderIPv4MappedIPv6Address,
83+
addressIPv4,
84+
true
85+
};
86+
87+
yield return new object[] {
88+
new[] { addressIPv4, addressIPv6MappedIPv4 },
89+
shouldConsiderIPv4MappedIPv6Address,
90+
IPAddress.Loopback,
91+
false
92+
};
93+
}
94+
}
95+
96+
[TestCaseSource(nameof(YieldTestCases_AddMuninNodeAccessRule_IReadOnlyListOfIPAddress_ShouldConsiderIPv4MappedIPv6Address))]
97+
public void AddMuninNodeAccessRule_IReadOnlyListOfIPAddress_ShouldConsiderIPv4MappedIPv6Address(
98+
IReadOnlyList<IPAddress> addressListAllowFrom,
99+
bool shouldConsiderIPv4MappedIPv6Address,
100+
IPAddress remoteAddress,
101+
bool expected
102+
)
103+
{
104+
var services = new ServiceCollection();
105+
106+
services.AddMuninNodeAccessRule(
107+
addressListAllowFrom: addressListAllowFrom,
108+
shouldConsiderIPv4MappedIPv6Address: shouldConsiderIPv4MappedIPv6Address
109+
);
110+
111+
var accessRule = services.BuildServiceProvider().GetRequiredService<IAccessRule>();
112+
113+
Assert.That(
114+
accessRule.IsAcceptable(new(remoteAddress, port: 0)),
115+
Is.EqualTo(expected)
116+
);
117+
}
52118
}

0 commit comments

Comments
 (0)