Skip to content

Commit 7ddd66a

Browse files
Pavel Šimerdaokias
authored andcommitted
ping: merge IPv4 and IPv6 pr_addr()
* Use `getnameinfo()` to perform dualstack name resolution * Use it also to format addresses to strings Note: A nice side effect is that IPv6 link-local addresses are now translated including the `scope_id`.
1 parent 243b6e1 commit 7ddd66a

File tree

3 files changed

+60
-94
lines changed

3 files changed

+60
-94
lines changed

ping.c

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ static int settos = 0; /* Set TOS, Precendence or other QOS options */
9292

9393
static int broadcast_pings = 0;
9494

95-
static char *pr_addr(__u32);
9695
static void pr_options(unsigned char * cp, int hlen);
9796
static void pr_iph(struct iphdr *ip);
9897
static void usage(void) __attribute__((noreturn));
@@ -904,7 +903,7 @@ int ping4_receive_error_msg(socket_st *sock)
904903
write_stdout("\bE", 2);
905904
} else {
906905
print_timestamp();
907-
printf("From %s icmp_seq=%u ", pr_addr(sin->sin_addr.s_addr), ntohs(icmph.un.echo.sequence));
906+
printf("From %s icmp_seq=%u ", pr_addr(sin, sizeof *sin), ntohs(icmph.un.echo.sequence));
908907
pr_icmph(e->ee_type, e->ee_code, e->ee_info, NULL);
909908
fflush(stdout);
910909
}
@@ -1000,7 +999,7 @@ ping4_parse_reply(struct socket_st *sock, struct msghdr *msg, int cc, void *addr
1000999
if (cc < hlen + 8 || ip->ihl < 5) {
10011000
if (options & F_VERBOSE)
10021001
fprintf(stderr, "ping: packet too short (%d bytes) from %s\n", cc,
1003-
pr_addr(from->sin_addr.s_addr));
1002+
pr_addr(from, sizeof *from));
10041003
return 1;
10051004
}
10061005
ttl = ip->ttl;
@@ -1035,7 +1034,7 @@ ping4_parse_reply(struct socket_st *sock, struct msghdr *msg, int cc, void *addr
10351034
return 1; /* 'Twas not our ECHO */
10361035
if (gather_statistics((__u8*)icp, sizeof(*icp), cc,
10371036
ntohs(icp->un.echo.sequence),
1038-
ttl, 0, tv, pr_addr(from->sin_addr.s_addr),
1037+
ttl, 0, tv, pr_addr(from, sizeof *from),
10391038
pr_echo_reply)) {
10401039
fflush(stdout);
10411040
return 0;
@@ -1081,7 +1080,7 @@ ping4_parse_reply(struct socket_st *sock, struct msghdr *msg, int cc, void *addr
10811080
}
10821081
print_timestamp();
10831082
printf("From %s: icmp_seq=%u ",
1084-
pr_addr(from->sin_addr.s_addr),
1083+
pr_addr(from, sizeof *from),
10851084
ntohs(icp1->un.echo.sequence));
10861085
if (csfailed)
10871086
printf("(BAD CHECKSUM)");
@@ -1106,7 +1105,7 @@ ping4_parse_reply(struct socket_st *sock, struct msghdr *msg, int cc, void *addr
11061105
gettimeofday(&recv_time, NULL);
11071106
printf("%lu.%06lu ", (unsigned long)recv_time.tv_sec, (unsigned long)recv_time.tv_usec);
11081107
}
1109-
printf("From %s: ", pr_addr(from->sin_addr.s_addr));
1108+
printf("From %s: ", pr_addr(from, sizeof *from));
11101109
if (csfailed) {
11111110
printf("(BAD CHECKSUM)\n");
11121111
return 0;
@@ -1261,8 +1260,11 @@ void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp)
12611260
printf("Redirect, Bad Code: %d", code);
12621261
break;
12631262
}
1264-
printf("(New nexthop: %s)\n",
1265-
pr_addr(icp ? icp->un.gateway : info));
1263+
{
1264+
struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { icp ? icp->un.gateway : info } };
1265+
1266+
printf("(New nexthop: %s)\n", pr_addr(&sin, sizeof sin));
1267+
}
12661268
if (icp && (options & F_VERBOSE))
12671269
pr_iph((struct iphdr*)(icp + 1));
12681270
break;
@@ -1361,8 +1363,11 @@ void pr_options(unsigned char * cp, int hlen)
13611363
cp += 4;
13621364
if (address == 0)
13631365
printf("\t0.0.0.0");
1364-
else
1365-
printf("\t%s", pr_addr(address));
1366+
else {
1367+
struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { address } };
1368+
1369+
printf("\t%s", pr_addr(&sin, sizeof sin));
1370+
}
13661371
j -= 4;
13671372
putchar('\n');
13681373
if (j <= IPOPT_MINOFF)
@@ -1396,8 +1401,11 @@ void pr_options(unsigned char * cp, int hlen)
13961401
cp += 4;
13971402
if (address == 0)
13981403
printf("\t0.0.0.0");
1399-
else
1400-
printf("\t%s", pr_addr(address));
1404+
else {
1405+
struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { address } };
1406+
1407+
printf("\t%s", pr_addr(&sin, sizeof sin));
1408+
}
14011409
i -= 4;
14021410
putchar('\n');
14031411
if (i <= 0)
@@ -1427,8 +1435,11 @@ void pr_options(unsigned char * cp, int hlen)
14271435
cp += 4;
14281436
if (address == 0)
14291437
printf("\t0.0.0.0");
1430-
else
1431-
printf("\t%s", pr_addr(address));
1438+
else {
1439+
struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { address } };
1440+
1441+
printf("\t%s", pr_addr(&sin, sizeof sin));
1442+
}
14321443
i -= 4;
14331444
if (i <= 0)
14341445
break;
@@ -1496,44 +1507,37 @@ void pr_iph(struct iphdr *ip)
14961507

