Skip to content

Commit bb66dd1

Browse files
committed
Added examples for SNI: examples/sni/sni_examples.py
1 parent d10a92a commit bb66dd1

File tree

1 file changed

+259
-0
lines changed

1 file changed

+259
-0
lines changed

examples/sni/sni_examples.py

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
#!/usr/bin/env python3
2+
"""
3+
SNI (Server Name Indication) protocol examples for py-multiaddr.
4+
5+
This script demonstrates how to use the 'sni' protocol in py-multiaddr,
6+
which is typically used to specify the hostname during the TLS handshake.
7+
8+
## Overview
9+
10+
This script shows various examples of SNI protocol usage:
11+
12+
1. **Basic SNI Usage**: Creating and parsing a basic /sni/hostname address.
13+
2. **Protocol Validation**: Testing valid and invalid hostnames.
14+
3. **Binary Encoding/Decoding**: Working with binary representations.
15+
4. **Multiaddr Integration**: Using 'sni' in a realistic multiaddr string
16+
(e.g., /dns/google.com/tcp/443/tls/sni/google.com).
17+
5. **Error Handling**: Demonstrating errors for invalid domain names.
18+
19+
# Expected Output
20+
21+
When you run this script, you should see output similar to:
22+
23+
```
24+
SNI Protocol Examples
25+
==================================================
26+
=== Basic SNI Usage ===
27+
Original SNI: /sni/protocol.ai
28+
Protocols: ['sni']
29+
Extracted Value: protocol.ai
30+
Binary length: 14 bytes
31+
Valid SNI address: True
32+
33+
=== Protocol Validation ===
34+
Testing valid SNI: /sni/protocol.ai
35+
Valid: True
36+
Value: protocol.ai
37+
38+
Testing invalid SNI (invalid domain chars): /sni/invalid_hostname!
39+
Valid: False Error: invalid_hostname! is not a valid domain name
40+
41+
Testing invalid SNI (empty value): /sni/
42+
Valid: False Error: is not a valid domain name
43+
44+
=== Binary Encoding/Decoding ===
45+
SNI binary operations:
46+
Original: /sni/protocol.ai
47+
Binary: 14 bytes
48+
Round-trip: /sni/protocol.ai
49+
Match: True
50+
51+
=== Multiaddr Integration ===
52+
Complex multiaddr with SNI:
53+
Address: /dns/google.com/tcp/443/tls/sni/google.com
54+
Protocols: ['dns', 'tcp', 'tls', 'sni']
55+
Extracted SNI value: google.com
56+
Match: True
57+
58+
==================================================
59+
All examples completed!
60+
```
61+
62+
## Key features Demonstrated
63+
64+
- **SNI Protocol**: Represents a Server Name Indication value.
65+
- **Validation**: Ensures the value is a valid domain name (as it uses the 'domain' transcoder).
66+
- **Binary Operation**: Encoding and decoding to/from binary format.
67+
- **Multiaddr Integration**: Using 'sni' within a '/tls' protocol.
68+
- **Error Handling**: Proper error handling for invalid domain names.
69+
70+
## Requirements
71+
72+
- Python 3.10+
73+
- py-multiaddr library
74+
75+
## Usage
76+
77+
```bash
78+
python examples/sni_examples.py
79+
```
80+
"""
81+
82+
from multiaddr import Multiaddr
83+
84+
# A valid domain name to use for SNI
85+
VALID_SNI_DOMAIN = "protocol.ai"
86+
VALID_SNI_ADDR = f"/sni/{VALID_SNI_DOMAIN}"
87+
88+
def basic_sni_usage():
89+
"""
90+
Basic SNI usage example
91+
92+
This function demonstrates:
93+
- Creating an SNI multiaddr
94+
- Extracting protocol information
95+
- Extracting the value
96+
- Getting binary representation
97+
"""
98+
99+
print("=== Basic SNI Usage ===")
100+
print(f"Original SNI: {VALID_SNI_ADDR}")
101+
102+
try:
103+
ma = Multiaddr(VALID_SNI_ADDR)
104+
print(f"Protocols: {[p.name for p in ma.protocols()]}")
105+
106+
# Extract the value
107+
sni_value = ma.value_for_protocol('sni')
108+
print(f"Extracted Value: {sni_value}")
109+
110+
# Get binary representation
111+
binary_data = ma.to_bytes()
112+
print(f"Binary length: {len(binary_data)} bytes")
113+
114+
print("Valid SNI address: True")
115+
116+
except Exception as e:
117+
print(f"Error: {e}")
118+
print("Valid SNI address: False")
119+
120+
def protocol_validation():
121+
"""
122+
Demonstrate protocol validation.
123+
124+
This function shows:
125+
- A valid SNI address
126+
- Invalid SNI addresses (invalid domain characters, empty)
127+
- Error handling for validation failures
128+
"""
129+
130+
print("\n=== Protocol Validation ===")
131+
132+
# Test valid SNI
133+
print(f"Testing valid SNI: {VALID_SNI_ADDR}")
134+
try:
135+
ma = Multiaddr(VALID_SNI_ADDR)
136+
print(" Valid: True")
137+
print(f" Value: {ma.value_for_protocol('sni')}")
138+
except Exception as e:
139+
print(" Valid: False")
140+
print(f" Error: {e}")
141+
142+
# Test invalid SNI (invalid characters)
143+
invalid_addr_str = "/sni/invalid_hostname!"
144+
print(f"\nTesting invalid SNI (invalid domain chars): {invalid_addr_str}")
145+
try:
146+
Multiaddr(invalid_addr_str)
147+
print(" Valid: True (ERROR: Should have failed)")
148+
except Exception as e:
149+
print(" Valid: False")
150+
print(f" Error: {e}")
151+
152+
# Test invalid SNI (empty value)
153+
invalid_addr_str = "/sni/"
154+
print(f"\nTesting invalid SNI (empty value): {invalid_addr_str}")
155+
try:
156+
Multiaddr(invalid_addr_str)
157+
print(" Valid: True (ERROR: Should have failed)")
158+
except Exception as e:
159+
print(" Valid: False")
160+
print(f" Error: {e}")
161+
162+
def binary_encoding_decoding():
163+
"""
164+
Demonstrate binary encoding and decoding.
165+
166+
This function shows:
167+
- Converting multiaddr to binary
168+
- Converting binary back to multiaddr
169+
- Round-trip validation
170+
"""
171+
print("\n=== Binary Encoding/Decoding ===")
172+
173+
print("SNI binary operations:")
174+
print(f" Original: {VALID_SNI_ADDR}")
175+
176+
try:
177+
ma = Multiaddr(VALID_SNI_ADDR)
178+
binary_data = ma.to_bytes()
179+
print(f" Binary: {len(binary_data)} bytes")
180+
181+
# Round-trip: binary back to multiaddr
182+
round_trip_ma = Multiaddr(binary_data)
183+
print(f" Round-trip: {round_trip_ma}")
184+
print(f" Match: {str(ma) == str(round_trip_ma)}")
185+
186+
except Exception as e:
187+
print(f" Error: {e}")
188+
189+
def multiaddr_integration():
190+
"""
191+
Demonstrate SNI protocol integration with other protocols.
192+
193+
This function shows:
194+
- The most common use case for /sni, nested within /tls.
195+
- Protocol stack analysis
196+
- SNI value extraction
197+
"""
198+
199+
print("\n=== Multiaddr Integration ===")
200+
201+
# Create a complex multiaddr with SNI
202+
# This is a typical address for a secure websocket connection
203+
sni_host = "google.com"
204+
complex_addr = f"/dns/google.com/tcp/443/tls/sni/{sni_host}"
205+
206+
print("Complex multiaddr with SNI:")
207+
print(f" Address: {complex_addr}")
208+
209+
try:
210+
ma = Multiaddr(complex_addr)
211+
protocols = [p.name for p in ma.protocols()]
212+
print(f" Protocols: {protocols}")
213+
214+
# Extract SNI value
215+
extracted_sni_value = ma.value_for_protocol('sni')
216+
print(f" Extracted SNI value: {extracted_sni_value}")
217+
print(f" Match: {extracted_sni_value == sni_host}")
218+
219+
except Exception as e:
220+
print(f" Error: {e}")
221+
222+
def main():
223+
"""
224+
Run all SNI protocol examples.
225+
226+
This function orchestrates all the SNI protocol examples:
227+
1. Basic SNI usage
228+
2. Protocol validation
229+
3. Binary encoding/decoding
230+
4. Multiaddr integration
231+
232+
Each example demonstrates different aspects of SNI protocol functionality
233+
and shows how to use it with py-multiaddr.
234+
"""
235+
print("SNI (Server Name Indication) Protocol Examples")
236+
print("=" * 50)
237+
238+
try:
239+
basic_sni_usage()
240+
protocol_validation()
241+
binary_encoding_decoding()
242+
multiaddr_integration()
243+
244+
print("\n" + "=" * 50)
245+
print("All examples completed!")
246+
print("\nSummary:")
247+
print("- SNI protocol is working correctly")
248+
print("- Binary encoding/decoding functions properly")
249+
print("- Validation catches invalid domain names")
250+
print("- Integration with /tls protocol works as expected")
251+
252+
except KeyboardInterrupt:
253+
print("\nExamples interrupted by user")
254+
except Exception as e:
255+
print(f"\nUnexpected error: {e}")
256+
257+
258+
if __name__ == "__main__":
259+
main()

0 commit comments

Comments
 (0)