Skip to content

Conversation

Stevenjin8
Copy link
Contributor

@ghost
Copy link

ghost commented Oct 3, 2024

All commit authors signed the Contributor License Agreement.
CLA signed

@bedevere-app
Copy link

bedevere-app bot commented Oct 3, 2024

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@rruuaanng
Copy link
Contributor

rruuaanng commented Oct 4, 2024

Also, you need to test this attribute in the corresponding test.

@Stevenjin8
Copy link
Contributor Author

@rruuaanng do you have any ideas on how to write a meaningful test?

The test should only run if the system has netfilter support.
We know this at build time through the HAVE_LINUX_NETFILTER_IPV4_H macro, but we don't have access to this when running the tests.
Other tests make similar checks by inspecting the attributes of socket.
For example, we check for bluetooth support by checking if socket.{AF_BLUETOOTH,BTPROTO_RFCOMM} are defined (amongst other things):

def _have_socket_bluetooth():
    """Check whether AF_BLUETOOTH sockets are supported on this host."""
    try:
        s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM)
    except (AttributeError, OSError):
        return False
    else:
        s.close()
    return True
# ...
HAVE_SOCKET_BLUETOOTH = _have_socket_bluetooth()

And then we run tests only if there is bluetooth support

@unittest.skipUnless(HAVE_SOCKET_BLUETOOTH,
                     'Bluetooth sockets required for this test.')
class BasicBluetoothTest(unittest.TestCase):

    def testBluetoothConstants(self):
        socket.BDADDR_ANY
        socket.BDADDR_LOCAL
        socket.AF_BLUETOOTH
        socket.BTPROTO_RFCOMM
    # ...

So the bluetooth tests are a bit circular because we test for socket.{AF_BLUETOOTH,BTPROTO_RFCOMM} only if socket.{AF_BLUETOOTH,BTPROTO_RFCOMM} are defined.
But in the bluetooth case, the tests run other checks, so they are still meaningful.

However, in the case of SO_ORIGINAL_DESTINATION/netfilter, the only way to check whether there is netfilter support is by checking if socket.SO_ORIGINAL_DESTINATION is defined. If I were to model the test for socket.SO_ORIGINAL_DST after the existing ones, the test would effectively be something like

if hasattr(socket, "SO_ORIGINAL_DST"):
    assert hasattr(socket, "SO_ORIGINAL_DST")

which is dead code.

@rruuaanng
Copy link
Contributor

rruuaanng commented Oct 4, 2024

if hasattr(socket, "SO_ORIGINAL_DST"):
    assert hasattr(socket, "SO_ORIGINAL_DST")

Actually, you can integrate this code into the existing tests for the sockets attribute, rather than writing a new test. It's meaning(Maybe).

Edit: And,It seems that SO_ORIGINAL_DST is unique to Unix-like system. Perhaps you can modify the test to skip it if the current platform is not Unix-like.

Edit: Maybe you should to see Lib/test/test_socket.py refer to the relevant unit test.

@Stevenjin8
Copy link
Contributor Author

Stevenjin8 commented Oct 4, 2024

@rruuaanng My understanding is that SO_ORIGINAL_DST is only for linux as it is part of the netfilter project:

The netfilter project is a community-driven collaborative FOSS project that provides packet filtering software for the Linux 2.4.x and later kernel series

And although most Linux distributions have netfilter and related headers (I couldn't find one without), Linux does not imply netfilter/SO_ORIGINAL_DST. You can disable it if you're building your own kernel/distribution.
Thus, we can't do something like

if sys.platform.startswith('linux'):
   socket.SO_ORIGINAL_DST

as tests in Lib/test/test_socket.py do because we would require systems with linux to have netfilter.

After writing all that, I do think that we can check whether socket.SO_ORIGINAL_DST works as expected if its defined.

if hasattr(socket, "SO_ORIGINAL_DST"):
    s = # set up socket
    opt = getsockopt(s, socket.SOL_IP, socket.SO_ORIGINAL_DST)
    # check that `opt` makes sense

This way we don't assert that linux systems have netfilter, but we do say that if socket.SO_ORIGINAL_DST exists, it should work with setsockopt.

Let me know what you think

@rruuaanng
Copy link
Contributor

rruuaanng commented Oct 5, 2024

You can actually add a description of this attribute in the documentation.
For example, you can state that it only applies to the linux. Since this is already explained in the documentation, there’s no need to modify other content.
You just need to include a check in the tests so that this particular test is only run on linux, as you demonstrated.

@picnixz
Copy link
Member

picnixz commented Oct 5, 2024

I don't think there's need to test this since we don't test other non-crucial constants, nor is there a need to add a dedicated documented entry (the docs just gather most constants under SO_*). Only crucial constants such as socket.AF_INET are really tested for their existence.

If you want a test, you can just do something like this:

@unittest.skipUnless(sysconfig.get_config_var('HAVE_LINUX_NETFILTER_IPV4_H'), 
					 "requires <linux/netfilter_ipv4.h>")
def test_socket_linux_netfilter_ipv4(self):
	socket.SO_ORIGINAL_DST

@Stevenjin8 Stevenjin8 force-pushed the fix-issue-124944 branch 2 times, most recently from cb6f2e3 to d417182 Compare October 7, 2024 14:50
@Stevenjin8 Stevenjin8 requested a review from picnixz October 7, 2024 14:51
* Move include out of __GNU__ guard
* Docs and lint
@Stevenjin8
Copy link
Contributor Author

going to ignore the docs error because it also happens for SO_REUSEPORT and SO_EXCLUSIVEADDRESS

Stevenjin8 and others added 2 commits October 7, 2024 21:44
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
@rruuaanng

This comment was marked as off-topic.

@erlend-aasland
Copy link
Contributor

Bénédict, are you happy with the changes? @picnixz

@picnixz picnixz self-requested a review October 14, 2024 22:34
Copy link
Member

@picnixz picnixz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@erlend-aasland
Copy link
Contributor

Let's go! Thanks, @Stevenjin8.

@erlend-aasland erlend-aasland merged commit 1bffd7a into python:main Oct 14, 2024
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants