Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
lohhiiccc
3717e01ab9 feat: traceroute skel 2026-04-22 23:45:38 +02:00
24 changed files with 469 additions and 1 deletions

View file

@ -60,6 +60,7 @@ AC_CONFIG_FILES([
Makefile Makefile
src/Makefile src/Makefile
src/ping/Makefile src/ping/Makefile
src/traceroute/Makefile
tests/Makefile tests/Makefile
]) ])
AC_OUTPUT AC_OUTPUT

View file

@ -0,0 +1,14 @@
#ifndef TRACEROUTE_CLI_HANDLERS_H
#define TRACEROUTE_CLI_HANDLERS_H
#include "cli.h"
extern const struct option_descriptor g_options[];
int cli_handle_help(const char *arg, void *config);
int cli_handle_version(const char *arg, void *config);
int cli_handle_verbose(const char *arg, void *config);
int cli_handle_max_ttl(const char *arg, void *config);
int cli_handle_waittime(const char *arg, void *config);
#endif

View file

@ -0,0 +1,65 @@
#ifndef TRACEROUTE_CLI_OPT_H
#define TRACEROUTE_CLI_OPT_H
#include <getopt.h>
#include "cli.h"
enum {
OPT_TR_ARG_HOPS = OPT_ARG_STRING + 1,
OPT_TR_ARG_SECONDS,
};
#define TRACEROUTE_OPTIONS_LIST \
X( \
'h', \
"help", \
no_argument, \
cli_handle_help, \
OPT_ARG_NONE, \
"Display this help and exit" \
) \
X( \
'V', \
"version", \
no_argument, \
cli_handle_version, \
OPT_ARG_NONE, \
"Display version information and exit" \
) \
X( \
'v', \
"verbose", \
no_argument, \
cli_handle_verbose, \
OPT_ARG_NONE, \
"Verbose output" \
) \
X( \
'm', \
"max-ttl", \
required_argument, \
cli_handle_max_ttl, \
OPT_TR_ARG_HOPS, \
"Set the max number of hops" \
) \
X( \
'w', \
"waittime", \
required_argument, \
cli_handle_waittime, \
OPT_TR_ARG_SECONDS, \
"Set the time to wait for a response" \
)
#undef X
#define X(short_opt, long_opt, has_arg, handler, arg_type, desc) + 1
enum { TR_OPT_LEN = (0 TRACEROUTE_OPTIONS_LIST) };
#undef X
#define X(short_opt, long_opt, has_arg, handler, arg_type, desc) \
+ (1 * (has_arg == no_argument) \
+ (2 * (has_arg == required_argument) \
+ (3 * (has_arg == optional_argument))))
enum { TR_OPTSTR_LEN = (2 TRACEROUTE_OPTIONS_LIST) };
#endif

View file

@ -0,0 +1,9 @@
#ifndef TRACEROUTE_CLI_PARSE_UTILS_H
#define TRACEROUTE_CLI_PARSE_UTILS_H
#include <netinet/in.h>
#include "traceroute/traceroute.h"
int cli_parse_destination(const char *s, struct traceroute_config *config);
#endif

11
includes/traceroute/cli.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef TRACEROUTE_CLI_H
#define TRACEROUTE_CLI_H
#include <cli.h>
#include "traceroute/traceroute.h"
enum cli_code cli_parse_arguments(int argc, char **argv, struct
traceroute_config *config);
void cli_config_free(struct traceroute_config *config);
#endif

View file

@ -0,0 +1,11 @@
#ifndef FT_TRACEROUTE_CONST_H
#define FT_TRACEROUTE_CONST_H
#define DEFAULT_MAX_TTL 30
#define DEFAULT_NQUERIES 3
#define DEFAULT_WAITTIME 5.0
#define MAX_TRACEROUTE_TTL 255
#define MAX_NQUERIES 10
#endif

View file

@ -0,0 +1,10 @@
#ifndef FT_TRACEROUTE_FLAGS_H
#define FT_TRACEROUTE_FLAGS_H
#define FLAG_TR_VERBOSE (1 << 0)
#define FLAG_TR_NO_DNS (1 << 1)
#define HAS_FLAG(flags, flag) ((flags) & (flag))
#define SET_FLAG(flags, flag) ((flags) |= (flag))
#endif

View file

@ -0,0 +1,18 @@
#ifndef TRACEROUTE_H
#define TRACEROUTE_H
#include <stdint.h>
#include <netinet/in.h>
struct traceroute_config {
const char *destination;
struct in_addr dest_ip;
uint8_t max_ttl;
uint8_t nqueries;
double waittime;
uint8_t flags;
};
int traceroute_run(const struct traceroute_config *config);
#endif

View file

@ -1 +1 @@
SUBDIRS = ping SUBDIRS = ping traceroute

View file

