|
52 | 52 | #define ROUTER_GW IP4(10,0,1,254) |
53 | 53 | #define ROUTER_IF1 IP4(10,0,2,1) |
54 | 54 | #define DEST_IP IP4(10,0,2,200) |
| 55 | +#define TTL_EXCEEDED_DATA_LEN 28 |
55 | 56 |
|
56 | 57 | #define PACKED __attribute__((packed)) |
57 | 58 |
|
@@ -82,6 +83,14 @@ struct icmp_echo { |
82 | 83 | uint16_t seq; |
83 | 84 | } PACKED; |
84 | 85 |
|
| 86 | +struct icmp_ttl_exceeded { |
| 87 | + uint8_t type; |
| 88 | + uint8_t code; |
| 89 | + uint16_t csum; |
| 90 | + uint8_t unused[4]; |
| 91 | + uint8_t data[TTL_EXCEEDED_DATA_LEN]; |
| 92 | +} PACKED; |
| 93 | + |
85 | 94 | static uint16_t ones_csum(const void *buf, size_t len) |
86 | 95 | { |
87 | 96 | const uint16_t *p = buf; |
@@ -344,19 +353,63 @@ int main(void) |
344 | 353 | mem_host_send(&link, frame, sizeof(struct eth_hdr) + sizeof(struct ipv4_hdr) + sizeof(struct icmp_echo)); |
345 | 354 |
|
346 | 355 | n = mem_host_recv(&link, frame, sizeof(frame), 1000); |
347 | | - if (n > 0) { |
| 356 | + if (n <= 0) { |
| 357 | + fprintf(stderr, "No TTL expired response\n"); |
| 358 | + goto cleanup; |
| 359 | + } |
| 360 | + |
| 361 | + { |
348 | 362 | struct eth_hdr *eth = (struct eth_hdr *)frame; |
349 | 363 | struct ipv4_hdr *ip = (struct ipv4_hdr *)(frame + sizeof(*eth)); |
350 | | - struct icmp_echo *icmp = (struct icmp_echo *)(frame + sizeof(*eth) + sizeof(*ip)); |
351 | | - if (ntohs(eth->type) == ETH_P_IP && ip->proto == 1 && icmp->type == 11 && |
352 | | - ntohl(ip->src) == DEST_IP && ntohl(ip->dst) == HOST_IP) { |
353 | | - printf("TTL expired response received\n"); |
354 | | - rc = EXIT_SUCCESS; |
| 364 | + struct icmp_ttl_exceeded *icmp = (struct icmp_ttl_exceeded *)(frame + sizeof(*eth) + sizeof(*ip)); |
| 365 | + struct ipv4_hdr *orig_ip = (struct ipv4_hdr *)icmp->data; |
| 366 | + struct icmp_echo *orig_icmp = (struct icmp_echo *)(icmp->data + sizeof(*orig_ip)); |
| 367 | + size_t expected_len = sizeof(*eth) + sizeof(*ip) + sizeof(*icmp); |
| 368 | + uint16_t ip_len = ntohs(ip->len); |
| 369 | + uint16_t expected_ip_len = (uint16_t)(sizeof(*ip) + sizeof(*icmp)); |
| 370 | + |
| 371 | + if ((size_t)n != expected_len) { |
| 372 | + fprintf(stderr, "Unexpected frame length: got %d expected %zu\n", n, expected_len); |
| 373 | + goto mismatch; |
355 | 374 | } |
356 | | - } else { |
357 | | - fprintf(stderr, "No TTL expired response\n"); |
| 375 | + if (ntohs(eth->type) != ETH_P_IP || |
| 376 | + memcmp(eth->dst, host_mac, sizeof(host_mac)) != 0 || |
| 377 | + memcmp(eth->src, router0_mac, sizeof(router0_mac)) != 0) { |
| 378 | + fprintf(stderr, "Ethernet header mismatch\n"); |
| 379 | + goto mismatch; |
| 380 | + } |
| 381 | + if (ip->ver_ihl != 0x45 || ip->proto != 1 || ip->ttl != 64 || |
| 382 | + ip_len != expected_ip_len || |
| 383 | + ntohl(ip->src) != ROUTER_IF0 || ntohl(ip->dst) != HOST_IP) { |
| 384 | + fprintf(stderr, "IPv4 header mismatch\n"); |
| 385 | + goto mismatch; |
| 386 | + } |
| 387 | + if (icmp->type != 11 || icmp->code != 0 || |
| 388 | + memcmp(icmp->unused, "\x00\x00\x00\x00", sizeof(icmp->unused)) != 0) { |
| 389 | + fprintf(stderr, "ICMP header mismatch\n"); |
| 390 | + goto mismatch; |
| 391 | + } |
| 392 | + if (orig_ip->ver_ihl != 0x45 || orig_ip->proto != 1 || |
| 393 | + ntohl(orig_ip->src) != HOST_IP || ntohl(orig_ip->dst) != DEST_IP || |
| 394 | + ntohs(orig_ip->len) != sizeof(*orig_ip) + sizeof(struct icmp_echo) || |
| 395 | + ntohs(orig_ip->id) != 0x1234 || orig_ip->ttl != 1) { |
| 396 | + fprintf(stderr, "Embedded IPv4 header mismatch\n"); |
| 397 | + goto mismatch; |
| 398 | + } |
| 399 | + if (orig_icmp->type != 8 || orig_icmp->code != 0 || |
| 400 | + ntohs(orig_icmp->id) != 0x0101 || ntohs(orig_icmp->seq) != 1) { |
| 401 | + fprintf(stderr, "Embedded ICMP header mismatch\n"); |
| 402 | + goto mismatch; |
| 403 | + } |
| 404 | + printf("TTL expired response received\n"); |
| 405 | + rc = EXIT_SUCCESS; |
| 406 | + goto cleanup; |
358 | 407 | } |
359 | 408 |
|
| 409 | +mismatch: |
| 410 | + fprintf(stderr, "TTL expired response mismatch\n"); |
| 411 | + |
| 412 | +cleanup: |
360 | 413 | running = 0; |
361 | 414 | pthread_join(th, NULL); |
362 | 415 | return rc; |
|
0 commit comments