Compare commits
4 commits
ac9ca93d9f
...
71ca9abc2e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71ca9abc2e | ||
|
|
e6693c97cc | ||
|
|
5713e343aa | ||
|
|
a9bdaf33f2 |
8 changed files with 72 additions and 18 deletions
2
LICENSE
2
LICENSE
|
|
@ -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
|
If the program does terminal interaction, make it output a short
|
||||||
notice like this when it starts in an interactive mode:
|
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 program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
||||||
|
|
|
||||||
19
README.md
19
README.md
|
|
@ -1,7 +1,7 @@
|
||||||
# libicmp
|
# libicmp
|
||||||
|
|
||||||
Non-blocking ICMPv4 library for building ping, traceroute, and network
|
ICMPv4 library for building ping, traceroute, and network diagnostic tools.
|
||||||
diagnostic tools.
|
Supports both non-blocking (default) and blocking socket modes.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
|
|
@ -28,12 +28,14 @@ make test
|
||||||
|
|
||||||
```c
|
```c
|
||||||
icmp_handle_t *icmp_create(void);
|
icmp_handle_t *icmp_create(void);
|
||||||
|
icmp_handle_t *icmp_create_block(void);
|
||||||
void icmp_destroy(icmp_handle_t *h);
|
void icmp_destroy(icmp_handle_t *h);
|
||||||
int icmp_get_fd(const 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_create()` opens a raw ICMP socket in non-blocking mode and returns an
|
||||||
`icmp_get_fd()` exposes the underlying file descriptor for use with
|
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()`.
|
`select()` or `poll()`. Errors are retrieved via `icmp_strerror()`.
|
||||||
|
|
||||||
### Send
|
### Send
|
||||||
|
|
@ -71,12 +73,13 @@ on error.
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
### handle/
|
### handle/
|
||||||
Handle lifecycle: `icmp_create()`, `icmp_destroy()`, `icmp_get_fd()`.
|
Handle lifecycle: `icmp_create()`, `icmp_create_block()`, `icmp_destroy()`,
|
||||||
Owns the opaque `icmp_handle_t` struct and the error state attached to it.
|
`icmp_get_fd()`. Owns the opaque `icmp_handle_t` struct and the error state
|
||||||
|
attached to it.
|
||||||
|
|
||||||
### socket/
|
### socket/
|
||||||
Raw socket creation, non-blocking configuration, and the DF (Don't
|
Raw socket creation, optional non-blocking configuration (`O_NONBLOCK`), and
|
||||||
Fragment) flag via `IP_MTU_DISCOVER`.
|
the DF (Don't Fragment) flag via `IP_MTU_DISCOVER`.
|
||||||
|
|
||||||
### send/
|
### send/
|
||||||
Packet building and transmission. Assembles the ICMP header and payload,
|
Packet building and transmission. Assembles the ICMP header and payload,
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ typedef void (*icmp_callback_t)(const icmp_reply_t *reply, void *userdata);
|
||||||
|
|
||||||
/* Handle lifecycle */
|
/* Handle lifecycle */
|
||||||
icmp_handle_t *icmp_create(void);
|
icmp_handle_t *icmp_create(void);
|
||||||
|
icmp_handle_t *icmp_create_block(void);
|
||||||
void icmp_destroy(icmp_handle_t *h);
|
void icmp_destroy(icmp_handle_t *h);
|
||||||
int icmp_get_fd(const 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 */
|
/* Socket options */
|
||||||
int icmp_set_dont_fragment(icmp_handle_t *h);
|
int icmp_set_dont_fragment(icmp_handle_t *h);
|
||||||
|
int icmp_set_tos(icmp_handle_t *h, uint8_t tos);
|
||||||
|
|
||||||
/* Error handling */
|
/* Error handling */
|
||||||
const char *icmp_strerror(const icmp_handle_t *h);
|
const char *icmp_strerror(const icmp_handle_t *h);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ SRCS += $(SRC_DIR)/error/should_retry.c
|
||||||
SRCS += $(SRC_DIR)/socket/create.c
|
SRCS += $(SRC_DIR)/socket/create.c
|
||||||
SRCS += $(SRC_DIR)/socket/configure.c
|
SRCS += $(SRC_DIR)/socket/configure.c
|
||||||
SRCS += $(SRC_DIR)/socket/set_dont_fragment.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/create.c
|
||||||
SRCS += $(SRC_DIR)/handle/destroy.c
|
SRCS += $(SRC_DIR)/handle/destroy.c
|
||||||
SRCS += $(SRC_DIR)/handle/get_fd.c
|
SRCS += $(SRC_DIR)/handle/get_fd.c
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,11 @@
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static int alloc_icmp_handle(struct icmp_handle **h);
|
static int alloc_icmp_handle(struct icmp_handle **h);
|
||||||
static void init_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 *
|
static struct icmp_handle *
|
||||||
icmp_create(void)
|
create_handle(void)
|
||||||
{
|
{
|
||||||
struct icmp_handle *h;
|
struct icmp_handle *h;
|
||||||
|
|
||||||
|
|
@ -26,6 +27,17 @@ icmp_create(void)
|
||||||
return NULL;
|
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))
|
if (-1 == socket_configure(h))
|
||||||
{
|
{
|
||||||
close(h->fd);
|
close(h->fd);
|
||||||
|
|
@ -36,6 +48,12 @@ icmp_create(void)
|
||||||
return (icmp_handle_t *)h;
|
return (icmp_handle_t *)h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icmp_handle_t *
|
||||||
|
icmp_create_block(void)
|
||||||
|
{
|
||||||
|
return (icmp_handle_t *)create_handle();
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
alloc_icmp_handle(struct icmp_handle **h)
|
alloc_icmp_handle(struct icmp_handle **h)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,12 @@ handle_send_error(struct icmp_handle *h)
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
|
|
||||||
saved_errno = 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,
|
icmp_set_error_fmt(h, ICMP_ERR_EAGAIN,
|
||||||
"Send would block (buffer full, retry later)");
|
"Send would block (buffer full, retry later)");
|
||||||
return -1;
|
return 1;
|
||||||
}
|
}
|
||||||
icmp_set_error_fmt(h, ICMP_ERR_SEND, "sendto() failed: %s",
|
icmp_set_error_fmt(h, ICMP_ERR_SEND, "sendto() failed: %s",
|
||||||
strerror(saved_errno));
|
strerror(saved_errno));
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,19 @@ send_to_destination(struct icmp_handle *h, const void *packet, size_t len,
|
||||||
struct in_addr dest, uint8_t ttl)
|
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)
|
if (send_set_socket_ttl(h, ttl) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
send_prepare_destination(&addr, dest);
|
send_prepare_destination(&addr, dest);
|
||||||
|
|
||||||
if (send_packet(h, packet, len, &addr) < 0)
|
ret = send_packet(h, packet, len, &addr);
|
||||||
return -1;
|
|
||||||
|
|
||||||
icmp_clear_error(h);
|
switch (ret)
|
||||||
return 0;
|
{
|
||||||
|
case -1: return -1;
|
||||||
|
case 1: return 1;
|
||||||
|
default: icmp_clear_error(h); return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
src/socket/set_tos.c
Normal file
25
src/socket/set_tos.c
Normal 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;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue