Skip to content

Commit a04783d

Browse files
hohMHHukiewitz
authored andcommitted
Fix: socket.getaddrinfo does not always return 2 values
A user reported that this function crashed on his host due to `ValueError: too many values to unpack (expected 2)`. Solution: Process each returned tuple instead of assuming that two of them are always returned. This fixes the issue both in the orchestrator and in the diagnostic VM.
1 parent 76e8adc commit a04783d

File tree

2 files changed

+51
-13
lines changed

2 files changed

+51
-13
lines changed

examples/example_fastapi/main.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
from datetime import datetime
88
from os import listdir
99
from pathlib import Path
10-
from typing import Dict
10+
from typing import Dict, Optional
1111

1212
import aiohttp
1313
from fastapi import FastAPI
1414
from fastapi.responses import PlainTextResponse
1515
from pip._internal.operations.freeze import freeze
1616
from pydantic import BaseModel
17+
from starlette.responses import JSONResponse
1718

1819
from aleph.sdk.chains.remote import RemoteAccount
1920
from aleph.sdk.client import AlephClient, AuthenticatedAlephClient
@@ -91,13 +92,31 @@ async def read_aleph_messages():
9192
@app.get("/dns")
9293
async def resolve_dns_hostname():
9394
"""Check if DNS resolution is working."""
94-
info_inet, info_inet6 = socket.getaddrinfo("example.org", 80, proto=socket.IPPROTO_TCP)
95-
ipv4 = info_inet[4][0]
96-
ipv6 = info_inet6[4][0]
97-
return {
98-
"ipv4": ipv4,
99-
"ipv6": ipv6,
100-
}
95+
hostname = "example.org"
96+
ipv4: Optional[str] = None
97+
ipv6: Optional[str] = None
98+
99+
info = socket.getaddrinfo(hostname, 80, proto=socket.IPPROTO_TCP)
100+
if not info:
101+
logger.error("DNS resolution failed")
102+
103+
# Iterate over the results to find the IPv4 and IPv6 addresses they may not all be present.
104+
# The function returns a list of 5-tuples with the following structure:
105+
# (family, type, proto, canonname, sockaddr)
106+
for info_tuple in info:
107+
if info_tuple[0] == socket.AF_INET:
108+
ipv4 = info_tuple[4][0]
109+
elif info_tuple[0] == socket.AF_INET6:
110+
ipv6 = info_tuple[4][0]
111+
112+
if ipv4 and not ipv6:
113+
logger.warning(f"DNS resolution for {hostname} returned only an IPv4 address")
114+
elif ipv6 and not ipv4:
115+
logger.warning(f"DNS resolution for {hostname} returned only an IPv6 address")
116+
117+
result = {"ipv4": ipv4, "ipv6": ipv6}
118+
status_code = 200 if len(info) > 1 else 503
119+
return JSONResponse(content=result, status_code=status_code)
101120

102121

103122
@app.get("/ip/address")

src/aleph/vm/orchestrator/views/host_status.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
import socket
3-
from typing import Any, Awaitable, Callable, Tuple
3+
from typing import Any, Awaitable, Callable, Optional, Tuple
44

55
import aiohttp
66

@@ -45,10 +45,29 @@ async def check_host_egress_ipv6() -> bool:
4545
return await check_ip_connectivity(settings.CONNECTIVITY_IPV6_URL)
4646

4747

48-
async def resolve_dns(hostname: str) -> Tuple[str, str]:
49-
info_inet, info_inet6 = socket.getaddrinfo(hostname, 80, proto=socket.IPPROTO_TCP)
50-
ipv4 = info_inet[4][0]
51-
ipv6 = info_inet6[4][0]
48+
async def resolve_dns(hostname: str) -> Tuple[Optional[str], Optional[str]]:
49+
"""Resolve a hostname to an IPv4 and IPv6 address."""
50+
ipv4: Optional[str] = None
51+
ipv6: Optional[str] = None
52+
53+
info = socket.getaddrinfo(hostname, 80, proto=socket.IPPROTO_TCP)
54+
if not info:
55+
logger.error("DNS resolution failed")
56+
57+
# Iterate over the results to find the IPv4 and IPv6 addresses they may not all be present.
58+
# The function returns a list of 5-tuples with the following structure:
59+
# (family, type, proto, canonname, sockaddr)
60+
for info_tuple in info:
61+
if info_tuple[0] == socket.AF_INET:
62+
ipv4 = info_tuple[4][0]
63+
elif info_tuple[0] == socket.AF_INET6:
64+
ipv6 = info_tuple[4][0]
65+
66+
if ipv4 and not ipv6:
67+
logger.warning(f"DNS resolution for {hostname} returned only an IPv4 address")
68+
elif ipv6 and not ipv4:
69+
logger.warning(f"DNS resolution for {hostname} returned only an IPv6 address")
70+
5271
return ipv4, ipv6
5372

5473

0 commit comments

Comments
 (0)