18
18
19
19
import java .net .InetAddress ;
20
20
import java .net .UnknownHostException ;
21
+ import java .util .Objects ;
21
22
import java .util .regex .Pattern ;
22
23
23
24
import jakarta .servlet .http .HttpServletRequest ;
33
34
* IPv4 address will never match a request which returns an IPv6 address, and vice-versa.
34
35
*
35
36
* @author Luke Taylor
37
+ * @author Steve Riesenberg
36
38
* @since 3.0.2
37
39
*/
38
40
public final class IpAddressMatcher implements RequestMatcher {
39
41
40
42
private static Pattern IPV4 = Pattern .compile ("\\ d{0,3}.\\ d{0,3}.\\ d{0,3}.\\ d{0,3}(/\\ d{0,3})?" );
41
43
42
- private final int nMaskBits ;
43
-
44
44
private final InetAddress requiredAddress ;
45
45
46
+ private final int nMaskBits ;
47
+
46
48
/**
47
49
* Takes a specific IP address or a range specified using the IP/Netmask (e.g.
48
50
* 192.168.1.0/24 or 202.24.0.0/14).
@@ -52,33 +54,37 @@ public final class IpAddressMatcher implements RequestMatcher {
52
54
public IpAddressMatcher (String ipAddress ) {
53
55
Assert .hasText (ipAddress , "ipAddress cannot be empty" );
54
56
assertNotHostName (ipAddress );
57
+
58
+ String requiredAddress ;
59
+ int nMaskBits ;
55
60
if (ipAddress .indexOf ('/' ) > 0 ) {
56
- String [] addressAndMask = StringUtils .split (ipAddress , "/" );
57
- ipAddress = addressAndMask [0 ];
58
- this . nMaskBits = Integer .parseInt (addressAndMask [1 ]);
61
+ String [] parts = Objects . requireNonNull ( StringUtils .split (ipAddress , "/" ) );
62
+ requiredAddress = parts [0 ];
63
+ nMaskBits = Integer .parseInt (parts [1 ]);
59
64
}
60
65
else {
61
- this .nMaskBits = -1 ;
66
+ requiredAddress = ipAddress ;
67
+ nMaskBits = -1 ;
62
68
}
63
- this .requiredAddress = parseAddress (ipAddress );
64
- String finalIpAddress = ipAddress ;
69
+ this .requiredAddress = parseAddress (requiredAddress );
70
+ this . nMaskBits = nMaskBits ;
65
71
Assert .isTrue (this .requiredAddress .getAddress ().length * 8 >= this .nMaskBits , () -> String
66
- .format ("IP address %s is too short for bitmask of length %d" , finalIpAddress , this .nMaskBits ));
72
+ .format ("IP address %s is too short for bitmask of length %d" , requiredAddress , this .nMaskBits ));
67
73
}
68
74
69
75
@ Override
70
76
public boolean matches (HttpServletRequest request ) {
71
77
return matches (request .getRemoteAddr ());
72
78
}
73
79
74
- public boolean matches (String address ) {
80
+ public boolean matches (String ipAddress ) {
75
81
// Do not match null or blank address
76
- if (!StringUtils .hasText (address )) {
82
+ if (!StringUtils .hasText (ipAddress )) {
77
83
return false ;
78
84
}
79
85
80
- assertNotHostName (address );
81
- InetAddress remoteAddress = parseAddress (address );
86
+ assertNotHostName (ipAddress );
87
+ InetAddress remoteAddress = parseAddress (ipAddress );
82
88
if (!this .requiredAddress .getClass ().equals (remoteAddress .getClass ())) {
83
89
return false ;
84
90
}
@@ -88,26 +94,31 @@ public boolean matches(String address) {
88
94
byte [] remAddr = remoteAddress .getAddress ();
89
95
byte [] reqAddr = this .requiredAddress .getAddress ();
90
96
int nMaskFullBytes = this .nMaskBits / 8 ;
91
- byte finalByte = (byte ) (0xFF00 >> (this .nMaskBits & 0x07 ));
92
97
for (int i = 0 ; i < nMaskFullBytes ; i ++) {
93
98
if (remAddr [i ] != reqAddr [i ]) {
94
99
return false ;
95
100
}
96
101
}
102
+ byte finalByte = (byte ) (0xFF00 >> (this .nMaskBits & 0x07 ));
97
103
if (finalByte != 0 ) {
98
104
return (remAddr [nMaskFullBytes ] & finalByte ) == (reqAddr [nMaskFullBytes ] & finalByte );
99
105
}
100
106
return true ;
101
107
}
102
108
103
- private void assertNotHostName (String ipAddress ) {
104
- boolean isIpv4 = IPV4 .matcher (ipAddress ).matches ();
105
- if (isIpv4 ) {
106
- return ;
107
- }
108
- String error = "ipAddress " + ipAddress + " doesn't look like an IP Address. Is it a host name?" ;
109
- Assert .isTrue (ipAddress .charAt (0 ) == '[' || ipAddress .charAt (0 ) == ':'
110
- || (Character .digit (ipAddress .charAt (0 ), 16 ) != -1 && ipAddress .contains (":" )), error );
109
+ private static void assertNotHostName (String ipAddress ) {
110
+ Assert .isTrue (isIpAddress (ipAddress ),
111
+ () -> String .format ("ipAddress %s doesn't look like an IP Address. Is it a host name?" , ipAddress ));
112
+ }
113
+
114
+ private static boolean isIpAddress (String ipAddress ) {
115
+ // @formatter:off
116
+ return IPV4 .matcher (ipAddress ).matches ()
117
+ || ipAddress .charAt (0 ) == '['
118
+ || ipAddress .charAt (0 ) == ':'
119
+ || Character .digit (ipAddress .charAt (0 ), 16 ) != -1
120
+ && ipAddress .indexOf (':' ) > 0 ;
121
+ // @formatter:on
111
122
}
112
123
113
124
private InetAddress parseAddress (String address ) {
0 commit comments