@ -0,0 +1,54 @@
bin_PROGRAMS = ft_traceroute
noinst_LTLIBRARIES = libtraceroute_core.la
TRACEROUTE_VERSION = 0.0.1
VERSION_HEADER = $(top_srcdir)/includes/version_gen.h
BUILT_SOURCES = $(VERSION_HEADER)
libtraceroute_core_la_SOURCES = \
cli/parse.c \
cli/config_free.c \
cli/handlers/option_map.c \
cli/handlers/handle_help.c \
cli/handlers/handle_version.c \
cli/handlers/handle_verbose.c \
cli/handlers/handle_max_ttl.c \
cli/handlers/handle_waittime.c \
cli/messages/help.c \
cli/messages/version.c \
cli/messages/error.c \
cli/parse_utils/parse_destination.c \
core/traceroute.c
BASE_CFLAGS = -std=c99 $(STRICT_CFLAGS)
if ENABLE_DEBUG
EXTRA_CFLAGS = -g -O0
else
EXTRA_CFLAGS =
endif
if ENABLE_SANITIZERS
SANITIZER_FLAGS = -fsanitize=address,undefined
else
SANITIZER_FLAGS =
endif
TRACEROUTE_CPPFLAGS = \
-I $(top_srcdir)/includes \
-I $(top_srcdir)/libcli/include \
-D_GNU_SOURCE
TRACEROUTE_CFLAGS = $(BASE_CFLAGS) $(EXTRA_CFLAGS) $(SANITIZER_FLAGS)
libtraceroute_core_la_CPPFLAGS = $(TRACEROUTE_CPPFLAGS)
libtraceroute_core_la_CFLAGS = $(TRACEROUTE_CFLAGS)
ft_traceroute_SOURCES = main.c
ft_traceroute_CPPFLAGS = $(TRACEROUTE_CPPFLAGS)
ft_traceroute_CFLAGS = $(TRACEROUTE_CFLAGS)
ft_traceroute_LDFLAGS = $(SANITIZER_FLAGS)
ft_traceroute_LDADD = \
libtraceroute_core.la \
$(top_builddir)/libcli/src/libcli.la

View file

@ -0,0 +1,7 @@
#include "traceroute/cli.h"
void
cli_config_free(struct traceroute_config *config)
{
config->destination = NULL;
}

View file

@ -0,0 +1,14 @@
#include "compiler.h"
#include "traceroute/cli.h"
#include "internal/traceroute/cli_handlers.h"
/* Forward declaration */
void print_help(void);
/* ------------------- */
int
cli_handle_help(__unused const char *arg, __unused void *config)
{
print_help();
return CLI_EXIT_SUCCESS;
}

View file

@ -0,0 +1,15 @@
#include "traceroute/cli.h"
#include "traceroute/ft_traceroute_const.h"
#include "internal/cli/parse_utils.h"
int
cli_handle_max_ttl(const char *arg, void *config_void)
{
struct traceroute_config *config = (struct traceroute_config *)config_void;
uint64_t val;
if (0 != cli_parse_uint64(arg, &val) || 0 == val || val > MAX_TRACEROUTE_TTL)
return CLI_ERROR;
config->max_ttl = (uint8_t)val;
return CLI_SUCCESS;
}

View file

@ -0,0 +1,11 @@
#include "compiler.h"
#include "traceroute/cli.h"
#include "traceroute/ft_traceroute_flags.h"
int
cli_handle_verbose(__unused const char *arg, void *config_void)
{
struct traceroute_config *config = (struct traceroute_config *)config_void;
SET_FLAG(config->flags, FLAG_TR_VERBOSE);
return CLI_SUCCESS;
}

View file

@ -0,0 +1,13 @@
#include "compiler.h"
#include "traceroute/cli.h"
/* Forward declaration */
void print_version(void);
/* ------------------- */
int
cli_handle_version(__unused const char *arg, __unused void *config)
{
print_version();
return CLI_EXIT_SUCCESS;
}

View file

@ -0,0 +1,14 @@
#include "traceroute/cli.h"
#include "internal/cli/parse_utils.h"
int
cli_handle_waittime(const char *arg, void *config_void)
{
struct traceroute_config *config = (struct traceroute_config *)config_void;
float val;
if (0 != cli_parse_ufloat(arg, &val) || val <= 0.0f)
return CLI_ERROR;
config->waittime = (double)val;
return CLI_SUCCESS;
}

View file

@ -0,0 +1,13 @@
#include "internal/traceroute/cli_handlers.h"
#include "internal/traceroute/options.h"
#undef X
#define X(short_opt, long_opt, has_arg, handler, arg_type, desc) \
{ short_opt, long_opt, has_arg, handler, arg_type, desc },
const struct option_descriptor g_options[] = {
TRACEROUTE_OPTIONS_LIST
{0, NULL, 0, NULL, OPT_ARG_NONE, NULL}
};
#undef X

View file

