commit 295e3dd9beb30d9ea2fcd8cd51ab309d2342cb34 Author: starnakin Date: Wed Oct 29 09:18:40 2025 -0500 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95491b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +obj \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..30a71dc --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +NAME := ft_ping + +CC := gcc +CFLAGS := -Wall -Wextra -Werror -g + +LD := $(CC) +LDFLAGS := + +SRC := $(shell find src -name '*.c') +OBJ := $(patsubst src/%.c,obj/%.o,$(SRC)) + +all: $(NAME) + +obj/%.o: src/%.c + mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ + +$(NAME): $(OBJ) + mkdir -p build + $(LD) $(LDFLAGS) -o build/$(NAME) $(OBJ) + +clean: + rm -rf obj + +fclean: clean + rm -rf build + +re: + $(MAKE) fclean + $(MAKE) all + +.PHONY: all clean fclean re +-include $(DEP) diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..8501af8 --- /dev/null +++ b/src/main.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void print_err(const char *format, ...) +{ + va_list args; + + puts("ft_ping: "); + va_start(args, format); + vprintf(format, args); + va_end(args); + putchar('\n'); +} + +unsigned short checksum(void *b, int len) { + unsigned short *buf = b; + unsigned int sum = 0; + unsigned short result; + + for (sum = 0; len > 1; len -= 2) + sum += *buf++; + if (len == 1) + sum += *(unsigned char *)buf; + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + result = ~sum; + return result; +} + +int pktcmp(const char *sent, const char *received, size_t packet_size) +{ + const struct icmphdr *sent_hdr = (const struct icmphdr*) sent; + const struct icmphdr *received_hdr = (const struct icmphdr*) received; + + if (received_hdr->type != 0 || received_hdr->code != 8) + return 1; + + if (received_hdr->un.echo.sequence == sent_hdr->un.echo.sequence) + return 2; + + const char *sent_payload = sent + sizeof(struct icmphdr); + const char *received_payload = received + sizeof(struct icmphdr); + + return memcmp(sent_payload, received_payload, packet_size - sizeof(struct icmphdr)); +} + +int fill_with_random(char *str, size_t nb) +{ + int fd; + + fd = open("/dev/random", O_RDONLY); + if (fd < 0) + { + print_err("error: open /dev/random failed."); + return 1; + } + if (read(fd, str, nb) != (ssize_t) nb) + { + close(fd); + print_err("error: read /dev/random failed."); + return 2; + } + close(fd); + return 0; +} + +int update_packet(char *packet, size_t payload_size) +{ + static size_t sequence = 1; + size_t hdr_size = sizeof(struct icmphdr); + size_t packet_size = hdr_size + payload_size; + + struct icmphdr *hdr = (void*)packet; + + hdr->un.echo.sequence = htons(sequence++); + hdr->checksum = 0; + + if (fill_with_random(packet + hdr_size, payload_size)) + { + free(packet); + return 1; + } + + hdr->checksum = checksum(packet, packet_size); + return 0; +} + +void *create_packet(size_t payload_size) +{ + size_t hdr_size = sizeof(struct icmphdr); + size_t packet_size = hdr_size + payload_size; + + char *packet; + + packet = malloc(packet_size); + if (packet == NULL) + { + print_err("allocation failed."); + return NULL; + } + + struct icmphdr *hdr = (struct icmphdr *)packet; + + hdr->type = ICMP_ECHO; + hdr->code = 0; + hdr->un.echo.id = htons(getpid() & 0xFFFF); + + update_packet(packet, payload_size); + + return packet; +} + +int packet_check(char *packet, size_t packet_size) +{ + struct icmphdr *hdr = (struct icmphdr *) packet; + + const uint16_t checksum_bak = hdr->checksum; + hdr->checksum = 0; + int tmp = checksum(packet, packet_size); + hdr->checksum = checksum_bak; + + return tmp - checksum_bak; +} + +int main(int ac, char **av) +{ + (void) ac; + (void) av; + size_t payload_size = 48; + size_t packet_size = sizeof(struct icmphdr) + payload_size; + + int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + + if (sockfd == -1) + { + print_err("open socket failed, maybe try in root (:"); + return 1; + } + + struct sockaddr_in dest; + + dest.sin_family = AF_INET; + dest.sin_port = htons(0); + inet_pton(AF_INET, "8.8.8.8", &dest.sin_addr); + + while (1) { + + char *packet = create_packet(payload_size); + if (packet == NULL) + { + close(sockfd); + return 2; + } + + if (sendto(sockfd, packet, packet_size, 0, (struct sockaddr *) &dest, sizeof(dest)) == -1) + { + print_err("error: send packet failed."); + free(packet); + close(sockfd); + return 2; + } + printf("icmp request sent\n"); + + char *buffer; + buffer = malloc(packet_size * sizeof(char)); + if (buffer == NULL) + { + print_err("error: allocation failed."); + free(packet); + close(sockfd); + return 10; + } + struct sockaddr_in sender; + socklen_t len = sizeof(sender); + + do + { + if (recvfrom(sockfd, buffer, packet_size, 0, (struct sockaddr *) &sender, &len) < 0) + { + print_err("error: receive packet failed."); + close(sockfd); + free(buffer); + free(packet); + return 3; + } + } + while (len == packet_size && packet_check(buffer, packet_size) == 0 && pktcmp(packet, buffer, packet_size) == 0); + free(packet); + printf("icmp reply received\n"); + sleep(1); + } +} \ No newline at end of file