Skip to content

Commit

Permalink
Avoid AF_UNIX if it does not exist
Browse files Browse the repository at this point in the history
  • Loading branch information
icgood committed Apr 29, 2023
1 parent 45aa1c2 commit 560a674
Show file tree
Hide file tree
Showing 13 changed files with 57 additions and 37 deletions.
5 changes: 0 additions & 5 deletions .flake8

This file was deleted.

22 changes: 11 additions & 11 deletions .github/workflows/python-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@ on:

jobs:
build:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11']
platform: [ubuntu-latest, macos-latest, windows-latest]

runs-on: ${{ matrix.platform }}

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
python-version: |
3.8
3.9
3.10
3.11
- name: Install build tools
run: |
python -m pip install hatch coveralls
- name: Run test suites, type checks, and linters
run: |
hatch run check
- name: Report test coverage to Coveralls
if: success()
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
coveralls --service=github
hatch run all:check
- name: Report Coveralls
uses: coverallsapp/github-action@v2
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ extremely simple. Here is an example, which will detect PROXY protocol v1 or
v2.

```python
from functools import partial

from proxyprotocol import ProxyProtocol
from proxyprotocol.detect import ProxyProtocolDetect
from proxyprotocol.reader import ProxyProtocolReader
Expand Down Expand Up @@ -70,9 +68,9 @@ The `pp_noop` object in this example is a special case implementation that does
not read a PROXY protocol header from the stream at all. It may be used to
disable PROXY protocol use without complicating your server code.

You can also check out the [`proxyprotocol/echo.py`][4] reference
implementation. If you configure your proxy to send PROXY protocol to
`localhost:10007`, you can see it in action:
You can also check out the [`proxyprotocol-echo`][4] reference implementation.
If you configure your proxy to send PROXY protocol to `localhost:10007`, you
can see it in action:

```bash
$ proxyprotocol-echo --help
Expand Down Expand Up @@ -146,7 +144,7 @@ hinting to the extent possible and common in the rest of the codebase.
[1]: https://hatch.pypa.io/latest/install/
[2]: https://docs.python.org/3/library/asyncio.html
[3]: https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server
[4]: https://github.com/icgood/proxy-protocol/blob/main/proxyprotocol/echo.py
[4]: https://github.com/icgood/proxy-protocol/blob/main/proxyprotocol/server/echo.py
[6]: https://www.python.org/dev/peps/pep-0484/
[7]: http://mypy-lang.org/
[8]: https://icgood.github.io/proxy-protocol/proxyprotocol.html#proxyprotocol.server.Address
2 changes: 1 addition & 1 deletion proxyprotocol/__about__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#: The package version string.
__version__ = '0.10.3'
__version__ = '0.11.0'
4 changes: 3 additions & 1 deletion proxyprotocol/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

__all__ = ['build_socket_result', 'build_transport_result']

_has_af_unix = hasattr(socket, 'AF_UNIX')


