Skip to content

Commit 4b189bc

Browse files
authored
Only accept numeric address in getnameinfo (#2003)
* Only accept numeric address in getnameinfo * Simplify getnameinfo implementation * Add some test cases * Don't check host name
1 parent 2062028 commit 4b189bc

4 files changed

Lines changed: 45 additions & 45 deletions

File tree

src/core/IronPython.Modules/_socket.cs

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,8 @@ public static object getnameinfo(CodeContext/*!*/ context, [NotNone] PythonTuple
11511151

11521152
string host = Converter.ConvertToString(socketAddr[0]);
11531153
if (host == null) throw PythonOps.TypeError("argument 1 must be string");
1154-
int port = 0;
1154+
1155+
int port;
11551156
try {
11561157
port = (int)socketAddr[1]!;
11571158
} catch (InvalidCastException) {
@@ -1167,60 +1168,45 @@ public static object getnameinfo(CodeContext/*!*/ context, [NotNone] PythonTuple
11671168
}
11681169
}
11691170

1170-
string resultHost;
1171-
string resultPort;
1172-
11731171
// Host
1174-
IList<IPAddress> addrs;
1175-
try {
1176-
addrs = HostToAddresses(context, host, AddressFamily.InterNetwork);
1177-
} catch (IndexOutOfRangeException) {
1172+
if (!IPAddress.TryParse(host, out IPAddress? addr)) {
11781173
throw MakeGaiException(context, EAI_NODATA);
11791174
}
11801175

1181-
if (addrs.Count > 1) {
1182-
// ignore non-IPV4 addresses
1183-
List<IPAddress> newAddrs = new List<IPAddress>(addrs.Count);
1184-
foreach (IPAddress addr in addrs) {
1185-
if (addr.AddressFamily == AddressFamily.InterNetwork) {
1186-
newAddrs.Add(addr);
1176+
string resultHost;
1177+
if ((flags & NI_NUMERICHOST) != 0) {
1178+
resultHost = addr.ToString();
1179+
} else {
1180+
string hostName;
1181+
if (addr.Equals(IPAddress.Any) || addr.Equals(IPAddress.IPv6Any)) {
1182+
hostName = Dns.GetHostName();
1183+
} else {
1184+
try {
1185+
hostName = Dns.GetHostEntry(addr).HostName;
1186+
} catch (SocketException ex) {
1187+
throw MakeGaiException(context, ex);
11871188
}
11881189
}
1189-
if (newAddrs.Count > 1) {
1190-
throw PythonExceptions.CreateThrowable(error, "sockaddr resolved to multiple addresses");
1191-
}
1192-
addrs = newAddrs;
1193-
}
11941190

1195-
if (addrs.Count < 1) {
1196-
throw MakeGaiException(context, EAI_NODATA);
1197-
}
1198-
1199-
IPHostEntry hostEntry;
1200-
try {
1201-
hostEntry = Dns.GetHostEntry(addrs[0]);
1202-
} catch (SocketException ex) {
1203-
throw MakeGaiException(context, ex);
1204-
}
1205-
if ((flags & (int)NI_NUMERICHOST) != 0) {
1206-
resultHost = addrs[0].ToString();
1207-
} else if ((flags & (int)NI_NOFQDN) != 0) {
1208-
resultHost = RemoveLocalDomain(hostEntry.HostName);
1209-
} else {
1210-
resultHost = hostEntry.HostName;
1191+
if ((flags & NI_NOFQDN) != 0) {
1192+
resultHost = RemoveLocalDomain(hostName);
1193+
} else {
1194+
resultHost = hostName;
1195+
}
12111196
}
12121197

12131198
// Port
1214-
if ((flags & (int)NI_NUMERICSERV) == 0) {
1199+
string resultPort;
1200+
if ((flags & NI_NUMERICSERV) == 0) {
12151201
//call the servbyport to translate port if not just use the port.ToString as the result
12161202
try {
12171203
resultPort = getservbyport(context, port);
12181204
} catch {
12191205
resultPort = port.ToString();
12201206
}
1221-
flags = flags | (int)NI_NUMERICSERV;
1222-
} else
1207+
} else {
12231208
resultPort = port.ToString();
1209+
}
12241210

12251211
return PythonTuple.MakeTuple(resultHost, resultPort);
12261212
}
@@ -2032,7 +2018,7 @@ private static IPAddress[] HostToAddresses(CodeContext/*!*/ context, string host
20322018
if (addrs.Count > 0) return addrs.ToArray();
20332019
}
20342020
throw MakeGaiException(context, EAI_NODATA);
2035-
} catch (SocketException ex) {
2021+
} catch (SocketException ex) {
20362022
throw MakeGaiException(context, ex);
20372023
}
20382024
}

src/core/IronPython/Runtime/Operations/StringOps.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ public static bool isalpha([NotNone] this string self) {
623623
return true;
624624
}
625625

626+
// new in Python 3.7
626627
public static bool isascii([NotNone] this string self) {
627628
foreach (char c in self) {
628629
if (c > 0x7f) return false;

tests/suite/modules/network_related/test__socket.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,12 +352,29 @@ def test_getnameinfo(self):
352352
host, service = _socket.getnameinfo( ("127.0.0.1", 80), 0)
353353
self.assertEqual(service, "http")
354354
#IP gives a TypeError
355-
#self.assertRaises(SystemError, _socket.getnameinfo, ("127.0.0.1"), 8)
356-
#self.assertRaises(SystemError, _socket.getnameinfo, (321), 8)
355+
self.assertRaises(TypeError, _socket.getnameinfo, ("127.0.0.1"), 8)
356+
self.assertRaises(TypeError, _socket.getnameinfo, (321), 8)
357357
self.assertRaises(TypeError, _socket.getnameinfo, ("127.0.0.1"), '0')
358358
self.assertRaises(TypeError, _socket.getnameinfo, ("127.0.0.1", 80, 0, 0, 0), 8)
359359
self.assertRaises(_socket.gaierror, _socket.getnameinfo, ('no such host will ever exist', 80), 8)
360360

361+
# try some IPv6 cases
362+
ports = {
363+
80: "http",
364+
443: "https",
365+
}
366+
367+
addresses = ["::1", "::", "::0"]
368+
address_num = {"::0": "::"}
369+
370+
for address in addresses:
371+
for port, port_name in ports.items():
372+
res = _socket.getnameinfo((address, port), 0)
373+
# don't check the host name, unreliable across platforms
374+
self.assertEqual(res[1], port_name)
375+
res = _socket.getnameinfo((address, port), _socket.NI_NUMERICHOST | _socket.NI_NUMERICSERV)
376+
self.assertEqual(res, (address_num.get(address, address), str(port)))
377+
361378
def test_gethostbyaddr(self):
362379
'''Tests _socket.gethostbyaddr'''
363380
_socket.gethostbyaddr("localhost")

tests/suite/test_socket_stdlib.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ def load_tests(loader, standard_tests, pattern):
4141
failing_tests += [
4242
test.test_socket.NonBlockingTCPTests('testRecv'), # TODO: figure out
4343
]
44-
if not is_mono:
45-
failing_tests += [
46-
test.test_socket.GeneralModuleTests('test_getnameinfo'), # https://github.com/IronLanguages/ironpython3/issues/1222
47-
]
4844
if is_linux:
4945
failing_tests += [
5046
test.test_socket.GeneralModuleTests('test_idna'), # TODO: figure out

0 commit comments

Comments
 (0)