|
18 | 18 | Classes use __slots__ to ensure extraneous attributes aren't accidentally added
|
19 | 19 | by tests, compromising their intended effect.
|
20 | 20 | """
|
| 21 | +from base64 import b32decode, b32encode |
21 | 22 | from codecs import encode
|
22 | 23 | import copy
|
23 | 24 | import hashlib
|
@@ -207,15 +208,20 @@ class CAddress:
|
207 | 208 |
|
208 | 209 | # see https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki
|
209 | 210 | NET_IPV4 = 1
|
| 211 | + NET_I2P = 5 |
210 | 212 |
|
211 | 213 | ADDRV2_NET_NAME = {
|
212 |
| - NET_IPV4: "IPv4" |
| 214 | + NET_IPV4: "IPv4", |
| 215 | + NET_I2P: "I2P" |
213 | 216 | }
|
214 | 217 |
|
215 | 218 | ADDRV2_ADDRESS_LENGTH = {
|
216 |
| - NET_IPV4: 4 |
| 219 | + NET_IPV4: 4, |
| 220 | + NET_I2P: 32 |
217 | 221 | }
|
218 | 222 |
|
| 223 | + I2P_PAD = "====" |
| 224 | + |
219 | 225 | def __init__(self):
|
220 | 226 | self.time = 0
|
221 | 227 | self.nServices = 1
|
@@ -255,24 +261,33 @@ def deserialize_v2(self, f):
|
255 | 261 | self.nServices = deser_compact_size(f)
|
256 | 262 |
|
257 | 263 | self.net = struct.unpack("B", f.read(1))[0]
|
258 |
| - assert self.net == self.NET_IPV4 |
| 264 | + assert self.net in (self.NET_IPV4, self.NET_I2P) |
259 | 265 |
|
260 | 266 | address_length = deser_compact_size(f)
|
261 | 267 | assert address_length == self.ADDRV2_ADDRESS_LENGTH[self.net]
|
262 | 268 |
|
263 |
| - self.ip = socket.inet_ntoa(f.read(4)) |
| 269 | + addr_bytes = f.read(address_length) |
| 270 | + if self.net == self.NET_IPV4: |
| 271 | + self.ip = socket.inet_ntoa(addr_bytes) |
| 272 | + else: |
| 273 | + self.ip = b32encode(addr_bytes)[0:-len(self.I2P_PAD)].decode("ascii").lower() + ".b32.i2p" |
264 | 274 |
|
265 | 275 | self.port = struct.unpack(">H", f.read(2))[0]
|
266 | 276 |
|
267 | 277 | def serialize_v2(self):
|
268 | 278 | """Serialize in addrv2 format (BIP155)"""
|
269 |
| - assert self.net == self.NET_IPV4 |
| 279 | + assert self.net in (self.NET_IPV4, self.NET_I2P) |
270 | 280 | r = b""
|
271 | 281 | r += struct.pack("<I", self.time)
|
272 | 282 | r += ser_compact_size(self.nServices)
|
273 | 283 | r += struct.pack("B", self.net)
|
274 | 284 | r += ser_compact_size(self.ADDRV2_ADDRESS_LENGTH[self.net])
|
275 |
| - r += socket.inet_aton(self.ip) |
| 285 | + if self.net == self.NET_IPV4: |
| 286 | + r += socket.inet_aton(self.ip) |
| 287 | + else: |
| 288 | + sfx = ".b32.i2p" |
| 289 | + assert self.ip.endswith(sfx) |
| 290 | + r += b32decode(self.ip[0:-len(sfx)] + self.I2P_PAD, True) |
276 | 291 | r += struct.pack(">H", self.port)
|
277 | 292 | return r
|
278 | 293 |
|
|
0 commit comments