Skip to content

NGdev2/ft_ping

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ft_ping

recoding the ping command

Ping use ICMP (Internet Control Message Protocol)

Ping is the name of a command that allows you to test the accessibility of another machine through the IP network.
The command also measures the time taken to receive a response, called the round-trip time

!!! You will take as reference the ping implementation from inetutils-2.0 (ping -V).

-- ping -V
ping from iputils 20240117
libcap: yes, IDN: yes, NLS: no, error.h: yes,
getrandom(): yes, __fpending(): yes

How it works

  • PC sends an ICMP Echo Request to a target IP.

  • If the target is reachable and allows ICMP, it responds with an ICMP Echo Reply (Type 0).

  • The time between request and reply = latency.

0               8              16             24            31
+---------------+---------------+---------------+---------------+
|     Type      |     Code      |           Checksum            |
+---------------+---------------+---------------+---------------+
|           Identifier          |        Sequence Number        |
+---------------+---------------+---------------+---------------+
|                           Data ...                            |
+---------------------------------------------------------------+

type

  • 8 → Echo Request
  • 0 → Echo Reply

code

  • Always 0 for Echo messages


ICMP Message Types and Codes

ICMP (Internet Control Message Protocol) is used not only for ping (Echo Request/Reply) but also for error reporting and network diagnostics. When you use the -v (verbose) flag, you can see all ICMP messages, not just echo replies.

Common ICMP Message Types

Type Name Purpose When You See It
0 Echo Reply Response to ping Normal successful ping
3 Destination Unreachable Host/network/port can't be reached Host is down, network doesn't exist
8 Echo Request Ping request packet Your own sent packet (visible with -v)
11 Time Exceeded Packet TTL expired Low TTL value, packet died in transit
5 Redirect Route changed Router suggests better path

Type 3: Destination Unreachable (Detailed Codes)

When a router or host cannot deliver your packet, it sends back a Type 3 message with a specific code explaining why:

Code Name Meaning Example Scenario
0 Network Unreachable The destination network doesn't exist ping 10.99.99.99 - no route to network
1 Host Unreachable Network exists but host is down/unreachable ping 192.168.1.254 - host doesn't respond
2 Protocol Unreachable Network protocol not supported ICMP blocked on destination
3 Port Unreachable Destination port is closed Used by traceroute
4 Fragmentation Needed Packet too big, can't be fragmented MTU issues
13 Communication Prohibited Firewall/policy blocked packet Security filtering

Example with verbose:

$ ./ft_ping -v 192.168.1.254
PING 192.168.1.254 (192.168.1.254) 56(84) bytes of data
From 192.168.1.1 icmp_seq=1 Destination Host Unreachable
From 192.168.1.1 icmp_seq=2 Destination Host Unreachable

Your router (192.168.1.1) is telling you it can't reach the host.

Type 11: Time Exceeded (TTL Expired)

When a packet's TTL (Time To Live) reaches 0, the router drops the packet and sends back a Type 11 message.

Code Name Meaning
0 TTL Exceeded in Transit Packet died during routing
1 Fragment Reassembly Time Exceeded Fragments couldn't be reassembled in time

Example with low TTL:

$ ./ft_ping -v -t 1 google.com
PING google.com (142.251.142.14) 56(84) bytes of data
From 192.168.1.1 icmp_seq=1 Time to live exceeded
From 192.168.1.1 icmp_seq=2 Time to live exceeded

With TTL=1, the packet dies at your router (first hop).

This is how traceroute works! It sends packets with increasing TTL values (1, 2, 3...) and collects the "Time Exceeded" responses to map the route.

Type 8: Echo Request (Your Own Packet)

With -v on localhost, you might see your own sent packets:

$ ./ft_ping -v 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data
From 127.0.0.1 icmp_seq=1 Echo Request (our own packet)
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.051 ms

This happens because the loopback interface captures both sent and received packets.

Why Verbose Mode is Useful

Without -v: You only see successful replies. When ping fails, you just see "Request timeout" with no explanation.

With -v: You see why it failed:

  • Is the network unreachable? (routing problem)
  • Is the host unreachable? (host is down)
  • Did the packet TTL expire? (too many hops or TTL too low)
  • Is there a firewall blocking? (communication prohibited)

This diagnostic information helps network troubleshooting!


Checksum

  • Initially set to 0, then computed over entire ICMP packet

Checksum is calculated using 16-bit chunks of data. This 16-bit word size is a protocol rule. If data length is odd, we pad with [0x00] (in code: sum += *(uint8_t *)ptr;)


Identifier

id - match request ↔ reply


Sequence number

  • Starts at 1 and increments for each packet

Data

  • can be anything but usually a timestamp

Data Structures

struct s_ping_options

Stores command-line arguments parsed from user input.

Fields:

  • bool verbose - Flag indicating if -v (verbose mode) was specified
  • char *destination - Target hostname or IP address from command line
  • bool help_requested - Flag indicating if -h or -? was specified

Usage: Created in main() and filled by parse_ping_argc()


struct s_resolved_ipv4

Stores the resolved IPv4 address information for the target destination.

