Skip to content

Commit dbd5f00

Browse files
FaramosCZclaude
andcommitted
MDEV-39169 Replace deprecated network functions in resolveip
Replace inet_aton/inet_addr/gethostbyname/gethostbyaddr with their modern POSIX equivalents inet_pton/getaddrinfo/getnameinfo. This adds IPv6 support to resolveip and removes dependency on the deprecated h_errno global. Handle IPv6 unspecified address (::) as Null-IP-Addr, consistent with existing IPv4 INADDR_ANY handling for 0.0.0.0. Add MTR test covering IPv4/IPv6 reverse lookups, special addresses, multiple arguments, mixed address types, and invalid hostname handling. Co-Authored-By: Claude AI <noreply@anthropic.com>
1 parent 685e0f8 commit dbd5f00

5 files changed

Lines changed: 267 additions & 71 deletions

File tree

extra/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ TARGET_LINK_LIBRARIES(resolveip mysys)
5959
IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
6060
INCLUDE(CheckFunctionExists)
6161
INCLUDE(CheckLibraryExists)
62-
MY_SEARCH_LIBS(inet_aton "nsl;socket;resolv" SOLARIS_NSL)
62+
MY_SEARCH_LIBS(getaddrinfo "nsl;socket;resolv" SOLARIS_NSL)
6363
TARGET_LINK_LIBRARIES(resolveip ${SOLARIS_NSL})
6464
ENDIF()
6565
ENDIF()

extra/resolveip.c

Lines changed: 108 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
/* Resolves IP's to hostname and hostnames to IP's */
1818

19-
#define VER "2.3"
19+
#define VER "2.4"
2020

2121
#include <my_global.h>
2222
#include <m_ctype.h>
@@ -33,9 +33,6 @@
3333
#include <my_getopt.h>
3434
#include <welcome_copyright_notice.h>
3535

36-
#if !defined(_AIX) && !defined(h_errno)
37-
extern int h_errno;
38-
#endif
3936

4037
static my_bool silent;
4138

@@ -104,9 +101,7 @@ static int get_options(int *argc,char ***argv)
104101

