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"\n Testing 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"\n Testing 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 ("\n Summary:" )
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 ("\n Examples interrupted by user" )
254+ except Exception as e :
255+ print (f"\n Unexpected error: { e } " )
256+
257+
258+ if __name__ == "__main__" :
259+ main ()
0 commit comments