Fields:

  • struct sockaddr_in addr - Binary IPv4 address structure used by socket functions
    • sin_family - Always AF_INET (indicates IPv4)
    • sin_addr - 32-bit IP address in network byte order (e.g., 0x08080808 for 8.8.8.8)
    • sin_port - Port number (not used for ICMP)
  • char ip_string[INET_ADDRSTRLEN] - Human-readable IP string (e.g., "142.250.185.46")
    • INET_ADDRSTRLEN = 16 bytes (enough for "255.255.255.255\0")
  • char *hostname - Pointer to original input string from user (can be IP or domain name)

Usage: Output structure filled by resolve_ipv4_sockaddr() after DNS resolution


struct s_icmp_header

ICMP packet header structure (8 bytes minimum + data).

Fields:

  • int8_t type - ICMP message type (0 = Echo Reply, 8 = Echo Request)
  • int8_t code - ICMP message code (always 0 for Echo messages)
  • int16_t checksum - 16-bit one's complement checksum of entire ICMP packet
  • uint16_t id - Identifier to match request ↔ reply (usually process ID)
  • uint16_t sequence - Sequence number (increments for each packet sent)
  • int8_t data[] - Flexible array member for payload (timestamp, padding, etc.)

enum e_icmp_type

ICMP message types used in the program.

Values:

  • ICMP_UNKNOWN = -1 - Unknown or unsupported type
  • ICMP_ECHO_REPLY = 0 - Echo Reply (response to ping)
  • ICMP_ECHO_REQUEST = 8 - Echo Request (ping packet)

Key Functions

parse_ping_argc()

int parse_ping_argc(int argc, char *argv[], struct s_ping_options *options)

Purpose: Parse command-line arguments and store results in options struct

Parameters:

  • argc - Argument count from main
  • argv[] - Argument values from main
  • options - Pointer to struct where parsed options are stored

Returns:

  • 0 - Success, valid options parsed
  • 1 - Error (invalid option or missing destination)
  • 2 - Help requested (-h or -?), help message already printed

Behavior:

  • Loops through all arguments
  • Detects flags: -v (verbose), -h/-? (help)
  • Stores destination (first non-flag argument)
  • Prints help and returns 2 if help requested
  • Prints error + help and returns 1 for invalid options
  • Validates destination exists before returning

resolve_ipv4_sockaddr()

int resolve_ipv4_sockaddr(const char *dest, struct s_resolved_ipv4 *out)

Purpose: Resolve hostname or IP string to binary IPv4 address

Parameters:

  • dest - Input: hostname (e.g., "google.com") or IP string (e.g., "8.8.8.8")
  • out - Output: pointer to struct where resolved address info is stored

Returns:

  • 0 - Success, out is filled with valid IPv4 address
  • -1 - Failure (DNS lookup failed, invalid input, or conversion error)

What it does:

  1. Validates input parameters
  2. Sets up getaddrinfo() hints for IPv4/ICMP/raw socket
  3. Calls getaddrinfo() to perform DNS resolution
  4. Extracts binary IPv4 address to out->addr
  5. Converts binary address to string using inet_ntop()
  6. Stores original hostname pointer
  7. Frees resolver resources

Key functions used:

  • getaddrinfo() - Converts hostname/IP string → binary address (with DNS lookup)
  • inet_ntop() - Converts binary address → human-readable string
  • freeaddrinfo() - Frees memory allocated by getaddrinfo (must call!)

calculate_icmp_checksum()

uint16_t calculate_icmp_checksum(void *data, int16_t len)

Purpose: Calculate RFC 1071 Internet Checksum for ICMP packet integrity

Parameters:

  • data - Pointer to ICMP packet data (header + payload)
  • len - Length of data in bytes

Returns:

  • 16-bit checksum value (one's complement)

Algorithm:

  1. Sum all 16-bit words in the data
  2. If odd length, add the last byte as 8-bit value
  3. Fold any overflow (carry bits) from 32-bit sum into 16 bits
  4. Return one's complement (~sum)

Usage:

  • Set checksum field to 0 before calling
  • Calculate checksum over entire ICMP packet
  • Store result in checksum field before sending

copy_icmp_header()

void copy_icmp_header(int8_t *dest, int8_t *src, int16_t len)

Purpose: Copy ICMP header bytes from source to destination

Parameters:

  • dest - Destination buffer
  • src - Source buffer
  • len - Number of bytes to copy

Note: Simple byte-by-byte copy. Consider using memcpy() for better performance.


Network Functions Reference

getaddrinfo()

int getaddrinfo(const char *node, const char *service,
                const struct addrinfo *hints, struct addrinfo **res)

Purpose: Protocol-independent hostname/IP resolution (DNS lookup)

What it does:

  • Takes hostname or IP string
  • Performs DNS lookup if needed
  • Returns linked list of matching addresses
  • Handles IPv4/IPv6 automatically based on hints

Must call: freeaddrinfo(res) when done to prevent memory leak


inet_ntop()

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)

Purpose: Convert binary network address to presentation (string) format

Parameters:

  • af - Address family (AF_INET for IPv4)
  • src - Pointer to binary address (e.g., &sockaddr_in.sin_addr)
  • dst - Destination buffer for string
  • size - Size of destination buffer (INET_ADDRSTRLEN for IPv4)

Returns: Pointer to dst on success, NULL on error

Example: 0x08080808"8.8.8.8"

About

recoding the ping command

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors