1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.handler.ipfilter;
17
18 import io.netty5.util.NetUtil;
19 import io.netty5.util.internal.SocketUtils;
20
21 import java.math.BigInteger;
22 import java.net.Inet4Address;
23 import java.net.Inet6Address;
24 import java.net.InetAddress;
25 import java.net.InetSocketAddress;
26 import java.net.UnknownHostException;
27
28 import static java.util.Objects.requireNonNull;
29
30
31
32
33
34 public final class IpSubnetFilterRule implements IpFilterRule, Comparable<IpSubnetFilterRule> {
35
36 private final IpFilterRule filterRule;
37 private final String ipAddress;
38
39 public IpSubnetFilterRule(String ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
40 try {
41 this.ipAddress = ipAddress;
42 filterRule = selectFilterRule(SocketUtils.addressByName(ipAddress), cidrPrefix, ruleType);
43 } catch (UnknownHostException e) {
44 throw new IllegalArgumentException("ipAddress", e);
45 }
46 }
47
48 public IpSubnetFilterRule(InetAddress ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
49 this.ipAddress = ipAddress.getHostAddress();
50 filterRule = selectFilterRule(ipAddress, cidrPrefix, ruleType);
51 }
52
53 private static IpFilterRule selectFilterRule(InetAddress ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
54 requireNonNull(ipAddress, "ipAddress");
55 requireNonNull(ruleType, "ruleType");
56
57 if (ipAddress instanceof Inet4Address) {
58 return new Ip4SubnetFilterRule((Inet4Address) ipAddress, cidrPrefix, ruleType);
59 } else if (ipAddress instanceof Inet6Address) {
60 return new Ip6SubnetFilterRule((Inet6Address) ipAddress, cidrPrefix, ruleType);
61 } else {
62 throw new IllegalArgumentException("Only IPv4 and IPv6 addresses are supported");
63 }
64 }
65
66 @Override
67 public boolean matches(InetSocketAddress remoteAddress) {
68 return filterRule.matches(remoteAddress);
69 }
70
71 @Override
72 public IpFilterRuleType ruleType() {
73 return filterRule.ruleType();
74 }
75
76
77
78
79 String getIpAddress() {
80 return ipAddress;
81 }
82
83
84
85
86 IpFilterRule getFilterRule() {
87 return filterRule;
88 }
89
90 @Override
91 public int compareTo(IpSubnetFilterRule ipSubnetFilterRule) {
92 if (filterRule instanceof Ip4SubnetFilterRule) {
93 return Integer.compare(((Ip4SubnetFilterRule) filterRule).networkAddress,
94 ((Ip4SubnetFilterRule) ipSubnetFilterRule.filterRule).networkAddress);
95 } else {
96 return ((Ip6SubnetFilterRule) filterRule).networkAddress
97 .compareTo(((Ip6SubnetFilterRule) ipSubnetFilterRule.filterRule).networkAddress);
98 }
99 }
100
101
102
103
104
105
106
107
108 int compareTo(InetSocketAddress inetSocketAddress) {
109 if (filterRule instanceof Ip4SubnetFilterRule) {
110 Ip4SubnetFilterRule ip4SubnetFilterRule = (Ip4SubnetFilterRule) filterRule;
111 return Integer.compare(ip4SubnetFilterRule.networkAddress, NetUtil.ipv4AddressToInt((Inet4Address)
112 inetSocketAddress.getAddress()) & ip4SubnetFilterRule.subnetMask);
113 } else {
114 Ip6SubnetFilterRule ip6SubnetFilterRule = (Ip6SubnetFilterRule) filterRule;
115 return ip6SubnetFilterRule.networkAddress
116 .compareTo(Ip6SubnetFilterRule.ipToInt((Inet6Address) inetSocketAddress.getAddress())
117 .and(ip6SubnetFilterRule.networkAddress));
118 }
119 }
120
121 static final class Ip4SubnetFilterRule implements IpFilterRule {
122
123 private final int networkAddress;
124 private final int subnetMask;
125 private final IpFilterRuleType ruleType;
126
127 private Ip4SubnetFilterRule(Inet4Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
128 if (cidrPrefix < 0 || cidrPrefix > 32) {
129 throw new IllegalArgumentException(String.format("IPv4 requires the subnet prefix to be in range of "
130 + "[0,32]. The prefix was: %d", cidrPrefix));
131 }
132
133 subnetMask = prefixToSubnetMask(cidrPrefix);
134 networkAddress = NetUtil.ipv4AddressToInt(ipAddress) & subnetMask;
135 this.ruleType = ruleType;
136 }
137
138 @Override
139 public boolean matches(InetSocketAddress remoteAddress) {
140 final InetAddress inetAddress = remoteAddress.getAddress();
141 if (inetAddress instanceof Inet4Address) {
142 int ipAddress = NetUtil.ipv4AddressToInt((Inet4Address) inetAddress);
143 return (ipAddress & subnetMask) == networkAddress;
144 }
145 return false;
146 }
147
148 @Override
149 public IpFilterRuleType ruleType() {
150 return ruleType;
151 }
152
153 private static int prefixToSubnetMask(int cidrPrefix) {
154
155
156
157
158
159
160
161
162
163
164 return (int) (-1L << 32 - cidrPrefix);
165 }
166 }
167
168 static final class Ip6SubnetFilterRule implements IpFilterRule {
169
170 private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1);
171
172 private final BigInteger networkAddress;
173 private final BigInteger subnetMask;
174 private final IpFilterRuleType ruleType;
175
176 private Ip6SubnetFilterRule(Inet6Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
177 if (cidrPrefix < 0 || cidrPrefix > 128) {
178 throw new IllegalArgumentException(String.format("IPv6 requires the subnet prefix to be in range of "
179 + "[0,128]. The prefix was: %d", cidrPrefix));
180 }
181
182 subnetMask = prefixToSubnetMask(cidrPrefix);
183 networkAddress = ipToInt(ipAddress).and(subnetMask);
184 this.ruleType = ruleType;
185 }
186
187 @Override
188 public boolean matches(InetSocketAddress remoteAddress) {
189 final InetAddress inetAddress = remoteAddress.getAddress();
190 if (inetAddress instanceof Inet6Address) {
191 BigInteger ipAddress = ipToInt((Inet6Address) inetAddress);
192 return ipAddress.and(subnetMask).equals(subnetMask) || ipAddress.and(subnetMask).equals(networkAddress);
193 }
194 return false;
195 }
196
197 @Override
198 public IpFilterRuleType ruleType() {
199 return ruleType;
200 }
201
202 private static BigInteger ipToInt(Inet6Address ipAddress) {
203 byte[] octets = ipAddress.getAddress();
204 assert octets.length == 16;
205
206 return new BigInteger(octets);
207 }
208
209 private static BigInteger prefixToSubnetMask(int cidrPrefix) {
210 return MINUS_ONE.shiftLeft(128 - cidrPrefix);
211 }
212 }
213 }