def build_socket_result(sock: socket.socket, *,
unique_id: Optional[bytes] = None,
Expand Down Expand Up @@ -70,7 +72,7 @@ def _build_result(sock: socket.socket, peername: SockAddr, sockname: SockAddr,
return ProxyResultIPv6((IPv6Address(peername[0]), peername[1]),
(IPv6Address(sockname[0]), sockname[1]),
protocol=protocol, tlv=tlv)
elif family == socket.AF_UNIX:
elif _has_af_unix and family == socket.AF_UNIX:
assert isinstance(peername, str)
assert isinstance(sockname, str)
tlv = _build_tlv(ssl_obj, unique_id, dnsbl)
Expand Down
4 changes: 3 additions & 1 deletion proxyprotocol/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

_empty_tlv = ProxyProtocolTLV()

_has_af_unix = hasattr(socket, 'AF_UNIX')


def is_local(result: ProxyResult) \
-> TypeGuard[ProxyResultLocal]:
Expand Down Expand Up @@ -67,7 +69,7 @@ def is_unix(result: ProxyResult) -> TypeGuard[ProxyResultUnix]:
result: The proxy protocol result.
"""
return result.proxied and result.family == socket.AF_UNIX
return result.proxied and _has_af_unix and result.family == socket.AF_UNIX


class ProxyResult(metaclass=ABCMeta):
Expand Down
6 changes: 4 additions & 2 deletions proxyprotocol/sock.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

_IP = Union[None, IPv4Address, IPv6Address]

_has_af_unix = hasattr(socket, 'AF_UNIX')


class SocketInfo(metaclass=ABCMeta):
"""Provides information about the connection, from either the underlying
Expand Down Expand Up @@ -76,7 +78,7 @@ def _get_str(self, addr: SockAddr, ip: _IP,
port: Optional[int]) -> Optional[str]:
if self.family in (socket.AF_INET, socket.AF_INET6):
return f'[{ip!s}]:{port!s}'
elif self.family == socket.AF_UNIX:
elif _has_af_unix and self.family == socket.AF_UNIX:
assert isinstance(addr, str)
return addr
elif self.family == socket.AF_UNSPEC:
Expand Down Expand Up @@ -252,7 +254,7 @@ def from_localhost(self) -> bool:
:attr:`~ipaddress.IPv4Address.is_loopback` flags.
"""
if self.family == socket.AF_UNIX:
if _has_af_unix and self.family == socket.AF_UNIX:
return True
ip = self.peername_ip
if ip is None:
Expand Down
4 changes: 3 additions & 1 deletion proxyprotocol/v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

__all__ = ['ProxyProtocolV2Header', 'ProxyProtocolV2']

_has_af_unix = hasattr(socket, 'AF_UNIX')


class ProxyProtocolV2Header:
"""The 16-byte header that precedes the source and destination address data
Expand Down Expand Up @@ -44,7 +46,7 @@ class ProxyProtocolV2(ProxyProtocol):
_families = [(0x00, socket.AF_UNSPEC),
(0x10, socket.AF_INET),
(0x20, socket.AF_INET6),
(0x30, socket.AF_UNIX)]
*([(0x30, socket.AF_UNIX)] if _has_af_unix else [])]
_protocols = [(0x00, None),
(0x01, socket.SOCK_STREAM),
(0x02, socket.SOCK_DGRAM)]
Expand Down
19 changes: 10 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,13 @@ files = ['proxyprotocol', 'test']
module = 'crc32c.*'
ignore_missing_imports = true

[tool.bandit]
skips = ['B101']
[tool.ruff]
select = ['ANN', 'B', 'B904', 'E', 'F', 'N', 'S', 'W']
ignore = ['ANN101', 'ANN102', 'ANN401', 'S101']
line-length = 79

[tool.ruff.per-file-ignores]
"test/*" = ['ANN', 'S104']

[tool.pytest.ini_options]
testpaths = 'test'
Expand All @@ -104,19 +109,15 @@ dependencies = [
'mypy',
'pytest',
'pytest-cov',
'flake8',
'flake8-annotations',
'flake8-bugbear',
'bandit[toml]',
'ruff',
]
features = ['crc32c']

[tool.hatch.envs.default.scripts]
run-pytest = 'py.test --cov-report=term-missing --cov=proxyprotocol'
run-mypy = 'mypy proxyprotocol test'
run-flake8 = 'flake8 proxyprotocol test'
run-bandit = 'bandit -c pyproject.toml -qr proxyprotocol'
check = ['run-pytest', 'run-mypy', 'run-flake8', 'run-bandit']
run-ruff = 'ruff proxyprotocol test'
check = ['run-pytest', 'run-mypy', 'run-ruff']

[[tool.hatch.envs.all.matrix]]
python = ['3.8', '3.9', '3.10', '3.11']
Expand Down
4 changes: 4 additions & 0 deletions test/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from typing import Any, Dict
from unittest.mock import MagicMock

import pytest

from proxyprotocol.build import build_socket_result, build_transport_result


Expand Down Expand Up @@ -47,6 +49,8 @@ def test_ipv6_socket(self) -> None:
self.assertEqual(b'uid', res.tlv.unique_id)
self.assertEqual('host', res.tlv.ext.dnsbl)

@pytest.mark.skipif(not hasattr(socket, 'AF_UNIX'),
reason='UNIX sockets not available')
def test_unix_socket(self) -> None:
sock = MagicMock(socket.socket)
sock.family = socket.AF_UNIX
Expand Down
4 changes: 4 additions & 0 deletions test/test_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import unittest
from ipaddress import IPv4Address, IPv6Address

import pytest

from proxyprotocol.result import is_local, is_unknown, \
is_ipv4, is_ipv6, is_unix, ProxyResultLocal, ProxyResultUnknown, \
ProxyResultIPv4, ProxyResultIPv6, ProxyResultUnix
Expand Down Expand Up @@ -91,6 +93,8 @@ def test_result_ipv6_protocol(self) -> None:
"(IPv6Address('::2'), 20), protocol=socket.SOCK_STREAM)",
repr(res))

@pytest.mark.skipif(not hasattr(socket, 'AF_UNIX'),
reason='UNIX sockets not available')
def test_result_unix(self) -> None:
res = ProxyResultUnix('/source.sock', '/dest.sock')
self.assertTrue(is_unix(res))
Expand Down
6 changes: 6 additions & 0 deletions test/test_sock.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from typing import Any, Dict
from unittest.mock import MagicMock

import pytest

from proxyprotocol.result import ProxyResultLocal, ProxyResultUnknown, \
ProxyResultIPv6
from proxyprotocol.sock import SocketInfo, SocketInfoLocal
Expand Down Expand Up @@ -193,6 +195,8 @@ def test_unique_id_override(self) -> None:
info = SocketInfo.get(self.transport, result, unique_id=b'abc')
self.assertEqual(b'1234567890', info.unique_id)

@pytest.mark.skipif(not hasattr(socket, 'AF_UNIX'),
reason='UNIX sockets not available')
def test_from_localhost_unix(self) -> None:
result = ProxyResultLocal()
info = SocketInfo.get(self.transport, result)
Expand All @@ -217,6 +221,8 @@ def test_from_localhost_false(self) -> None:
info = SocketInfo.get(self.transport, result)
self.assertFalse(info.from_localhost)

@pytest.mark.skipif(not hasattr(socket, 'AF_UNIX'),
reason='UNIX sockets not available')
def test_str_unix(self) -> None:
info = SocketInfoLocal(self.transport)
self.extra['sockname'] = 'source'
Expand Down
4 changes: 4 additions & 0 deletions test/test_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import unittest
from ipaddress import IPv4Address, IPv6Address

import pytest

from proxyprotocol import ProxyProtocolSyntaxError, \
ProxyProtocolChecksumError, ProxyProtocolIncompleteError
from proxyprotocol.version import ProxyProtocolVersion
Expand Down Expand Up @@ -132,6 +134,8 @@ def test_unpack_data_inet6(self) -> None:
self.assertEqual('::1', str(res.dest[0]))
self.assertEqual(25, res.dest[1])

@pytest.mark.skipif(not hasattr(socket, 'AF_UNIX'),
reason='UNIX sockets not available')
def test_unpack_data_unix(self) -> None:
pp = ProxyProtocolV2()
header = ProxyProtocolV2Header(command='proxy', family=socket.AF_UNIX,
Expand Down

0 comments on commit 560a674

Please sign in to comment.