14971508
/*
14981509
* pr_addr --
1499-
* Return an ascii host address as a dotted quad and optionally with
1500-
* a hostname.
1510+
*
1511+
* Return an ascii host address optionally with a hostname.
15011512
*/
15021513
char *
1503-
pr_addr(__u32 addr)
1514+
pr_addr(void *sa, socklen_t salen)
15041515
{
1505-
struct hostent *hp;
1506-
static char buf[4096] = "";
1507-
static __u32 last_addr = 0;
1516+
static char buffer[4096] = "";
1517+
static struct sockaddr_storage last_sa = { 0 };
1518+
static socklen_t last_salen = 0;
1519+
char name[NI_MAXHOST] = "";
1520+
char address[NI_MAXHOST] = "";
15081521

1509-
if(*buf && addr == last_addr)
1510-
return(buf);
1522+
if (salen == last_salen && !memcmp(sa, &last_sa, salen))
1523+
return buffer;
15111524

1512-
last_addr = addr;
1525+
memcpy(&last_sa, sa, (last_salen = salen));
15131526

15141527
in_pr_addr = !setjmp(pr_addr_jmp);
15151528

1516-
if (exiting || (options & F_NUMERIC) ||
1517-
!(hp = gethostbyaddr((char *)&addr, 4, AF_INET)))
1518-
sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&addr));
1519-
else {
1520-
char *s;
1521-
#if USE_IDN
1522-
if (idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS)
1523-
s = NULL;
1524-
#else
1525-
s = NULL;
1526-
#endif
1527-
snprintf(buf, sizeof(buf), "%s (%s)", s ? s : hp->h_name,
1528-
inet_ntoa(*(struct in_addr *)&addr));
1529-
#if USE_IDN
1530-
free(s);
1531-
#endif
1532-
}
1529+
getnameinfo(sa, salen, address, sizeof address, NULL, 0, getnameinfo_flags | NI_NUMERICHOST);
1530+
if (!exiting && !(options & F_NUMERIC))
1531+
getnameinfo(sa, salen, name, sizeof name, NULL, 0, getnameinfo_flags);
1532+
1533+
if (*name)
1534+
snprintf(buffer, sizeof buffer, "%s (%s)", name, address);
1535+
else
1536+
snprintf(buffer, sizeof buffer, "%s", address);
15331537

15341538
in_pr_addr = 0;
15351539

1536-
return(buf);
1540+
return(buffer);
15371541
}
15381542

15391543

ping.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
#include <idna.h>
4040
#include <stringprep.h>
4141
#define getaddrinfo_flags (AI_CANONNAME | AI_IDN | AI_CANONIDN)
42+
#define getnameinfo_flags NI_IDN
4243
#else
4344
#define getaddrinfo_flags (AI_CANONNAME)
45+
#define getnameinfo_flags 0
4446
#endif
4547

4648
#ifndef WITHOUT_IFADDRS
@@ -283,6 +285,8 @@ typedef struct socket_st {
283285
int working_recverr;
284286
} socket_st;
285287

288+
char *pr_addr(void *sa, socklen_t salen);
289+
286290
int is_ours(socket_st *sock, uint16_t id);
287291

288292
int ping4_run(int argc, char **argv, struct addrinfo *ai, socket_st *sock);

ping6_common.c

Lines changed: 11 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ static struct sockaddr_in6 firsthop;
9696
static unsigned char cmsgbuf[4096];
9797
static int cmsglen = 0;
9898

99-
static char * pr_addr(struct in6_addr *addr);
100-
static char * pr_addr_n(struct in6_addr *addr);
10199
static int pr_icmph(__u8 type, __u8 code, __u32 info);
102100
void ping6_usage(unsigned) __attribute((noreturn));
103101

@@ -1043,12 +1041,15 @@ int ping6_run(int argc, char **argv, struct addrinfo *ai, struct socket_st *sock
10431041
#endif
10441042
}
10451043

