1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ipfilter;
17
18 import io.netty.util.NetUtil;
19 import io.netty.util.internal.ObjectUtil;
20 import io.netty.util.internal.SocketUtils;
21
22 import java.math.BigInteger;
23 import java.net.Inet4Address;
24 import java.net.Inet6Address;
25 import java.net.InetAddress;
26 import java.net.InetSocketAddress;
27 import java.net.UnknownHostException;
28
29
30
31
32
33 public final class IpSubnetFilterRule implements IpFilterRule, Comparable<IpSubnetFilterRule> {
34
35 private final IpFilterRule filterRule;
36 private final String ipAddress;
37
38
39
40
41
42
43
44 public IpSubnetFilterRule(String ipAddressWithCidr, IpFilterRuleType ruleType) {
45 try {
46 String[] ipAndCidr = ipAddressWithCidr.split("/");
47 if (ipAndCidr.length != 2) {
48 throw new IllegalArgumentException("ipAddressWithCidr: " + ipAddressWithCidr +
49 " (expected: \"<ip-address>/<mask-size>\")");
50 }
51
52 ipAddress = ipAndCidr[0];
53 int cidrPrefix = Integer.parseInt(ipAndCidr[1]);
54 filterRule = selectFilterRule(SocketUtils.addressByName(ipAddress), cidrPrefix, ruleType);
55 } catch (UnknownHostException e) {
56 throw new IllegalArgumentException("ipAddressWithCidr", e);
57 }
58 }
59
60
61
62
63
64
65
66
67 public IpSubnetFilterRule(String ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
68 try {
69 this.ipAddress = ipAddress;
70 filterRule = selectFilterRule(SocketUtils.addressByName(ipAddress), cidrPrefix, ruleType);
71 } catch (UnknownHostException e) {
72 throw new IllegalArgumentException("ipAddress", e);
73 }
74 }
75
76
77
78
79
80
81
82
83 public IpSubnetFilterRule(InetAddress ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
84 this.ipAddress = ipAddress.getHostAddress();
85 filterRule = selectFilterRule(ipAddress, cidrPrefix, ruleType);
86 }
87
88 private static IpFilterRule selectFilterRule(InetAddress ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
89 ObjectUtil.checkNotNull(ipAddress, "ipAddress");
90 ObjectUtil.checkNotNull(ruleType, "ruleType");
91
92 if (ipAddress instanceof Inet4Address) {
93 return new Ip4SubnetFilterRule((Inet4Address) ipAddress, cidrPrefix, ruleType);
94 } else if (ipAddress instanceof Inet6Address) {
95 return new Ip6SubnetFilterRule((Inet6Address) ipAddress, cidrPrefix, ruleType);
96 } else {
97 throw new IllegalArgumentException("Only IPv4 and IPv6 addresses are supported");
98 }
99 }
100
101 @Override
102 public boolean matches(InetSocketAddress remoteAddress) {
103 return filterRule.matches(remoteAddress);
104 }
105
106 @Override
107 public IpFilterRuleType ruleType() {
108 return filterRule.ruleType();
109 }
110
111
112
113
114 String getIpAddress() {
115 return ipAddress;
116 }
117
118
119
120
121 IpFilterRule getFilterRule() {
122 return filterRule;
123 }
124
125 @Override
126 public int compareTo(IpSubnetFilterRule ipSubnetFilterRule) {
127 if (filterRule instanceof Ip4SubnetFilterRule) {
128 return compareInt(((Ip4SubnetFilterRule) filterRule).networkAddress,
129 ((Ip4SubnetFilterRule) ipSubnetFilterRule.filterRule).networkAddress);
130 } else {
131 return ((Ip6SubnetFilterRule) filterRule).networkAddress
132 .compareTo(((Ip6SubnetFilterRule) ipSubnetFilterRule.filterRule).networkAddress);
133 }
134 }
135
136
137
138
139
140
141
142
143 int compareTo(InetSocketAddress inetSocketAddress) {
144 if (filterRule instanceof Ip4SubnetFilterRule) {
145 Ip4SubnetFilterRule ip4SubnetFilterRule = (Ip4SubnetFilterRule) filterRule;
146 return compareInt(ip4SubnetFilterRule.networkAddress, NetUtil.ipv4AddressToInt((Inet4Address)
147 inetSocketAddress.getAddress()) & ip4SubnetFilterRule.subnetMask);
148 } else {
149 Ip6SubnetFilterRule ip6SubnetFilterRule = (Ip6SubnetFilterRule) filterRule;
150 return ip6SubnetFilterRule.networkAddress
151 .compareTo(Ip6SubnetFilterRule.ipToInt((Inet6Address) inetSocketAddress.getAddress())
152 .and(ip6SubnetFilterRule.subnetMask));
153 }
154 }
155
156
157
158
159 boolean contains(IpSubnetFilterRule other) {
160 if (filterRule instanceof Ip4SubnetFilterRule) {
161 Ip4SubnetFilterRule parent = (Ip4SubnetFilterRule) filterRule;
162 Ip4SubnetFilterRule child = (Ip4SubnetFilterRule) other.filterRule;
163 return (parent.subnetMask & child.subnetMask) == parent.subnetMask &&
164 (child.networkAddress & parent.subnetMask) == parent.networkAddress;
165 }
166 Ip6SubnetFilterRule parent = (Ip6SubnetFilterRule) filterRule;
167 Ip6SubnetFilterRule child = (Ip6SubnetFilterRule) other.filterRule;
168 return parent.subnetMask.and(child.subnetMask).equals(parent.subnetMask) &&
169 child.networkAddress.and(parent.subnetMask).equals(parent.networkAddress);
170 }
171
172
173
174
175 private static int compareInt(int x, int y) {
176 return Integer.compare(x ^ Integer.MIN_VALUE, y ^ Integer.MIN_VALUE);
177 }
178
179 @Override
180 public String toString() {
181 return "IpSubnetFilterRule(" + ipAddress + ", " + ruleType() + ')';
182 }
183
184 static final class Ip4SubnetFilterRule implements IpFilterRule {
185
186 private final int networkAddress;
187 private final int subnetMask;
188 private final IpFilterRuleType ruleType;
189
190 private Ip4SubnetFilterRule(Inet4Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
191 if (cidrPrefix < 0 || cidrPrefix > 32) {
192 throw new IllegalArgumentException(String.format("IPv4 requires the subnet prefix to be in range of "
193 + "[0,32]. The prefix was: %d", cidrPrefix));
194 }
195
196 subnetMask = prefixToSubnetMask(cidrPrefix);
197 networkAddress = NetUtil.ipv4AddressToInt(ipAddress) & subnetMask;
198 this.ruleType = ruleType;
199 }
200
201 @Override
202 public boolean matches(InetSocketAddress remoteAddress) {
203 final InetAddress inetAddress = remoteAddress.getAddress();
204 if (inetAddress instanceof Inet4Address) {
205 int ipAddress = NetUtil.ipv4AddressToInt((Inet4Address) inetAddress);
206 return (ipAddress & subnetMask) == networkAddress;
207 }
208 return false;
209 }
210
211 @Override
212 public IpFilterRuleType ruleType() {
213 return ruleType;
214 }
215
216 private static int prefixToSubnetMask(int cidrPrefix) {
217
218
219
220
221
222
223
224
225
226
227 return (int) (-1L << 32 - cidrPrefix);
228 }
229 }
230
231 static final class Ip6SubnetFilterRule implements IpFilterRule {
232
233 private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1);
234
235 private final BigInteger networkAddress;
236 private final BigInteger subnetMask;
237 private final IpFilterRuleType ruleType;
238
239 private Ip6SubnetFilterRule(Inet6Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
240 if (cidrPrefix < 0 || cidrPrefix > 128) {
241 throw new IllegalArgumentException(String.format("IPv6 requires the subnet prefix to be in range of "
242 + "[0,128]. The prefix was: %d", cidrPrefix));
243 }
244
245 subnetMask = prefixToSubnetMask(cidrPrefix);
246 networkAddress = ipToInt(ipAddress).and(subnetMask);
247 this.ruleType = ruleType;
248 }
249
250 @Override
251 public boolean matches(InetSocketAddress remoteAddress) {
252 final InetAddress inetAddress = remoteAddress.getAddress();
253 if (inetAddress instanceof Inet6Address) {
254 BigInteger ipAddress = ipToInt((Inet6Address) inetAddress);
255 return ipAddress.and(subnetMask).equals(subnetMask) || ipAddress.and(subnetMask).equals(networkAddress);
256 }
257 return false;
258 }
259
260 @Override
261 public IpFilterRuleType ruleType() {
262 return ruleType;
263 }
264
265 private static BigInteger ipToInt(Inet6Address ipAddress) {
266 byte[] octets = ipAddress.getAddress();
267 assert octets.length == 16;
268
269 return new BigInteger(1, octets);
270 }
271
272 private static BigInteger prefixToSubnetMask(int cidrPrefix) {
273 return MINUS_ONE.shiftLeft(128 - cidrPrefix);
274 }
275 }
276 }