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 COUNT_OF(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define STATIC_ARRAY_FOREACH(arr, ptr) \
|
||||
for ((ptr) = (arr); (ptr) < (arr) + COUNT_OF(arr); (ptr)++)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -91,6 +91,14 @@
|
|||
cli_handle_flood, \
|
||||
OPT_ARG_NONE, \
|
||||
"Flood mode" \
|
||||
) \
|
||||
X( \
|
||||
'M', \
|
||||
"dont-fragment", \
|
||||
no_argument, \
|
||||
cli_handle_dont_fragment, \
|
||||
OPT_ARG_NONE, \
|
||||
"Set the Don't Fragment bit" \
|
||||
)
|
||||
|
||||
#undef X
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
extern const struct option_descriptor g_options[];
|
||||
|
||||
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_flood(const char *arg, void *config);
|
||||
int cli_handle_help(const char *arg, void *config);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#ifndef FT_PING_FLAGS
|
||||
#define FT_PING_FLAGS
|
||||
|
||||
#define FLAG_VERBOSE (1 << 0)
|
||||
#define FLAG_QUIET (1 << 1)
|
||||
#define FLAG_FLOOD (1 << 2)
|
||||
#define FLAG_VERBOSE (1 << 0)
|
||||
#define FLAG_QUIET (1 << 1)
|
||||
#define FLAG_FLOOD (1 << 2)
|
||||
#define FLAG_DONT_FRAGMENT (1 << 3)
|
||||
|
||||
#define HAS_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)/cli/parse.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_flood.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,
|
||||
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].has_arg = src[i].has_arg;
|
||||
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)
|
||||
{
|
||||
icmp_handle_t *handle;
|
||||
int ret;
|
||||
size_t i;
|
||||
int ret = 0 ;
|
||||
size_t i = 0 ;
|
||||
|
||||
if (0 == config->nb_destinations)
|
||||
return 1;
|
||||
handle = icmp_create();
|
||||
if (NULL == handle)
|
||||
return 1;
|
||||
ret = 0;
|
||||
i = 0;
|
||||
if (HAS_FLAG(config->flags, FLAG_DONT_FRAGMENT)
|
||||
&& 0 != icmp_set_dont_fragment(handle))
|
||||
{
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (i < config->nb_destinations)
|
||||
{
|
||||
if (0 != ping_one(config, config->destinations[i], handle))
|
||||
ret = 1;
|
||||
i++;
|
||||
}
|
||||
cleanup:
|
||||
icmp_destroy(handle);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "compiler.h"
|
||||
|
|
@ -7,27 +8,82 @@
|
|||
#include "icmp_types.h"
|
||||
#include "internal/ping/output.h"
|
||||
|
||||
// TODO: CLEAN THIS FILE !
|
||||
/* Forward declarations */
|
||||
static const char *error_msg_for(const icmp_reply_t *reply);
|
||||
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);
|
||||
/* -------------------- */
|
||||
|
||||
void
|
||||
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)
|
||||
{
|
||||
char from_str[INET_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET, &reply->from, from_str, sizeof(from_str));
|
||||
fprintf(stderr, "From %s: icmp_seq=%u %s\n",
|
||||
from_str, (unsigned int)seq, error_msg_for(reply));
|
||||
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));
|
||||
}
|
||||
|
||||
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 *
|
||||
error_msg_for(const icmp_reply_t *reply)
|
||||
{
|
||||
if (ICMP_TYPE_TIME_EXCEEDED == reply->type)
|
||||
return ("Time to live exceeded");
|
||||
if (ICMP_CODE_HOST_UNREACHABLE == reply->code)
|
||||
return ("Destination Host Unreachable");
|
||||
return ("Destination Net Unreachable");
|
||||
static const struct s_error_entry
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t code;
|
||||
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