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.internal.SocketUtils;
19
20 import java.math.BigInteger;
21 import java.net.Inet4Address;
22 import java.net.Inet6Address;
23 import java.net.InetAddress;
24 import java.net.InetSocketAddress;
25 import java.net.UnknownHostException;
26
27
28
29
30
31 public final class IpSubnetFilterRule implements IpFilterRule {
32
33 private final IpFilterRule filterRule;
34
35 public IpSubnetFilterRule(String ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
36 try {
37 filterRule = selectFilterRule(SocketUtils.addressByName(ipAddress), cidrPrefix, ruleType);
38 } catch (UnknownHostException e) {
39 throw new IllegalArgumentException("ipAddress", e);
40 }
41 }
42
43 public IpSubnetFilterRule(InetAddress ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
44 filterRule = selectFilterRule(ipAddress, cidrPrefix, ruleType);
45 }
46
47 private static IpFilterRule selectFilterRule(InetAddress ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
48 if (ipAddress == null) {
49 throw new NullPointerException("ipAddress");
50 }
51
52 if (ruleType == null) {
53 throw new NullPointerException("ruleType");
54 }
55
56 if (ipAddress instanceof Inet4Address) {
57 return new Ip4SubnetFilterRule((Inet4Address) ipAddress, cidrPrefix, ruleType);
58 } else if (ipAddress instanceof Inet6Address) {
59 return new Ip6SubnetFilterRule((Inet6Address) ipAddress, cidrPrefix, ruleType);
60 } else {
61 throw new IllegalArgumentException("Only IPv4 and IPv6 addresses are supported");
62 }
63 }
64
65 @Override
66 public boolean matches(InetSocketAddress remoteAddress) {
67 return filterRule.matches(remoteAddress);
68 }
69
70 @Override
71 public IpFilterRuleType ruleType() {
72 return filterRule.ruleType();
73 }
74
75 private static final class Ip4SubnetFilterRule implements IpFilterRule {
76
77 private final int networkAddress;
78 private final int subnetMask;
79 private final IpFilterRuleType ruleType;
80
81 private Ip4SubnetFilterRule(Inet4Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
82 if (cidrPrefix < 0 || cidrPrefix > 32) {
83 throw new IllegalArgumentException(String.format("IPv4 requires the subnet prefix to be in range of " +
84 "[0,32]. The prefix was: %d", cidrPrefix));
85 }
86
87 subnetMask = prefixToSubnetMask(cidrPrefix);
88 networkAddress = ipToInt(ipAddress) & subnetMask;
89 this.ruleType = ruleType;
90 }
91
92 @Override
93 public boolean matches(InetSocketAddress remoteAddress) {
94 int ipAddress = ipToInt((Inet4Address) remoteAddress.getAddress());
95
96 return (ipAddress & subnetMask) == networkAddress;
97 }
98
99 @Override
100 public IpFilterRuleType ruleType() {
101 return ruleType;
102 }
103
104 private static int ipToInt(Inet4Address ipAddress) {
105 byte[] octets = ipAddress.getAddress();
106 assert octets.length == 4;
107
108 return (octets[0] & 0xff) << 24 |
109 (octets[1] & 0xff) << 16 |
110 (octets[2] & 0xff) << 8 |
111 octets[3] & 0xff;
112 }
113
114 private static int prefixToSubnetMask(int cidrPrefix) {
115
116
117
118
119
120
121
122
123
124
125 return (int) ((-1L << 32 - cidrPrefix) & 0xffffffff);
126 }
127 }
128
129 private static final class Ip6SubnetFilterRule implements IpFilterRule {
130
131 private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1);
132
133 private final BigInteger networkAddress;
134 private final BigInteger subnetMask;
135 private final IpFilterRuleType ruleType;
136
137 private Ip6SubnetFilterRule(Inet6Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
138 if (cidrPrefix < 0 || cidrPrefix > 128) {
139 throw new IllegalArgumentException(String.format("IPv6 requires the subnet prefix to be in range of " +
140 "[0,128]. The prefix was: %d", cidrPrefix));
141 }
142
143 subnetMask = prefixToSubnetMask(cidrPrefix);
144 networkAddress = ipToInt(ipAddress).and(subnetMask);
145 this.ruleType = ruleType;
146 }
147
148 @Override
149 public boolean matches(InetSocketAddress remoteAddress) {
150 BigInteger ipAddress = ipToInt((Inet6Address) remoteAddress.getAddress());
151
152 return ipAddress.and(subnetMask).equals(networkAddress);
153 }
154
155 @Override
156 public IpFilterRuleType ruleType() {
157 return ruleType;
158 }
159
160 private static BigInteger ipToInt(Inet6Address ipAddress) {
161 byte[] octets = ipAddress.getAddress();
162 assert octets.length == 16;
163
164 return new BigInteger(octets);
165 }
166
167 private static BigInteger prefixToSubnetMask(int cidrPrefix) {
168 return MINUS_ONE.shiftLeft(128 - cidrPrefix);
169 }
170 }
171 }