Buy commercial curl support from WolfSSL. We help you work out your issues, debug your libcurl applications, use the API, port to new platforms, add new features and more. With a team lead by the curl founder himself.

Re: Return

From: Pēteris Caune via curl-and-python <curl-and-python_at_lists.haxx.se>
Date: Thu, 02 Feb 2023 14:51:15 +0200

I'm probably overthinking the _make_opensocket bit, it could probably be simpler like so:


    opensocket_rejected_ips = []

    def opensocket(purpose, curl_address):
        family, socktype, protocol, address = curl_address
        if not settings.INTEGRATIONS_ALLOW_PRIVATE_IPS:
            if ipaddress.ip_address(address[0]).is_private:
                opensocket_rejected_ips.append(address[0])
                return pycurl.SOCKET_BAD

        return socket.socket(family, socktype, protocol)

    c = pycurl.Curl()
    c.setopt(pycurl.OPENSOCKETFUNCTION, opensocket)

    (...)

    try:
        c.perform()
    except pycurl.error as e:
        errcode = e.args[0]
        if errcode == pycurl.E_COULDNT_CONNECT:
            if opensocket_rejected_ips:
                raise CurlError("Connections to private IP addresses are not allowed")

            # fall back to the generic error message
            raise CurlError("Connection failed")

        (...)

My concern is – is this safe for the OPENSOCKETFUNCTION callback to touch objects outside its scope? It would work fine in pure python, but could there be any issues when it gets called by curl?

Thanks,
Pēteris

On Thu, Feb 2, 2023, at 11:55 AM, Pēteris Caune via curl-and-python wrote:
> Hello,
>
> I'm using pycurl and the OPENSOCKETFUNCTION callback to reject requests to private IP addresses:
>
> def _opensocket(purpose, curl_address):
> family, socktype, protocol, address = curl_address
> if not settings.INTEGRATIONS_ALLOW_PRIVATE_IPS:
> if ipaddress.ip_address(address[0]).is_private:
> return pycurl.SOCKET_BAD
>
> return socket.socket(family, socktype, protocol)
>
> My client code catches pycurl.error exceptions, checks their error codes and generates appropriate error messages:
>
> try:
> c.perform()
> except pycurl.error as e:
> errcode = e.args[0]
> if errcode == pycurl.E_OPERATION_TIMEDOUT:
> raise CurlError("Connection timed out")
> elif errcode == pycurl.E_COULDNT_CONNECT:
> raise CurlError("Connection failed")
> ...
>
> It looks like E_COULDNT_CONNECT can be returned for a variety of reasons. I'd like to give the user a specific error message if the request was blocked because of the private IP check: "Connection to a private IP such-and-such was refused" or something along these lines. So my _opensocket function would need to somehow smuggle out information about the failure reason. But I'm not sure what would be a safe way to do this. Would using a closure be fine?
>
> def _make_opensocket(errors):
> def _opensocket(purpose, curl_address):
> family, socktype, protocol, address = curl_address
> if not settings.INTEGRATIONS_ALLOW_PRIVATE_IPS:
> if ipaddress.ip_address(address[0]).is_private:
> errors.append("more specific error code or errror message here")
> return pycurl.SOCKET_BAD
>
> return socket.socket(family, socktype, protocol)
>
> return _opensocket
>
> The caller would do:
>
> opensocket_errors = []
> c.setopt(pycurl.OPENSOCKETFUNCTION, _make_opensocket(opensocket_errors))
>
>
> Or is there perhaps a more straightforward way to do the same?
> I'll appreciate any tips,
>
> Thanks,
> Pēteris
>
> --
> curl-and-python mailing list
> curl-and-python_at_lists.haxx.se
> https://lists.haxx.se/listinfo/curl-and-python
>
-- 
curl-and-python mailing list
curl-and-python_at_lists.haxx.se
https://lists.haxx.se/listinfo/curl-and-python
Received on 2023-02-02