diff options
author | Jonas Danielsson <jonasdn@axis.com> | 2016-06-23 18:26:32 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-06-23 18:26:32 +0200 |
commit | 4d5acd2d4264d0a754d3d11c94825fd69d0c7837 (patch) | |
tree | 0332502afadae4d4a8c8ec24b5fadbabb0bea956 | |
parent | 9ca56f9621d9e7265699997d90902fcaf6ed5aad (diff) | |
download | busybox-w32-4d5acd2d4264d0a754d3d11c94825fd69d0c7837.tar.gz busybox-w32-4d5acd2d4264d0a754d3d11c94825fd69d0c7837.tar.bz2 busybox-w32-4d5acd2d4264d0a754d3d11c94825fd69d0c7837.zip |
ping: populate icmp_id field for "simple" ping too
The ICMP RFC says that identifier and sequence number may be zero.
Having them zero for a Echo message, along with a data of zero's
as well will result in a Echo reply message with only zero's.
Some NAT implementations seem to get the checksum wrong on these
packages. Setting a checksum of 0x0 instead of 0xffff.
Through NAT:
Internet Control Message Protocol
Type: 0 (Echo (ping) reply)
Code: 0
Checksum: 0x0000 [incorrect, should be 0xffff]
Identifier (BE): 0 (0x0000)
Identifier (LE): 0 (0x0000)
Sequence number (BE): 0 (0x0000)
Sequence number (LE): 0 (0x0000)
Data (56 bytes)
Data: 000000000000000000000000000000000000000000000000...
[Length: 56]
Without NAT:
Internet Control Message Protocol
Type: 0 (Echo (ping) reply)
Code: 0
Checksum: 0xffff [correct]
Identifier (BE): 0 (0x0000)
Identifier (LE): 0 (0x0000)
Sequence number (BE): 0 (0x0000)
Sequence number (LE): 0 (0x0000)
[Request frame: 189]
[Response time: 0.024 ms]
Data (56 bytes)
Data: 000000000000000000000000000000000000000000000000...
[Length: 56]
And this in turn will make some hardware MAC checksum offloading
engines drop the packet.
(This was seen with a Synopsis MAC, the same one used in for instance the
stmmac Ethernet driver in the linux kernel.)
This change can be seen as a workaround for bugs in other layers.
But just setting an identifier for the Echo message packet will
avoid prodding the hornets nest.
function old new delta
common_ping_main 424 500 +76
Signed-off-by: Jonas Danielsson <jonasdn@axis.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/ping.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/networking/ping.c b/networking/ping.c index cfe682646..d8767a39f 100644 --- a/networking/ping.c +++ b/networking/ping.c | |||
@@ -186,6 +186,7 @@ create_icmp_socket(void) | |||
186 | struct globals { | 186 | struct globals { |
187 | char *hostname; | 187 | char *hostname; |
188 | char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; | 188 | char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; |
189 | uint16_t myid; | ||
189 | } FIX_ALIASING; | 190 | } FIX_ALIASING; |
190 | #define G (*(struct globals*)bb_common_bufsiz1) | 191 | #define G (*(struct globals*)bb_common_bufsiz1) |
191 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 192 | #define INIT_G() do { setup_common_bufsiz(); } while (0) |
@@ -204,6 +205,7 @@ static void ping4(len_and_sockaddr *lsa) | |||
204 | pkt = (struct icmp *) G.packet; | 205 | pkt = (struct icmp *) G.packet; |
205 | /*memset(pkt, 0, sizeof(G.packet)); already is */ | 206 | /*memset(pkt, 0, sizeof(G.packet)); already is */ |
206 | pkt->icmp_type = ICMP_ECHO; | 207 | pkt->icmp_type = ICMP_ECHO; |
208 | pkt->icmp_id = G.myid; | ||
207 | pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); | 209 | pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); |
208 | 210 | ||
209 | xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); | 211 | xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); |
@@ -228,6 +230,8 @@ static void ping4(len_and_sockaddr *lsa) | |||
228 | struct iphdr *iphdr = (struct iphdr *) G.packet; | 230 | struct iphdr *iphdr = (struct iphdr *) G.packet; |
229 | 231 | ||
230 | pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */ | 232 | pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */ |
233 | if (pkt->icmp_id != G.myid) | ||
234 | continue; /* not our ping */ | ||
231 | if (pkt->icmp_type == ICMP_ECHOREPLY) | 235 | if (pkt->icmp_type == ICMP_ECHOREPLY) |
232 | break; | 236 | break; |
233 | } | 237 | } |
@@ -246,6 +250,7 @@ static void ping6(len_and_sockaddr *lsa) | |||
246 | pkt = (struct icmp6_hdr *) G.packet; | 250 | pkt = (struct icmp6_hdr *) G.packet; |
247 | /*memset(pkt, 0, sizeof(G.packet)); already is */ | 251 | /*memset(pkt, 0, sizeof(G.packet)); already is */ |
248 | pkt->icmp6_type = ICMP6_ECHO_REQUEST; | 252 | pkt->icmp6_type = ICMP6_ECHO_REQUEST; |
253 | pkt->icmp6_id = G.myid; | ||
249 | 254 | ||
250 | sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); | 255 | sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); |
251 | setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt); | 256 | setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt); |
@@ -269,6 +274,8 @@ static void ping6(len_and_sockaddr *lsa) | |||
269 | continue; | 274 | continue; |
270 | } | 275 | } |
271 | if (c >= ICMP_MINLEN) { /* icmp6_hdr */ | 276 | if (c >= ICMP_MINLEN) { /* icmp6_hdr */ |
277 | if (pkt->icmp6_id != G.myid) | ||
278 | continue; /* not our ping */ | ||
272 | if (pkt->icmp6_type == ICMP6_ECHO_REPLY) | 279 | if (pkt->icmp6_type == ICMP6_ECHO_REPLY) |
273 | break; | 280 | break; |
274 | } | 281 | } |
@@ -317,6 +324,7 @@ static int common_ping_main(sa_family_t af, char **argv) | |||
317 | alarm(5); /* give the host 5000ms to respond */ | 324 | alarm(5); /* give the host 5000ms to respond */ |
318 | 325 | ||
319 | create_icmp_socket(lsa); | 326 | create_icmp_socket(lsa); |
327 | G.myid = (uint16_t) getpid(); | ||
320 | #if ENABLE_PING6 | 328 | #if ENABLE_PING6 |
321 | if (lsa->u.sa.sa_family == AF_INET6) | 329 | if (lsa->u.sa.sa_family == AF_INET6) |
322 | ping6(lsa); | 330 | ping6(lsa); |