@ -0,0 +1,32 @@
#include <unistd.h>
#include <stdio.h>
#include "traceroute/cli.h"
#include "version_gen.h"
/* Forward declaration */
static inline void print_suggest_help(void);
/* ------------------- */
enum cli_code
error_missing_dest(void)
{
dprintf(STDERR_FILENO, "%s: usage error: Destination address required\n",
g_prog_name);
print_suggest_help();
return CLI_ERROR;
}
enum cli_code
error_invalid_dest(void)
{
dprintf(STDERR_FILENO, "%s: unknown host\n", g_prog_name);
return CLI_ERROR;
}
static inline void
print_suggest_help(void)
{
dprintf(STDERR_FILENO, "Try '%s --help' for more information.\n",
g_prog_name);
}

View file

@ -0,0 +1,40 @@
#include <stdio.h>
#include "internal/traceroute/cli_handlers.h"
#include "internal/traceroute/options.h"
/* Forward declaration */
static inline const char *option_arg_type_to_str(int type);
/* ------------------- */
void
print_help(void)
{
printf("ft_traceroute - Trace the route to a network host\n");
printf("Usage: ft_traceroute [options] <destination>\n\n");
printf("Options:\n");
for (size_t i = 0; i < TR_OPT_LEN; ++i)
{
const struct option_descriptor *opt = &g_options[i];
const char *argstr = option_arg_type_to_str(opt->arg_type);
printf(" -%c, --%-10s %-8s %s\n",
opt->short_opt,
opt->long_opt,
argstr[0] ? argstr : "",
opt->description);
}
}
static inline const char *
option_arg_type_to_str(int type)
{
switch (type)
{
case OPT_ARG_NONE: return "";
case OPT_TR_ARG_HOPS: return "<HOPS>";
case OPT_TR_ARG_SECONDS: return "<SEC>";
default: return "<ARG>";
}
}

View file

@ -0,0 +1,19 @@
#include <stdio.h>
#include "version_gen.h"
void
print_version(void)
{
printf("%s version %s\n", g_prog_name, PING_VERSION);
printf("Copyright (C) 2026 lohhiicccc\n");
printf("License GPLv3+:");
printf("GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\n");
printf("This is free software: ");
printf("you are free to change and redistribute it.\n");
printf("There is NO WARRANTY, to the extent permitted by law.\n");
printf("\n");
#if PING_HAS_GIT_COMMIT
printf("Build: %s (commit %s)\n", PING_BUILD_DATE, PING_GIT_COMMIT);
#endif
}

View file

@ -0,0 +1,39 @@
#include <string.h>
#include <getopt.h>
#include "traceroute/cli.h"
#include "traceroute/ft_traceroute_const.h"
#include "internal/traceroute/cli_handlers.h"
#include "internal/traceroute/parse_utils.h"
#include "internal/traceroute/options.h"
#include "internal/cli/messages.h"
/* Forward declaration */
static void init_config(struct traceroute_config *config);
/* ------------------- */
enum cli_code
cli_parse_arguments(int argc, char **argv, struct traceroute_config *config)
{
char opt_str[TR_OPTSTR_LEN];
struct option long_opts[TR_OPT_LEN + 1];
enum cli_code ret;
init_config(config);
ret = cli_parse(argc, argv, config, g_options, TR_OPT_LEN,
opt_str, long_opts);
if (CLI_SUCCESS != ret)
return ret;
if (optind >= argc)
return error_missing_dest();
return cli_parse_destination(argv[optind], config);
}
static void
init_config(struct traceroute_config *config)
{
memset(config, 0, sizeof(struct traceroute_config));
config->max_ttl = DEFAULT_MAX_TTL;
config->nqueries = DEFAULT_NQUERIES;
config->waittime = DEFAULT_WAITTIME;
}

View file

@ -0,0 +1,25 @@
#include <netdb.h>
#include <string.h>
#include "traceroute/traceroute.h"
#include "internal/traceroute/parse_utils.h"
#include "internal/cli/messages.h"
int
cli_parse_destination(const char *s, struct traceroute_config *config)
{
struct addrinfo hints;
struct addrinfo *res;
struct sockaddr_in sin;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
if (0 != getaddrinfo(s, NULL, &hints, &res))
return error_invalid_dest();
memcpy(&sin, res->ai_addr, sizeof(sin));
freeaddrinfo(res);
config->dest_ip = sin.sin_addr;
config->destination = s;
return 0;
}

View file

@ -0,0 +1,8 @@
#include "compiler.h"
#include "traceroute/traceroute.h"
int
traceroute_run(__unused const struct traceroute_config *config)
{
return 0;
}

25
src/traceroute/main.c Normal file
View file

@ -0,0 +1,25 @@
#include <stdlib.h>
#include "traceroute/cli.h"
#include "version_gen.h"
char *g_prog_name = NULL;
int
main(int argc, char **argv)
{
struct traceroute_config config = {0};
int ret = CLI_ERROR;
g_prog_name = argv[0];
cli_set_prog_name(g_prog_name);
ret = cli_parse_arguments(argc, argv, &config);
if (ret != CLI_SUCCESS)
goto cleanup;
ret = traceroute_run(&config);
cleanup:
cli_config_free(&config);
return (ret == CLI_ERROR) ? 2 : EXIT_SUCCESS;
}