1046-
printf("PING %s(%s) ", hostname, pr_addr(&whereto.sin6_addr));
1044+
printf("PING %s(%s) ", hostname, pr_addr(&whereto, sizeof whereto));
10471045
if (flowlabel)
10481046
printf(", flow 0x%05x, ", (unsigned)ntohl(flowlabel));
10491047
if (device || (options&F_STRICTSOURCE)) {
1050-
printf("from %s %s: ",
1051-
pr_addr_n(&source6.sin6_addr), device ? : "");
1048+
int saved_options = options;
1049+
1050+
options |= F_NUMERIC;
1051+
printf("from %s %s: ", pr_addr(&source6, sizeof source6), device ? : "");
1052+
options = saved_options;
10521053
}
10531054
printf("%d data bytes\n", datalen);
10541055

@@ -1128,7 +1129,7 @@ int ping6_receive_error_msg(socket_st *sock)
11281129
write_stdout("\bE", 2);
11291130
} else {
11301131
print_timestamp();
1131-
printf("From %s icmp_seq=%u ", pr_addr(&sin6->sin6_addr), ntohs(icmph.icmp6_seq));
1132+
printf("From %s icmp_seq=%u ", pr_addr(sin6, sizeof *sin6), ntohs(icmph.icmp6_seq));
11321133
pr_icmph(e->ee_type, e->ee_code, e->ee_info);
11331134
putchar('\n');
11341135
fflush(stdout);
@@ -1418,7 +1419,7 @@ ping6_parse_reply(socket_st *sock, struct msghdr *msg, int cc, void *addr, struc
14181419
return 1;
14191420
if (gather_statistics((__u8*)icmph, sizeof(*icmph), cc,
14201421
ntohs(icmph->icmp6_seq),
1421-
hops, 0, tv, pr_addr(&from->sin6_addr),
1422+
hops, 0, tv, pr_addr(from, sizeof *from),
14221423
pr_echo_reply)) {
14231424
fflush(stdout);
14241425
return 0;
@@ -1430,7 +1431,7 @@ ping6_parse_reply(socket_st *sock, struct msghdr *msg, int cc, void *addr, struc
14301431
return 1;
14311432
if (gather_statistics((__u8*)icmph, sizeof(*icmph), cc,
14321433
seq,
1433-
hops, 0, tv, pr_addr(&from->sin6_addr),
1434+
hops, 0, tv, pr_addr(from, sizeof *from),
14341435
pr_niquery_reply))
14351436
return 0;
14361437
} else {
@@ -1470,13 +1471,13 @@ ping6_parse_reply(socket_st *sock, struct msghdr *msg, int cc, void *addr, struc
14701471
return 0;
14711472
}
14721473
print_timestamp();
1473-
printf("From %s: icmp_seq=%u ", pr_addr(&from->sin6_addr), ntohs(icmph1->icmp6_seq));
1474+
printf("From %s: icmp_seq=%u ", pr_addr(from, sizeof *from), ntohs(icmph1->icmp6_seq));
14741475
} else {
14751476
/* We've got something other than an ECHOREPLY */
14761477
if (!(options & F_VERBOSE) || uid)
14771478
return 1;
14781479
print_timestamp();
1479-
printf("From %s: ", pr_addr(&from->sin6_addr));
1480+
printf("From %s: ", pr_addr(from, sizeof *from));
14801481
}
14811482
pr_icmph(icmph->icmp6_type, icmph->icmp6_code, ntohl(icmph->icmp6_mtu));
14821483
}
@@ -1596,49 +1597,6 @@ void ping6_install_filter(socket_st *sock)
15961597
perror("WARNING: failed to install socket filter\n");
15971598
}
15981599

1599-
1600-
/*
1601-
* pr_addr --
1602-
* Return an ascii host address as a dotted quad and optionally with
1603-
* a hostname.
1604-
*/
1605-
char * pr_addr(struct in6_addr *addr)
1606-
{
1607-
static struct hostent *hp = NULL;
1608-
static char *s;
1609-
static struct in6_addr last_addr;
1610-
1611-
#ifdef USE_IDN
1612-
free(s);
1613-
#endif
1614-
1615-
in_pr_addr = !setjmp(pr_addr_jmp);
1616-
1617-
if (!(hp && memcmp(addr, &last_addr, sizeof(struct in6_addr))) &&
1618-
!(exiting || options&F_NUMERIC)) {
1619-
hp = gethostbyaddr((__u8*)addr, sizeof(struct in6_addr), AF_INET6);
1620-
memcpy(&last_addr, addr, sizeof(struct in6_addr));
1621-
}
1622-
1623-
in_pr_addr = 0;
1624-
1625-
if (!hp
1626-
#ifdef USE_IDN
1627-
|| idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS
1628-
#endif
1629-
)
1630-
s = NULL;
1631-
1632-
return hp ? (s ? s : hp->h_name) : pr_addr_n(addr);
1633-
}
1634-
1635-
char * pr_addr_n(struct in6_addr *addr)
1636-
{
1637-
static char str[64];
1638-
inet_ntop(AF_INET6, addr, str, sizeof(str));
1639-
return str;
1640-
}
1641-
16421600
#define USAGE_NEWLINE "\n "
16431601

16441602
void ping6_usage(unsigned from_ping)

0 commit comments

Comments
 (0)