105102
int main(int argc, char **argv)
106103
{
107-
struct hostent *hpaddr;
108-
in_addr_t taddr;
109-
char *ip,**q;
104+
char *ip;
110105
int error=0;
111106

112107
MY_INIT(argv[0]);
@@ -119,92 +114,135 @@ int main(int argc, char **argv)
119114

120115
while (argc--)
121116
{
122-
my_bool do_more;
123-
#ifndef WIN32
124-
struct in_addr addr;
125-
#endif
126-
ip = *argv++;
127-
128-
/* Not compatible with IPv6! Probably should use getnameinfo(). */
129-
#ifdef WIN32
130-
taddr = inet_addr(ip);
131-
do_more= (taddr != INADDR_NONE);
132-
#else
133-
if ((do_more= (inet_aton(ip, &addr) != 0)))
134-
taddr= addr.s_addr;
135-
#endif
136-
if (do_more)
117+
struct in_addr addr4;
118+
struct in6_addr addr6;
119+
int is_ipv4, is_ipv6;
120+
121+
ip = *argv++;
122+
123+
is_ipv4= (inet_pton(AF_INET, ip, &addr4) == 1);
124+
is_ipv6= (!is_ipv4 && inet_pton(AF_INET6, ip, &addr6) == 1);
125+
126+
if (is_ipv4 || is_ipv6)
137127
{
138-
if (taddr == htonl(INADDR_BROADCAST))
139-
{
140-
puts("Broadcast");
141-
continue;
128+
/* Reverse lookup: IP address -> hostname */
129+
130+
if (is_ipv4)
131+
{
132+
in_addr_t taddr= addr4.s_addr;
133+
if (taddr == htonl(INADDR_BROADCAST))
134+
{
135+
puts("Broadcast");
136+
continue;
137+
}
138+
if (taddr == htonl(INADDR_ANY))
139+
{
140+
if (!taddr)
141+
puts("Null-IP-Addr");
142+
else
143+
puts("Old-Bcast");
144+
continue;
145+
}
142146
}
143-
if (taddr == htonl(INADDR_ANY))
147+
else if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
144148
{
145-
if (!taddr)
146-
puts("Null-IP-Addr");
147-
else
148-
puts("Old-Bcast");
149+
puts("Null-IP-Addr");
149150
continue;
150151
}
151152

152-
hpaddr = gethostbyaddr((char*) &(taddr), sizeof(struct in_addr),AF_INET);
153-
if (hpaddr)
154153
{
155-
if (silent)
156-
puts(hpaddr->h_name);
154+
struct sockaddr_storage sa;
155+
socklen_t sa_len;
156+
char hostname[NI_MAXHOST];
157+
int err;
158+
159+
memset(&sa, 0, sizeof(sa));
160+
161+
if (is_ipv4)
162+
{
163+
struct sockaddr_in *sa4= (struct sockaddr_in *) &sa;
164+
sa4->sin_family= AF_INET;
165+
sa4->sin_addr= addr4;
166+
sa_len= sizeof(struct sockaddr_in);
167+
}
157168
else
158169
{
159-
printf ("Host name of %s is %s", ip,hpaddr->h_name);
160-
for (q = hpaddr->h_aliases; *q != 0; q++)
161-
(void) printf(", %s", *q);
162-
puts("");
170+
struct sockaddr_in6 *sa6= (struct sockaddr_in6 *) &sa;
171+
sa6->sin6_family= AF_INET6;
172+
sa6->sin6_addr= addr6;
173+
sa_len= sizeof(struct sockaddr_in6);
174+
}
175+
176+
err= getnameinfo((struct sockaddr *) &sa, sa_len,
177+
hostname, sizeof(hostname), NULL, 0, NI_NAMEREQD);
178+
if (err == 0)
179+
{
180+
if (silent)
181+
puts(hostname);
182+
else
183+
printf("Host name of %s is %s\n", ip, hostname);
184+
}
185+
else
186+
{
187+
error= 2;
188+
fflush(stdout);
189+
fprintf(stderr, "%s: Unable to find hostname for '%s'\n",
190+
my_progname, ip);
163191
}
164-
}
165-
else
166-
{
167-
error=2;
168-
fprintf(stderr,"%s: Unable to find hostname for '%s'\n",my_progname,
169-
ip);
170192
}
171193
}
172194
else
173195
{
174-
hpaddr = gethostbyname(ip);
175-
if (!hpaddr)
196+
/* Forward lookup: hostname -> IP address(es) */
197+
198+
struct addrinfo hints, *res, *rp;
199+
int err;
200+
201+
memset(&hints, 0, sizeof(hints));
202+
hints.ai_family= AF_UNSPEC;
203+
hints.ai_socktype= SOCK_STREAM;
204+
205+
err= getaddrinfo(ip, NULL, &hints, &res);
206+
if (err != 0)
176207
{
177-
const char *err;
178-
fprintf(stderr,"%s: Unable to find hostid for '%s'",my_progname,ip);
179-
switch (h_errno) {
180-
case HOST_NOT_FOUND: err="host not found"; break;
181-
case TRY_AGAIN: err="try again"; break;
182-
case NO_RECOVERY: err="no recovery"; break;
183-
case NO_DATA: err="no_data"; break;
184-
default: err=0;
185-
}
186-
if (err)
187-
fprintf(stderr,": %s\n",err);
188-
else
189-
fprintf(stderr,"\n");
190-
error=2;
208+
fflush(stdout);
209+
fprintf(stderr, "%s: Unable to find hostid for '%s': %s\n",
210+
my_progname, ip, gai_strerror(err));
211+
error= 2;
191212
}
192213
else if (silent)
193214
{
194-
struct in_addr in;
195-
memcpy((char*) &in.s_addr, (char*) *hpaddr->h_addr_list,
196-
sizeof (in.s_addr));
197-
puts(inet_ntoa(in));
215+
char addr_str[INET6_ADDRSTRLEN];
216+
const void *addr_ptr;
217+
218+
if (res->ai_family == AF_INET)
219+
addr_ptr= &((struct sockaddr_in *) res->ai_addr)->sin_addr;
220+
else
221+
addr_ptr= &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
222+
223+
if (inet_ntop(res->ai_family, addr_ptr, addr_str, sizeof(addr_str)))
224+
puts(addr_str);
225+
226+
freeaddrinfo(res);
198227
}
199228
else
200229
{
201-
char **p;
202-
for (p = hpaddr->h_addr_list; *p != 0; p++)
230+
for (rp= res; rp != NULL; rp= rp->ai_next)
203231
{
204-
struct in_addr in;
205-
memcpy(&in.s_addr, *p, sizeof (in.s_addr));
206-
printf ("IP address of %s is %s\n",ip,inet_ntoa(in));
232+
char addr_str[INET6_ADDRSTRLEN];
233+
const void *addr_ptr;
234+
235+
if (rp->ai_family == AF_INET)
236+
addr_ptr= &((struct sockaddr_in *) rp->ai_addr)->sin_addr;
237+
else if (rp->ai_family == AF_INET6)
238+
addr_ptr= &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr;
239+
else
240+
continue;
241+
242+
if (inet_ntop(rp->ai_family, addr_ptr, addr_str, sizeof(addr_str)))
243+
printf("IP address of %s is %s\n", ip, addr_str);
207244
}
245+
freeaddrinfo(res);
208246
}
209247
}
210248
}

mysql-test/main/resolveip.result

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#
2+
# MDEV-39169: resolveip IPv6 support
3+
#
4+
#
5+
# IPv4 special addresses (deterministic, no DNS needed)
6+
#
7+
Broadcast
8+
Null-IP-Addr
9+
#
10+
# IPv4 reverse lookup
11+
#
12+
Host name of 127.0.0.1 is HOSTNAME
13+
#
14+
# IPv4 reverse lookup (silent mode)
15+
#
16+
HOSTNAME
17+
#
18+
# IPv6 special address (deterministic, no DNS needed)
19+
#
20+
Null-IP-Addr
21+
#
22+
# IPv6 unspecified address (full form)
23+
#
24+
Null-IP-Addr
25+
#
26+
# IPv6 reverse lookup
27+
#
28+
Host name of ::1 is HOSTNAME
29+
#
30+
# IPv6 reverse lookup (silent mode)
31+
#
32+
HOSTNAME
33+
#
34+
# IPv6 IPv4-mapped address
35+
#
36+
Host name of ::ffff:127.0.0.1 is HOSTNAME
37+
#
38+
# IPv6 full form address
39+
#
40+
Host name of 0000:0000:0000:0000:0000:0000:0000:0001 is HOSTNAME
41+
#
42+
# Multiple addresses in one call
43+
#
44+
Broadcast
45+
Null-IP-Addr
46+
#
47+
# Mixed IPv4 and IPv6 addresses
48+
#
49+
Broadcast
50+
Null-IP-Addr
51+
#
52+
# Mixed IP address and hostname
53+
#
54+
REPLACED
55+
REPLACED
56+
#
57+
# Invalid hostname
58+
#
59+
resolveip: Unable to find hostid for 'nonexistent.invalid': NAME_RESOLUTION_ERROR
60+
#
61+
# Invalid address mixed with valid address
62+
#
63+
Broadcast
64+
resolveip: Unable to find hostid for 'nonexistent.invalid': NAME_RESOLUTION_ERROR
65+
#
66+
# End of 13.0 tests
67+
#

mysql-test/main/resolveip.test

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
--source include/not_windows.inc
2+
--source include/check_ipv6.inc
3+
4+
--echo #
5+
--echo # MDEV-39169: resolveip IPv6 support
6+
--echo #
7+
8+
--echo #
9+
--echo # IPv4 special addresses (deterministic, no DNS needed)
10+
--echo #
11+
--exec $MYSQL_RESOLVEIP 255.255.255.255
12+
--exec $MYSQL_RESOLVEIP 0.0.0.0
13+
14+
--echo #
15+
--echo # IPv4 reverse lookup
16+
--echo #
17+
--exec $MYSQL_RESOLVEIP 127.0.0.1 2>&1 | sed 's/Host name of 127\.0\.0\.1 is .*/Host name of 127.0.0.1 is HOSTNAME/' | sed "s|.*Unable to find hostname for '127.0.0.1'|Host name of 127.0.0.1 is HOSTNAME|"
18+
19+
--echo #
20+
--echo # IPv4 reverse lookup (silent mode)
21+
--echo #
22+
--exec $MYSQL_RESOLVEIP -s 127.0.0.1 2>&1 | sed 's/.*/HOSTNAME/'
23+
24+
--echo #
25+
--echo # IPv6 special address (deterministic, no DNS needed)
26+
--echo #
27+
--exec $MYSQL_RESOLVEIP ::
28+
29+
--echo #
30+
--echo # IPv6 unspecified address (full form)
31+
--echo #
32+
--exec $MYSQL_RESOLVEIP 0000:0000:0000:0000:0000:0000:0000:0000
33+
34+
--echo #
35+
--echo # IPv6 reverse lookup
36+
--echo #
37+
--exec $MYSQL_RESOLVEIP ::1 2>&1 | sed 's/Host name of ::1 is .*/Host name of ::1 is HOSTNAME/' | sed "s|.*Unable to find hostname for '::1'|Host name of ::1 is HOSTNAME|"
38+
39+
--echo #
40+
--echo # IPv6 reverse lookup (silent mode)
41+
--echo #
42+
--exec $MYSQL_RESOLVEIP -s ::1 2>&1 | sed 's/.*/HOSTNAME/'
43+
44+
--echo #
45+
--echo # IPv6 IPv4-mapped address
46+
--echo #
47+
--exec $MYSQL_RESOLVEIP ::ffff:127.0.0.1 2>&1 | sed 's/Host name of ::ffff:127\.0\.0\.1 is .*/Host name of ::ffff:127.0.0.1 is HOSTNAME/' | sed "s|.*Unable to find hostname for '::ffff:127.0.0.1'|Host name of ::ffff:127.0.0.1 is HOSTNAME|"
48+
49+
--echo #
50+
--echo # IPv6 full form address
51+
--echo #
52+
--exec $MYSQL_RESOLVEIP 0000:0000:0000:0000:0000:0000:0000:0001 2>&1 | sed 's/Host name of 0000:0000:0000:0000:0000:0000:0000:0001 is .*/Host name of 0000:0000:0000:0000:0000:0000:0000:0001 is HOSTNAME/' | sed "s|.*Unable to find hostname for '0000:0000:0000:0000:0000:0000:0000:0001'|Host name of 0000:0000:0000:0000:0000:0000:0000:0001 is HOSTNAME|"
53+
54+
--echo #
55+
--echo # Multiple addresses in one call
56+
--echo #
57+
--exec $MYSQL_RESOLVEIP 255.255.255.255 0.0.0.0
58+
59+
--echo #
60+
--echo # Mixed IPv4 and IPv6 addresses
61+
--echo #
62+
--exec $MYSQL_RESOLVEIP 255.255.255.255 ::
63+
64+
--echo #
65+
--echo # Mixed IP address and hostname
66+
--echo #
67+
--exec $MYSQL_RESOLVEIP -s 127.0.0.1 localhost | sed 's/.*/REPLACED/'
68+
69+
--echo #
70+
--echo # Invalid hostname
71+
--echo #
72+
--exec $MYSQL_RESOLVEIP nonexistent.invalid 2>&1 | sed "s|.*Unable to find hostid for 'nonexistent.invalid': .*|resolveip: Unable to find hostid for 'nonexistent.invalid': NAME_RESOLUTION_ERROR|"
73+
74+
--echo #
75+
--echo # Invalid address mixed with valid address
76+
--echo #
77+
--exec $MYSQL_RESOLVEIP 255.255.255.255 nonexistent.invalid 2>&1 | sed "s|.*Unable to find hostid for 'nonexistent.invalid': .*|resolveip: Unable to find hostid for 'nonexistent.invalid': NAME_RESOLUTION_ERROR|"
78+
79+
--echo #
80+
--echo # End of 13.0 tests
81+
--echo #

0 commit comments

Comments
 (0)