feat: add -M (dont-fragment) option
- Add FLAG_DONT_FRAGMENT flag and cli_handle_dont_fragment handler - Register -M/--dont-fragment option in the X-macro option table - Apply DF bit via icmp_set_dont_fragment() before ping loop - Expand error output: table-driven ICMP error messages and dedicated frag-needed output with next-hop MTU - Add STATIC_ARRAY_FOREACH / COUNT_OF macros to compiler.h
This commit is contained in:
parent
5a8671bdde
commit
770265ee80
9 changed files with 107 additions and 17 deletions
|
|
@ -3,4 +3,9 @@
|
||||||
|
|
||||||
#define __unused __attribute__((unused))
|
#define __unused __attribute__((unused))
|
||||||
|
|
||||||
|
#define COUNT_OF(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
#define STATIC_ARRAY_FOREACH(arr, ptr) \
|
||||||
|
for ((ptr) = (arr); (ptr) < (arr) + COUNT_OF(arr); (ptr)++)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,14 @@
|
||||||
cli_handle_flood, \
|
cli_handle_flood, \
|
||||||
OPT_ARG_NONE, \
|
OPT_ARG_NONE, \
|
||||||
"Flood mode" \
|
"Flood mode" \
|
||||||
|
) \
|
||||||
|
X( \
|
||||||
|
'M', \
|
||||||
|
"dont-fragment", \
|
||||||
|
no_argument, \
|
||||||
|
cli_handle_dont_fragment, \
|
||||||
|
OPT_ARG_NONE, \
|
||||||
|
"Set the Don't Fragment bit" \
|
||||||
)
|
)
|
||||||
|
|
||||||
#undef X
|
#undef X
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
extern const struct option_descriptor g_options[];
|
extern const struct option_descriptor g_options[];
|
||||||
|
|
||||||
int cli_handle_count(const char *arg, void *config);
|
int cli_handle_count(const char *arg, void *config);
|
||||||
|
int cli_handle_dont_fragment(const char *arg, void *config);
|
||||||
int cli_handle_deadline(const char *arg, void *config);
|
int cli_handle_deadline(const char *arg, void *config);
|
||||||
int cli_handle_flood(const char *arg, void *config);
|
int cli_handle_flood(const char *arg, void *config);
|
||||||
int cli_handle_help(const char *arg, void *config);
|
int cli_handle_help(const char *arg, void *config);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#define FLAG_VERBOSE (1 << 0)
|
#define FLAG_VERBOSE (1 << 0)
|
||||||
#define FLAG_QUIET (1 << 1)
|
#define FLAG_QUIET (1 << 1)
|
||||||
#define FLAG_FLOOD (1 << 2)
|
#define FLAG_FLOOD (1 << 2)
|
||||||
|
#define FLAG_DONT_FRAGMENT (1 << 3)
|
||||||
|
|
||||||
#define HAS_FLAG(flags, flag) ((flags) & (flag))
|
#define HAS_FLAG(flags, flag) ((flags) & (flag))
|
||||||
#define SET_FLAG(flags, flag) ((flags) |= (flag))
|
#define SET_FLAG(flags, flag) ((flags) |= (flag))
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ PING_SRCS = $(CLI_SRCS) \
|
||||||
$(PING_SRC_DIR)/main.c \
|
$(PING_SRC_DIR)/main.c \
|
||||||
$(PING_SRC_DIR)/cli/parse.c \
|
$(PING_SRC_DIR)/cli/parse.c \
|
||||||
$(PING_SRC_DIR)/cli/handlers/handle_count.c \
|
$(PING_SRC_DIR)/cli/handlers/handle_count.c \
|
||||||
|
$(PING_SRC_DIR)/cli/handlers/handle_dont_fragment.c \
|
||||||
$(PING_SRC_DIR)/cli/handlers/handle_deadline.c \
|
$(PING_SRC_DIR)/cli/handlers/handle_deadline.c \
|
||||||
$(PING_SRC_DIR)/cli/handlers/handle_flood.c \
|
$(PING_SRC_DIR)/cli/handlers/handle_flood.c \
|
||||||
$(PING_SRC_DIR)/cli/handlers/handle_help.c \
|
$(PING_SRC_DIR)/cli/handlers/handle_help.c \
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,8 @@ static void
|
||||||
build_long_options(struct option *long_opts, size_t nb_opts,
|
build_long_options(struct option *long_opts, size_t nb_opts,
|
||||||
const struct option_descriptor *src)
|
const struct option_descriptor *src)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < nb_opts; ++i) {
|
for (size_t i = 0; i < nb_opts; ++i)
|
||||||
|
{
|
||||||
long_opts[i].name = src[i].long_opt;
|
long_opts[i].name = src[i].long_opt;
|
||||||
long_opts[i].has_arg = src[i].has_arg;
|
long_opts[i].has_arg = src[i].has_arg;
|
||||||
long_opts[i].flag = NULL;
|
long_opts[i].flag = NULL;
|
||||||
|
|
|
||||||
11
src/ping/cli/handlers/handle_dont_fragment.c
Normal file
11
src/ping/cli/handlers/handle_dont_fragment.c
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "ping/cli.h"
|
||||||
|
#include "ping/ft_ping_flags.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
cli_handle_dont_fragment(__unused const char *arg, void *config_void)
|
||||||
|
{
|
||||||
|
struct ping_config *config = (struct ping_config *)config_void;
|
||||||
|
SET_FLAG(config->flags, FLAG_DONT_FRAGMENT);
|
||||||
|
return CLI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
@ -25,22 +25,28 @@ int
|
||||||
ping_run(const struct ping_config *config)
|
ping_run(const struct ping_config *config)
|
||||||
{
|
{
|
||||||
icmp_handle_t *handle;
|
icmp_handle_t *handle;
|
||||||
int ret;
|
int ret = 0 ;
|
||||||
size_t i;
|
size_t i = 0 ;
|
||||||
|
|
||||||
if (0 == config->nb_destinations)
|
if (0 == config->nb_destinations)
|
||||||
return 1;
|
return 1;
|
||||||
handle = icmp_create();
|
handle = icmp_create();
|
||||||
if (NULL == handle)
|
if (NULL == handle)
|
||||||
return 1;
|
return 1;
|
||||||
ret = 0;
|
if (HAS_FLAG(config->flags, FLAG_DONT_FRAGMENT)
|
||||||
i = 0;
|
&& 0 != icmp_set_dont_fragment(handle))
|
||||||
|
{
|
||||||
|
ret = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
while (i < config->nb_destinations)
|
while (i < config->nb_destinations)
|
||||||
{
|
{
|
||||||
if (0 != ping_one(config, config->destinations[i], handle))
|
if (0 != ping_one(config, config->destinations[i], handle))
|
||||||
ret = 1;
|
ret = 1;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
cleanup:
|
||||||
icmp_destroy(handle);
|
icmp_destroy(handle);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
|
@ -7,27 +8,82 @@
|
||||||
#include "icmp_types.h"
|
#include "icmp_types.h"
|
||||||
#include "internal/ping/output.h"
|
#include "internal/ping/output.h"
|
||||||
|
|
||||||
|
// TODO: CLEAN THIS FILE !
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
|
static void output_frag_needed(const char *from, uint16_t seq,
|
||||||
|
uint16_t next_mtu);
|
||||||
static const char *error_msg_for(const icmp_reply_t *reply);
|
static const char *error_msg_for(const icmp_reply_t *reply);
|
||||||
/* -------------------- */
|
/* -------------------- */
|
||||||
|
|
||||||
void
|
void
|
||||||
ping_output_error(const icmp_reply_t *reply,
|
ping_output_error(const icmp_reply_t *reply,
|
||||||
__unused const icmp_offending_packet_t *offending,
|
const icmp_offending_packet_t *offending,
|
||||||
uint16_t seq, __unused const struct ping_config *config)
|
uint16_t seq, __unused const struct ping_config *config)
|
||||||
{
|
{
|
||||||
char from_str[INET_ADDRSTRLEN];
|
char from_str[INET_ADDRSTRLEN];
|
||||||
|
|
||||||
inet_ntop(AF_INET, &reply->from, from_str, sizeof(from_str));
|
inet_ntop(AF_INET, &reply->from, from_str, sizeof(from_str));
|
||||||
fprintf(stderr, "From %s: icmp_seq=%u %s\n",
|
if (ICMP_TYPE_DEST_UNREACHABLE == reply->type
|
||||||
|
&& ICMP_CODE_FRAG_NEEDED == reply->code)
|
||||||
|
output_frag_needed(from_str, seq, offending->next_mtu);
|
||||||
|
else
|
||||||
|
dprintf(STDERR_FILENO, "From %s: icmp_seq=%u %s\n",
|
||||||
from_str, (unsigned int)seq, error_msg_for(reply));
|
from_str, (unsigned int)seq, error_msg_for(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
output_frag_needed(const char *from, uint16_t seq, uint16_t next_mtu)
|
||||||
|
{
|
||||||
|
if (next_mtu > 0)
|
||||||
|
dprintf(STDERR_FILENO,
|
||||||
|
"From %s: icmp_seq=%u Frag needed and DF set (mtu = %u)\n",
|
||||||
|
from, (unsigned int)seq, (unsigned int)next_mtu);
|
||||||
|
else
|
||||||
|
dprintf(STDERR_FILENO,
|
||||||
|
"From %s: icmp_seq=%u Frag needed and DF set (mtu unknown)\n",
|
||||||
|
from, (unsigned int)seq);
|
||||||
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
error_msg_for(const icmp_reply_t *reply)
|
error_msg_for(const icmp_reply_t *reply)
|
||||||
{
|
{
|
||||||
if (ICMP_TYPE_TIME_EXCEEDED == reply->type)
|
static const struct s_error_entry
|
||||||
return ("Time to live exceeded");
|
{
|
||||||
if (ICMP_CODE_HOST_UNREACHABLE == reply->code)
|
uint8_t type;
|
||||||
return ("Destination Host Unreachable");
|
uint8_t code;
|
||||||
return ("Destination Net Unreachable");
|
const char *msg;
|
||||||
|
} error_table[] = {
|
||||||
|
{
|
||||||
|
ICMP_TYPE_TIME_EXCEEDED, ICMP_CODE_TTL_EXCEEDED,
|
||||||
|
"Time to live exceeded"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ICMP_TYPE_TIME_EXCEEDED, ICMP_CODE_FRAG_REASM_EXCEEDED,
|
||||||
|
"Frag reassembly time exceeded"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ICMP_TYPE_DEST_UNREACHABLE, ICMP_CODE_NET_UNREACHABLE,
|
||||||
|
"Destination Net Unreachable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ICMP_TYPE_DEST_UNREACHABLE, ICMP_CODE_HOST_UNREACHABLE,
|
||||||
|
"Destination Host Unreachable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ICMP_TYPE_DEST_UNREACHABLE, ICMP_CODE_PROTOCOL_UNREACHABLE,
|
||||||
|
"Destination Protocol Unreachable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ICMP_TYPE_DEST_UNREACHABLE, ICMP_CODE_PORT_UNREACHABLE,
|
||||||
|
"Destination Port Unreachable"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const struct s_error_entry *entry;
|
||||||
|
|
||||||
|
STATIC_ARRAY_FOREACH(error_table, entry)
|
||||||
|
{
|
||||||
|
if (entry->type == reply->type && entry->code == reply->code)
|
||||||
|
return (entry->msg);
|
||||||
|
}
|
||||||
|
return ("Unknown ICMP error");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue