-
Notifications
You must be signed in to change notification settings - Fork 37
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
Raising errors on invalid ip requires rewrite of client logic #200
Comments
You could always just make a custom overridden class that doesn't run the check but I suppose I wouldn't mind adding a bool arg to toggle the check as long as it's enabled by default, like you did in the PR. I do wonder though, what code do you have that ensures the validity of the IP that's not compatible with the current checking which we're doing? There is a custom error raised (TypeError or ValueError) which you could easily catch and go from there. It is also possible to get the error message so you would be able to capture exactly what went wrong too. |
This code is spread to many files, so better inspect my code yourself. |
Seems to me like what you're really looking for is a separation of the DNS lookup logic into it's own staticmethod, so that you could just check the DNS without having to even make an instance of I think doing that makes a lot more sense and even though I don't necessarily mind the bool arg to toggle the verification, there shouldn't be any need to do that, the IP verification should always happen if you're making a full But I do think separating the DNS parsing logic into it's own static method makes a lot of sense. |
This also could be a fix (move checks to a classmethod) No, sorry I missed up |
With the better regex expression that is RFC compliant, is this already fixed? If not, please provide an example code that was the cause for reporting this issue. |
What fixed? The issue is that, there is existing any check which raising exception. |
Why don't you just handle for that exception with Handling these exceptions shouldn't be hard at all, we only raise TypeErrors or ValueErrors, but I've said this earlier. Is our logic really so unreliable that you need to be using Nevertheless, if you just need to perform the DNS lookup, you shouldn't even need to construct an entire instance of This logic would look like this: We simply can't remove these checks from |
Yes, I can use So, as an example, I will give my piece of code that receives DNS information from mcstatus and parses it: async def parse_ip(input_ip: str) -> ServerInfo:
"""Pasing IP.
Args:
input_ip: IP, given by user.
Returns:
ServerInfo obj with information, about server.
"""
dns_info = MinecraftServer.lookup(input_ip) # Here, mcstatus raising exception
try:
num_ip = gethostbyname(dns_info.host)
valid = True
except gaierror:
valid, num_ip = False, None
return ServerInfo(valid, dns_info, num_ip, str(dns_info.port)) Try rewrite it with try:
dns_info = MinecraftServer.lookup(input_ip)
except ValueError as err_msg:
if "Port must be within the allowed range" in err_msg:
return "Port must be lower than 65535 and bigger than 0"
elif "(doesn't match the required pattern)" in err_msg:
return "You need provide valid hostname"
# I ensure that, ip is valid, because mcstatus check it
# so removing try except here
# P.S. this bad idea, because my tests crashed code with input_ip='www'
num_ip = gethostbyname(dns_info.host)
return ServerInfo(True, dns_info, num_ip, str(dns_info.port)) But as you can see, client code doesn't know what to do with non-ServerInfo objects. So let's add error codes to ServerInfo. if "Port must be within the allowed range" in err_msg:
return ServerInfo(dns_info=None, num_ip=None, port=None, err_code=1)
elif "(doesn't match the required pattern)" in err_msg:
return ServerInfo(dns_info=None, num_ip=None, port=None, err_code=2)
num_ip = gethostbyname(dns_info.host)
# Remove field valid, because for this now created err_code
return ServerInfo(dns_info, num_ip, str(dns_info.port), err_code=0) This looks ugly, better let's create a new class for the exceptions that are returned by my code... So, step by step, we will rewrite all the code that is somehow related to the mcstatus object. I understand. You can't remove checks from |
I don't see how this is an issue with mcstatus though. I agree that separating DNS functions to make things like this easier is a good thing to do for cases like these, I personally don't think we should make the ip validation optional though since again, it just causes issues and we don't really have any good reason for doing that. If you need something like this on your side, why don't you just make a subclass, override our behavior and be done with it? class MyMinecraftServer(mcstatus.MinecraftServer):
def __init__(self, host: str, port: int = 25565, timeout: float = 3):
# ensure_valid_ip(host, port) # Don't do this in your subclass
self.host = host
self.port = port
self.timeout = timeout This way you get exactly the behavior you were looking for without any need to alter the library code, which requires this validation to be there. But it's up to you to debug any potential errors if they occur because the address was invalid in case you were using functions that require it. To circumvent that, you could implement any of the proposed solutions (bool flag with a function that blocks all other if false set by another function or running the check before each function making a connection), or something else if you can think of it. Though you don't really need it for your use-case, so it's up to you to implement those, just know that not doing that may cause issues. What I'd actually suggest though is just not storing This would mean you'd have to change your class DnsInfo:
def __init__(self, address: str):
self.address = address
host, port = mcstatus.server.parse_address(address)
# If the port wasn't in the address, we should first perform and SRV DNS lookup
# and only if that fails should we rely on the default port
if port is None:
try:
host, port = mcstatus.server.MinecraftServer.dns_srv_lookup(host)
except dns.resolver.NXDOMAIN:
port = 25565
self.host = host
self.port = port What may actually be worth doing is making |
Okay, thanks. But the only reason I use mcstatus for DNS info, is because you already have the code I wanted to write to check SRV and other stuff. Also, creating my own subclass means I'll have to check each time to see if anything in |
Indeed, It's not, but again you shouldn't be storing the entire class just for DNS info, the only reason I suggested that, was to give you a solution that doesn't break your compatibility. The custom class is a lot better, but again, you shouldn't even be storing a class, just use a named tuple with host and port, or store them as attributes direcly in your class. But we could make it even easier for something like this by making that staticmethod function with lookup logic in it that I suggested along with also making the DNS functions, I wouldn't mind adding that into 203 when I'll have some time. |
Thanks for the extra information and discussion! I only asked for the code that raised the exception. dns_info = MinecraftServer.lookup(input_ip) # Here, mcstatus raising exception what is
"127.0.0.1"? Also nothing raised:
Soooo my question remains, what code is giving you an exception? I'm of a mind to close this because of the RFC compliant regex that was added. Make sure you are running the latest released version (v8.0.0 is the latest stable at the time of writing this and is what I used above), please :) |
I am using 9.0.0-dev2, because Dinnerbone/mcstatus#198 (comment). >>> from mcstatus import MinecraftServer
>>> MinecraftServer.lookup("www")
<mcstatus.server.MinecraftServer object at 0x000001F3C7467580> What expected: >>> MinecraftServer.lookup("not_valid_ip")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\perch\AppData\Local\Programs\Python\Python310\lib\site-packages\mcstatus\server.py", line 73, in lookup
return cls(host, port, timeout)
File "C:\Users\perch\AppData\Local\Programs\Python\Python310\lib\site-packages\mcstatus\server.py", line 46, in __init__
ensure_valid_ip(host, port)
File "C:\Users\perch\AppData\Local\Programs\Python\Python310\lib\site-packages\mcstatus\server.py", line 32, in ensure_valid_ip
raise ValueError(f"Invalid host address, {host!r} (doesn't match the required pattern)")
ValueError: Invalid host address, 'not_valid_ip' (doesn't match the required pattern) |
Underscores are not valid characters for hostnames... but they are for DNS names! That was my bad to conflate those two. Also my bad for forgetting which version this was in. After doing some research, I'm convinced that maintaining this validity check is going to be awful. Let's go back to not checking it at all and relying on exceptions. We'd have to check if it's an IPv4 address, an IPv6 address, a valid hostname, a valid DNS name, or whatever else the connection software stack is capable of. I'll remove the check for now until we find a better way of doing it. Research: |
Another dev version: v9.0.0-dev3 |
I have code, that parsed and ensured the ip is valid. And all this with object from
MinecraftServer.lookup
.So I need to rewrite almost all code which uses mcstatus objects, just because da4770a.
Add switch, or something like this please.
Also I can't do fast-fix just with
except: MineServer.lookup("not-valid.com")
because object with offline server != object with invalid ip.P.S. I don't ask remove this feature, it would be nice to give messages like
Invalid IP, reason: Port must be lower than 36635
.The text was updated successfully, but these errors were encountered: