Compare commits

...

4 commits

Author SHA1 Message Date
lohhiiccc
71ca9abc2e feat: set TOS 2026-04-23 13:53:35 +02:00
lohhiiccc
e6693c97cc chore: update LICENSE 2026-04-23 12:59:58 +02:00
lohhiiccc
5713e343aa feat: icmp_create_block() 2026-04-22 23:58:41 +02:00
lohhiiccc
a9bdaf33f2 feat: add ENOBUFS (no buff space left) to EAGAIN error behavior 2026-04-22 13:22:33 +02:00
8 changed files with 72 additions and 18 deletions

View file

@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
libicmp Copyright (C) 2026 lohhiiccc
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

View file

@ -1,7 +1,7 @@
# libicmp
Non-blocking ICMPv4 library for building ping, traceroute, and network
diagnostic tools.
ICMPv4 library for building ping, traceroute, and network diagnostic tools.
Supports both non-blocking (default) and blocking socket modes.
## Dependencies
@ -28,12 +28,14 @@ make test
```c
icmp_handle_t *icmp_create(void);
icmp_handle_t *icmp_create_block(void);
void icmp_destroy(icmp_handle_t *h);
int icmp_get_fd(const icmp_handle_t *h);
```
`icmp_create()` opens a raw ICMP socket and returns an opaque handle.
`icmp_get_fd()` exposes the underlying file descriptor for use with
`icmp_create()` opens a raw ICMP socket in non-blocking mode and returns an
opaque handle. `icmp_create_block()` does the same but leaves the socket in
blocking mode`icmp_get_fd()` exposes the underlying file descriptor for use with
`select()` or `poll()`. Errors are retrieved via `icmp_strerror()`.
### Send
@ -71,12 +73,13 @@ on error.
## Modules
### handle/
Handle lifecycle: `icmp_create()`, `icmp_destroy()`, `icmp_get_fd()`.
Owns the opaque `icmp_handle_t` struct and the error state attached to it.
Handle lifecycle: `icmp_create()`, `icmp_create_block()`, `icmp_destroy()`,
`icmp_get_fd()`. Owns the opaque `icmp_handle_t` struct and the error state
attached to it.
### socket/
Raw socket creation, non-blocking configuration, and the DF (Don't
Fragment) flag via `IP_MTU_DISCOVER`.
Raw socket creation, optional non-blocking configuration (`O_NONBLOCK`), and
the DF (Don't Fragment) flag via `IP_MTU_DISCOVER`.
### send/
Packet building and transmission. Assembles the ICMP header and payload,

View file

@ -50,6 +50,7 @@ typedef void (*icmp_callback_t)(const icmp_reply_t *reply, void *userdata);
/* Handle lifecycle */
icmp_handle_t *icmp_create(void);
icmp_handle_t *icmp_create_block(void);
void icmp_destroy(icmp_handle_t *h);
int icmp_get_fd(const icmp_handle_t *h);
@ -75,6 +76,7 @@ int icmp_error_extract_offending(const icmp_reply_t *reply,
/* Socket options */
int icmp_set_dont_fragment(icmp_handle_t *h);
int icmp_set_tos(icmp_handle_t *h, uint8_t tos);
/* Error handling */
const char *icmp_strerror(const icmp_handle_t *h);

View file

@ -9,6 +9,7 @@ SRCS += $(SRC_DIR)/error/should_retry.c
SRCS += $(SRC_DIR)/socket/create.c
SRCS += $(SRC_DIR)/socket/configure.c
SRCS += $(SRC_DIR)/socket/set_dont_fragment.c
SRCS += $(SRC_DIR)/socket/set_tos.c
SRCS += $(SRC_DIR)/handle/create.c
SRCS += $(SRC_DIR)/handle/destroy.c
SRCS += $(SRC_DIR)/handle/get_fd.c

View file

@ -8,10 +8,11 @@
/* Forward declarations */
static int alloc_icmp_handle(struct icmp_handle **h);
static void init_icmp_handle(struct icmp_handle *h);
static struct icmp_handle *create_handle(void);
/* -------------------- */
icmp_handle_t *
icmp_create(void)
static struct icmp_handle *
create_handle(void)
{
struct icmp_handle *h;
@ -26,6 +27,17 @@ icmp_create(void)
return NULL;
}
return h;
}
icmp_handle_t *
icmp_create(void)
{
struct icmp_handle *h = create_handle();
if (NULL == h)
return NULL;
if (-1 == socket_configure(h))
{
close(h->fd);
@ -36,6 +48,12 @@ icmp_create(void)
return (icmp_handle_t *)h;
}
icmp_handle_t *
icmp_create_block(void)
{
return (icmp_handle_t *)create_handle();
}
static int
alloc_icmp_handle(struct icmp_handle **h)
{

View file

@ -37,11 +37,12 @@ handle_send_error(struct icmp_handle *h)
int saved_errno;
saved_errno = errno;
if (EAGAIN == saved_errno || EWOULDBLOCK == saved_errno)
if (EAGAIN == saved_errno || EWOULDBLOCK == saved_errno
|| ENOBUFS == saved_errno)
{
icmp_set_error_fmt(h, ICMP_ERR_EAGAIN,
"Send would block (buffer full, retry later)");
return -1;
return 1;
}
icmp_set_error_fmt(h, ICMP_ERR_SEND, "sendto() failed: %s",
strerror(saved_errno));

View file

@ -7,16 +7,20 @@ int
send_to_destination(struct icmp_handle *h, const void *packet, size_t len,
struct in_addr dest, uint8_t ttl)
{
struct sockaddr_in addr;
struct sockaddr_in addr;
int ret;
if (send_set_socket_ttl(h, ttl) < 0)
return -1;
send_prepare_destination(&addr, dest);
if (send_packet(h, packet, len, &addr) < 0)
return -1;
ret = send_packet(h, packet, len, &addr);
icmp_clear_error(h);
return 0;
switch (ret)
{
case -1: return -1;
case 1: return 1;
default: icmp_clear_error(h); return 0;
}
}

25
src/socket/set_tos.c Normal file
View file

@ -0,0 +1,25 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include "internal/icmp_internal.h"
int
icmp_set_tos(struct icmp_handle *h, uint8_t tos)
{
int val;
int saved_errno;
if (NULL == h)
return -1;
val = (int)tos;
if (0 > setsockopt(h->fd, IPPROTO_IP, IP_TOS, &val, sizeof(val)))
{
saved_errno = errno;
icmp_set_error_fmt(h, ICMP_ERR_SOCKET,
"Failed to set TOS: %s", strerror(saved_errno));
return -1;
}
return 0;
}