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.networkAddress));
153 }
154 }
155
156
157
158
159 private static int compareInt(int x, int y) {
160 return (x < y) ? -1 : ((x == y) ? 0 : 1);
161 }
162
163 static final class Ip4SubnetFilterRule implements IpFilterRule {
164
165 private final int networkAddress;
166 private final int subnetMask;
167 private final IpFilterRuleType ruleType;
168
169 private Ip4SubnetFilterRule(Inet4Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
170 if (cidrPrefix < 0 || cidrPrefix > 32) {
171 throw new IllegalArgumentException(String.format("IPv4 requires the subnet prefix to be in range of "
172 + "[0,32]. The prefix was: %d", cidrPrefix));
173 }
174
175 subnetMask = prefixToSubnetMask(cidrPrefix);
176 networkAddress = NetUtil.ipv4AddressToInt(ipAddress) & subnetMask;
177 this.ruleType = ruleType;
178 }
179
180 @Override
181 public boolean matches(InetSocketAddress remoteAddress) {
182 final InetAddress inetAddress = remoteAddress.getAddress();
183 if (inetAddress instanceof Inet4Address) {
184 int ipAddress = NetUtil.ipv4AddressToInt((Inet4Address) inetAddress);
185 return (ipAddress & subnetMask) == networkAddress;
186 }
187 return false;
188 }
189
190 @Override
191 public IpFilterRuleType ruleType() {
192 return ruleType;
193 }
194
195 private static int prefixToSubnetMask(int cidrPrefix) {
196
197
198
199
200
201
202
203
204
205
206 return (int) (-1L << 32 - cidrPrefix);
207 }
208 }
209
210 static final class Ip6SubnetFilterRule implements IpFilterRule {
211
212 private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1);
213
214 private final BigInteger networkAddress;
215 private final BigInteger subnetMask;
216 private final IpFilterRuleType ruleType;
217
218 private Ip6SubnetFilterRule(Inet6Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
219 if (cidrPrefix < 0 || cidrPrefix > 128) {
220 throw new IllegalArgumentException(String.format("IPv6 requires the subnet prefix to be in range of "
221 + "[0,128]. The prefix was: %d", cidrPrefix));
222 }
223
224 subnetMask = prefixToSubnetMask(cidrPrefix);
225 networkAddress = ipToInt(ipAddress).and(subnetMask);
226 this.ruleType = ruleType;
227 }
228
229 @Override
230 public boolean matches(InetSocketAddress remoteAddress) {
231 final InetAddress inetAddress = remoteAddress.getAddress();
232 if (inetAddress instanceof Inet6Address) {
233 BigInteger ipAddress = ipToInt((Inet6Address) inetAddress);
234 return ipAddress.and(subnetMask).equals(subnetMask) || ipAddress.and(subnetMask).equals(networkAddress);
235 }
236 return false;
237 }
238
239 @Override
240 public IpFilterRuleType ruleType() {
241 return ruleType;
242 }
243
244 private static BigInteger ipToInt(Inet6Address ipAddress) {
245 byte[] octets = ipAddress.getAddress();
246 assert octets.length == 16;
247
248 return new BigInteger(octets);
249 }
250
251 private static BigInteger prefixToSubnetMask(int cidrPrefix) {
252 return MINUS_ONE.shiftLeft(128 - cidrPrefix);
253 }
254 }
255 }