Skip to content

Commit 5bd097b

Browse files
authored
Feat/fix issue 72 thin waist address validation (#77)
* feat: add thin waist address module and psutil dep * doc: add doc for thin waist address module
1 parent e36af28 commit 5bd097b

File tree

10 files changed

+550
-10
lines changed

10 files changed

+550
-10
lines changed

README.rst

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,28 +97,27 @@ Multiaddr allows expressing tunnels very nicely.
9797
# /ip4/10.20.30.40/tcp/443
9898
9999
DNS Resolution
100-
-------------
100+
--------------
101101

102-
Multiaddr supports DNS-based address resolution using the DNSADDR protocol.
102+
Multiaddr supports DNS-based address resolution using the DNSADDR protocol. This is particularly useful for resolving bootstrap node addresses and maintaining peer IDs during resolution.
103103

104104

105105
.. code-block:: python
106106
107107
from multiaddr import Multiaddr
108+
import trio
108109
109-
# Create a DNSADDR multiaddr
110-
ma = Multiaddr("/dnsaddr/example.com")
111-
112-
# Resolve to actual IP addresses
110+
# Basic DNS resolution
111+
ma = Multiaddr("/dns/example.com")
113112
resolved = await ma.resolve()
114113
print(resolved)
115114
# [Multiaddr("/ip4/93.184.216.34"), Multiaddr("/ip6/2606:2800:220:1:248:1893:25c8:1946")]
116115
117-
# DNSADDR with peer ID
118-
ma_with_peer = Multiaddr("/dnsaddr/example.com/p2p/QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7wjh53Qk")
116+
# DNSADDR with peer ID (bootstrap node style)
117+
ma_with_peer = Multiaddr("/dnsaddr/github.com/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN")
119118
resolved_with_peer = await ma_with_peer.resolve()
120119
print(resolved_with_peer)
121-
# [Multiaddr("/ip4/93.184.216.34/p2p/QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7wjh53Qk")]
120+
# [Multiaddr("/ip4/140.82.121.4/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN")]
122121
123122
# Using the DNS resolver directly
124123
from multiaddr.resolvers import DNSResolver
@@ -127,6 +126,76 @@ Multiaddr supports DNS-based address resolution using the DNSADDR protocol.
127126
print(resolved)
128127
# [Multiaddr("/ip4/93.184.216.34"), Multiaddr("/ip6/2606:2800:220:1:248:1893:25c8:1946")]
129128
129+
# Peer ID preservation test
130+
original_peer_id = ma_with_peer.get_peer_id()
131+
print(f"Original peer ID: {original_peer_id}")
132+
# Original peer ID: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
133+
134+
for resolved_addr in resolved_with_peer:
135+
preserved_peer_id = resolved_addr.get_peer_id()
136+
print(f"Resolved peer ID: {preserved_peer_id}")
137+
# Resolved peer ID: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
138+
139+
For comprehensive examples including bootstrap node resolution, protocol comparison, and py-libp2p integration, see the `DNS examples <https://github.com/multiformats/py-multiaddr/tree/master/examples/dns>`_ in the examples directory.
140+
141+
Thin Waist Address Validation
142+
-----------------------------
143+
144+
Multiaddr provides thin waist address validation functionality to process multiaddrs and expand wildcard addresses to all available network interfaces. This is particularly useful for server configuration, network discovery, and dynamic port management.
145+
146+
147+
.. code-block:: python
148+
149+
from multiaddr import Multiaddr
150+
from multiaddr.utils import get_thin_waist_addresses, get_network_addrs
151+
152+
# Network interface discovery
153+
ipv4_addrs = get_network_addrs(4)
154+
print(f"Available IPv4 addresses: {ipv4_addrs}")
155+
# Available IPv4 addresses: ['192.168.1.12', '10.152.168.99']
156+
157+
# Specific address (no expansion)
158+
addr = Multiaddr("/ip4/192.168.1.100/tcp/8080")
159+
result = get_thin_waist_addresses(addr)
160+
print(result)
161+
# [<Multiaddr /ip4/192.168.1.100/tcp/8080>]
162+
163+
# IPv4 wildcard expansion
164+
addr = Multiaddr("/ip4/0.0.0.0/tcp/8080")
165+
result = get_thin_waist_addresses(addr)
166+
print(result)
167+
# [<Multiaddr /ip4/192.168.1.12/tcp/8080>, <Multiaddr /ip4/10.152.168.99/tcp/8080>]
168+
169+
# IPv6 wildcard expansion
170+
addr = Multiaddr("/ip6/::/tcp/8080")
171+
result = get_thin_waist_addresses(addr)
172+
print(result)
173+
# [<Multiaddr /ip6/fd9b:9eba:8224:1:41a1:8939:231a:b414/tcp/8080>]
174+
175+
# Port override
176+
addr = Multiaddr("/ip4/0.0.0.0/tcp/8080")
177+
result = get_thin_waist_addresses(addr, port=9000)
178+
print(result)
179+
# [<Multiaddr /ip4/192.168.1.12/tcp/9000>, <Multiaddr /ip4/10.152.168.99/tcp/9000>]
180+
181+
# UDP transport support
182+
addr = Multiaddr("/ip4/0.0.0.0/udp/1234")
183+
result = get_thin_waist_addresses(addr)
184+
print(result)
185+
# [<Multiaddr /ip4/192.168.1.12/udp/1234>, <Multiaddr /ip4/10.152.168.99/udp/1234>]
186+
187+
# Server binding scenario
188+
wildcard = Multiaddr("/ip4/0.0.0.0/tcp/8080")
189+
interfaces = get_thin_waist_addresses(wildcard)
190+
print("Available interfaces for server binding:")
191+
for i, interface in enumerate(interfaces, 1):
192+
print(f" {i}. {interface}")
193+
# Available interfaces for server binding:
194+
# 1. /ip4/192.168.1.12/tcp/8080
195+
# 2. /ip4/10.152.168.99/tcp/8080
196+
197+
For comprehensive examples including error handling, practical usage scenarios, and detailed network interface information, see the `thin waist examples <https://github.com/multiformats/py-multiaddr/tree/master/examples/thin_waist>`_ in the examples directory.
198+
130199
Maintainers
131200
===========
132201

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ Contents:
1616
contributing
1717
authors
1818
history
19+
modules
1920

2021
Indices and tables
2122
==================
2223

2324
* :ref:`genindex`
2425
* :ref:`modindex`
2526
* :ref:`search`
26-

docs/multiaddr.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ multiaddr.transforms module
4545
:show-inheritance:
4646
:undoc-members:
4747

48+
multiaddr.utils module
49+
----------------------
50+
51+
.. automodule:: multiaddr.utils
52+
:members:
53+
:show-inheritance:
54+
:undoc-members:
55+
4856
Module contents
4957
---------------
5058

examples/thin_waist/README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Thin Waist Address Validation Examples
2+
3+
This directory contains examples demonstrating how to use the thin waist address validation functionality in the Python multiaddr library.
4+
5+
## What is Thin Waist Address Validation?
6+
7+
Thin waist address validation is a technique used in libp2p to:
8+
- Process multiaddrs and extract thin waist addresses (IP + transport protocol)
9+
- Expand wildcard addresses (like `0.0.0.0` or `::`) to all available network interfaces
10+
- Override ports when needed
11+
- Filter out link-local addresses
12+
13+
## Example File
14+
15+
### `thin_waist_example.py`
16+
17+
A comprehensive example that demonstrates all aspects of thin waist address validation.
18+
19+
**Usage:**
20+
```bash
21+
# Basic examples only
22+
python examples/thin_waist/thin_waist_example.py
23+
24+
# Detailed examples with edge cases and practical scenarios
25+
python examples/thin_waist/thin_waist_example.py --detailed
26+
```
27+
28+
**What it demonstrates:**
29+
30+
**Basic Examples:**
31+
1. Specific IP addresses (no expansion)
32+
2. IPv4 wildcard expansion (`0.0.0.0` → all IPv4 interfaces)
33+
3. IPv6 wildcard expansion (`::` → all IPv6 interfaces)
34+
4. Port override functionality
35+
5. Handling empty input
36+
37+
**Detailed Examples (with `--detailed` flag):**
38+
6. UDP transport support
39+
7. Port override on specific addresses
40+
8. Error handling for invalid multiaddrs
41+
9. Server binding scenarios
42+
10. Dynamic port configuration
43+
44+
## Key Functions
45+
46+
### `get_thin_waist_addresses(ma=None, port=None)`
47+
48+
The main function for thin waist address validation.
49+
50+
**Parameters:**
51+
- `ma`: A Multiaddr object (optional)
52+
- `port`: Port number to override (optional)
53+
54+
**Returns:**
55+
- List of Multiaddr objects representing thin waist addresses
56+
57+
**Examples:**
58+
59+
```python
60+
from multiaddr import Multiaddr
61+
from multiaddr.utils import get_thin_waist_addresses
62+
63+
# Specific address (no expansion)
64+
addr = Multiaddr('/ip4/192.168.1.100/tcp/8080')
65+
result = get_thin_waist_addresses(addr)
66+
# Returns: [<Multiaddr /ip4/192.168.1.100/tcp/8080>]
67+
68+
# Wildcard expansion
69+
addr = Multiaddr('/ip4/0.0.0.0/tcp/8080')
70+
result = get_thin_waist_addresses(addr)
71+
# Returns: [<Multiaddr /ip4/192.168.1.12/tcp/8080>, <Multiaddr /ip4/10.152.168.99/tcp/8080>]
72+
73+
# Port override
74+
addr = Multiaddr('/ip4/0.0.0.0/tcp/8080')
75+
result = get_thin_waist_addresses(addr, port=9000)
76+
# Returns: [<Multiaddr /ip4/192.168.1.12/tcp/9000>, <Multiaddr /ip4/10.152.168.99/tcp/9000>]
77+
```
78+
79+
## Use Cases
80+
81+
1. **Server Configuration**: Expand wildcard addresses to bind to all interfaces
82+
2. **Network Discovery**: Find all available network interfaces
83+
3. **Port Management**: Override ports in multiaddrs
84+
4. **Address Validation**: Ensure multiaddrs represent valid thin waist addresses
85+
86+
## Requirements
87+
88+
- Python 3.9+
89+
- `multiaddr` library with `psutil` dependency
90+
- Network interfaces to demonstrate wildcard expansion
91+
92+
## Running the Example
93+
94+
Make sure you have the virtual environment activated and all dependencies installed:
95+
96+
```bash
97+
# Activate virtual environment
98+
source venv/bin/activate
99+
100+
# Run basic examples
101+
python examples/thin_waist/thin_waist_example.py
102+
103+
# Run detailed examples
104+
python examples/thin_waist/thin_waist_example.py --detailed
105+
```
106+
107+
The output will show your actual network interfaces and demonstrate how wildcard addresses are expanded to specific IP addresses on your system.

0 commit comments

Comments
 (0)