diff --git a/doc/ping.xml b/doc/ping.xml index 2ab0b850..962b6e05 100644 --- a/doc/ping.xml +++ b/doc/ping.xml @@ -646,7 +646,10 @@ xml:id="man.ping"> Specifies the number of data bytes to be sent. The default is 56, which translates into 64 ICMP data bytes when combined with the 8 bytes of ICMP header data. - Maximum allowed value is 127992, but though most systems + The maximum allowed value is 65507 for IPv4 + (65467 when or + or Intermediate hops) + or 65527 for IPv6, but most systems limit this to a smaller, system-dependent number. diff --git a/ping/ping.c b/ping/ping.c index d491be38..e19d8f02 100644 --- a/ping/ping.c +++ b/ping/ping.c @@ -59,6 +59,7 @@ #include #include #include +#include /* FIXME: global_rts will be removed in future */ struct ping_rts *global_rts; @@ -84,6 +85,12 @@ ping_func_set_st ping4_func_set = { #define NROUTES 9 /* number of record route slots */ #define TOS_MAX 255 /* 8-bit TOS field */ +/* max. IPv4 packet size - IPv4 header size - ICMP header size */ +#define ICMP_MAX_DATALEN (MAXPACKET - 20 - 8) + +/* max. IPv6 payload size - ICMPv6 Echo Reply Header */ +#define ICMPV6_MAX_DATALEN (MAXPACKET - sizeof (struct icmp6_hdr)) + #define CASE_TYPE(x) case x: return #x; static char *str_family(int family) @@ -345,6 +352,8 @@ main(int argc, char **argv) .ni.query = -1, .ni.subject_type = -1, }; + char buf[INET6_ADDRSTRLEN]; + /* FIXME: global_rts will be removed in future */ global_rts = &rts; @@ -535,7 +544,8 @@ main(int argc, char **argv) rts.opt_so_dontroute = 1; break; case 's': - rts.datalen = strtol_or_err(optarg, _("invalid argument"), 0, MAXPACKET - 8); + /* real validation is done later */ + rts.datalen = strtol_or_err(optarg, _("invalid argument"), 0, INT_MAX); break; case 'S': rts.sndbuf = strtol_or_err(optarg, _("invalid argument"), 1, INT_MAX); @@ -622,6 +632,24 @@ main(int argc, char **argv) hints.ai_family = AF_INET; } + int max_s = MAX(ICMP_MAX_DATALEN, ICMPV6_MAX_DATALEN); + + /* Detect based on -4 / -6 */ + if (hints.ai_family == AF_INET) + max_s = ICMP_MAX_DATALEN - get_ipv4_optlen(&rts); + else if (hints.ai_family == AF_INET6) + max_s = ICMPV6_MAX_DATALEN; + + /* Force limit on IPv4/IPv6 adresses */ + if (inet_pton(AF_INET, target, buf)) + max_s = ICMP_MAX_DATALEN - get_ipv4_optlen(&rts); + else if (inet_pton(AF_INET6, target, buf)) + max_s = ICMPV6_MAX_DATALEN; + + if (rts.datalen > max_s) + error(EXIT_FAILURE, 0, "invalid -s value: '%d': out of range: 0 <= value <= %d", + rts.datalen, max_s); + if (rts.opt_verbose) error(0, 0, "sock4.fd: %d (socktype: %s), sock6.fd: %d (socktype: %s)," " hints.ai_family: %s\n", @@ -643,7 +671,6 @@ main(int argc, char **argv) int target_ai_family = hints.ai_family; hints.ai_family = AF_UNSPEC; - char buf[INET6_ADDRSTRLEN]; if (!strchr(target, '%') && sock6.socktype == SOCK_DGRAM && inet_pton(AF_INET6, target, buf) > 0 && (IN6_IS_ADDR_LINKLOCAL(buf) || IN6_IS_ADDR_MC_LINKLOCAL(buf))) { @@ -1011,11 +1038,6 @@ int ping4_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai, error(2, errno, _("cannot set unicast time-to-live")); } - - if (rts->datalen > 0xFFFF - 8 - rts->optlen - 20) - error(2, 0, _("packet size %d is too large. Maximum is %d"), - rts->datalen, 0xFFFF - 8 - 20 - rts->optlen); - if (rts->datalen >= (int)sizeof(struct timeval)) /* can we time transfer */ rts->timing = 1; packlen = rts->datalen + MAXIPLEN + MAXICMPLEN; diff --git a/ping/ping.h b/ping/ping.h index d7d4f0b4..48e35b78 100644 --- a/ping/ping.h +++ b/ping/ping.h @@ -107,7 +107,8 @@ typedef uint32_t bitmap_t; # error Please MAX_DUP_CHK and/or BITMAP_SHIFT #endif -#define MAXPACKET 128000 /* max packet size */ +/* IPv4 packet size / IPv6 payload size */ +#define MAXPACKET 65535 struct rcvd_table { bitmap_t bitmap[MAX_DUP_CHK / (sizeof(bitmap_t) * 8)];