-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Throws exception when passed IP address with too long mask #7084
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Throws exception when passed IP address with too long mask #7084
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@clementkng, thanks for the PR! I left some feedback inline.
} | ||
|
||
public boolean matches(HttpServletRequest request) { | ||
return matches(request.getRemoteAddr()); | ||
} | ||
|
||
public boolean matches(String address) { | ||
InetAddress remoteAddress = parseAddress(address); | ||
String [] addressAndMask = preprocessAddressAndMask(address); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The address passed into this method doesn't have a mask, so the preprocessing is unnecessary here.
As such, the preprocessAddressAndMask
method is probably also unnecessary for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So does this mean that we don't have to check remote address
anymore, since there's no mask that will be assigned there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of this line:
if ((remAddr[i] & mask[i]) != (reqAddr[i] & mask[i])) {
The code needs to ensure that both remAddr
and reqAddr
are not too short. It makes sense to me that the code would verify the required address in the constructor and the remote address in the matches
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume you're referring to this line. I can add a comparison that the remAddr.length * 8 >= nMaskBits
, but I'm having trouble coming up w/ a too short IP address. Stuff like 192.168.1
and shorter variants seem to be matching just fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I was behind a version. I'm referring to this line.
I wonder if it would break if you configured to match against an IPv6 address and called matches
with an IPv4 address?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jzheaux In that case this line will realize that the classes of the IP addresses are different (java.net.Inet6Address
vs java.net.Inet4Address
) and then simply return False
. IMO this feels more correct than an IllegalArgumentException
stating that a mask length is too long, which isn't indicative that the addresses you're comparing are of different types. Unless it is valid to try to mix and match ipv4 and ipv6 addresses?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jzheaux In that case this line will realize that the classes of the IP addresses are different (java.net.Inet6Address
vs java.net.Inet4Address
) and then simply return False
. IMO this feels more correct than an IllegalArgumentException
stating that a mask length is too long, which isn't indicative that the addresses you're comparing are of different types. Unless it is valid to try to mix and match ipv4 and ipv6 addresses?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's not a valid use case -- was just thinking out loud about how you might make the remote address byte array too long.
I agree that an IPv4Address
instance will always be 4 bytes long and an IPv6Address
will always be 16 bytes long, so there's no need to check the length of remote address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @jzheaux, any other feedback?
dc38ca4
to
be57e8f
Compare
@@ -46,15 +47,18 @@ | |||
*/ | |||
public IpAddressMatcher(String ipAddress) { | |||
|
|||
String ipAddr = ipAddress; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this may be an improvement, @clementkng, let's please leave renaming the variable for another PR, unless there is a reason it's necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jzheaux I changed it because ipAddress
is overwritten if we parse a mask, meaning that I can’t use it in a meaningful error message (to show the ip and mask together).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess an alternative would be to rewrite the message in a way i.e. IP address <address> too short for bitmask <mask>.
Let me know what you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that a message with placeholders is a good solution. I like it because of the smaller change footprint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jzheaux I changed the message and changed the variables back.
be57e8f
to
6d917c1
Compare
@jzheaux Thanks for the review. Is there any other feedback? |
@@ -76,6 +80,8 @@ public boolean matches(String address) { | |||
byte[] reqAddr = requiredAddress.getAddress(); | |||
|
|||
int nMaskFullBytes = nMaskBits / 8; | |||
Assert.isTrue(remAddr.length >= nMaskFullBytes, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this check can be removed, correct @clementkng? You and I could not find a use case where this check would fail.
I'd recommend taking it out; however, if it stays, then let's make sure that the error messages align to both include the ip address and the bitmask length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jzheaux good catch, forgot about that! I removed the check.
6d917c1
to
a80944e
Compare
Thanks, @clementkng! This is now merged into |
Originally,
matches(String address)
would first callparse
on an address, when I believe the correct behavior is to first check for the validity of the subnet mask (an invalid mask for an IP address is invalid regardless of what method it's a part of). This is why invalid masks could be passed into the constructor but then throw exceptions on valid calls tomatches
. So I changed both the constructor and thematches
method to first validate that the mask in the IP address passed in is not too long.Draft b/c I'm not sure if my assumption fully holds for all cases.
Fixes gh-2790