Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change UDP and ICMP sockets binding to accept a source IP from the -a… #484

Merged
merged 1 commit into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 67 additions & 109 deletions packet/construct_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,6 @@ uint16_t compute_checksum(
return (~sum & 0xffff);
}

/* Encode the IP header length field in the order required by the OS. */
static
uint16_t length_byte_swap(
const struct net_state_t *net_state,
uint16_t length)
{
if (net_state->platform.ip_length_host_order) {
return length;
} else {
return htons(length);
}
}

/* Construct a combined sockaddr from a source address and source port */
static
void construct_addr_port(
Expand All @@ -95,61 +82,27 @@ void construct_addr_port(
*sockaddr_port_offset(addr_with_port) = htons(port);
}

/* Construct a header for IP version 4 */
static
void construct_ip4_header(
const struct net_state_t *net_state,
const struct probe_t *probe,
char *packet_buffer,
int packet_size,
const struct probe_param_t *param)
{
struct IPHeader *ip;

ip = (struct IPHeader *) &packet_buffer[0];

memset(ip, 0, sizeof(struct IPHeader));

ip->version = 0x45;
ip->tos = param->type_of_service;
ip->len = length_byte_swap(net_state, packet_size);
ip->ttl = param->ttl;
ip->protocol = param->protocol;
// ip->id = htons(getpid());
memcpy(&ip->saddr,
sockaddr_addr_offset(&probe->local_addr),
sockaddr_addr_size(&probe->local_addr));
memcpy(&ip->daddr,
sockaddr_addr_offset(&probe->remote_addr),
sockaddr_addr_size(&probe->remote_addr));
}

/* Construct an ICMP header for IPv4 */
static
void construct_icmp4_header(
int construct_icmp4_packet(
const struct net_state_t *net_state,
struct probe_t *probe,
char *packet_buffer,
int packet_size,
const struct probe_param_t *param)
{
struct ICMPHeader *icmp;
int icmp_size;

if (net_state->platform.ip4_socket_raw) {
icmp = (struct ICMPHeader *) &packet_buffer[sizeof(struct IPHeader)];
icmp_size = packet_size - sizeof(struct IPHeader);
} else {
icmp = (struct ICMPHeader *) &packet_buffer[0];
icmp_size = packet_size;
}
icmp = (struct ICMPHeader *) packet_buffer;

memset(icmp, 0, sizeof(struct ICMPHeader));

icmp->type = ICMP_ECHO;
icmp->id = htons(getpid());
icmp->sequence = htons(probe->sequence);
icmp->checksum = htons(compute_checksum(icmp, icmp_size));
icmp->checksum = htons(compute_checksum(icmp, packet_size));

return 0;
}

/* Construct an ICMP header for IPv6 */
Expand Down Expand Up @@ -238,7 +191,7 @@ int udp4_checksum(void *pheader, void *udata, int psize, int dsize,
with the probe.
*/
static
void construct_udp4_header(
int construct_udp4_packet(
const struct net_state_t *net_state,
struct probe_t *probe,
char *packet_buffer,
Expand All @@ -248,13 +201,8 @@ void construct_udp4_header(
struct UDPHeader *udp;
int udp_size;

if (net_state->platform.ip4_socket_raw) {
udp = (struct UDPHeader *) &packet_buffer[sizeof(struct IPHeader)];
udp_size = packet_size - sizeof(struct IPHeader);
} else {
udp = (struct UDPHeader *) &packet_buffer[0];
udp_size = packet_size;
}
udp = (struct UDPHeader *) packet_buffer;
udp_size = packet_size;

memset(udp, 0, sizeof(struct UDPHeader));

Expand Down Expand Up @@ -283,6 +231,8 @@ void construct_udp4_header(
*checksum_off = htons(udp4_checksum(&udph, udp,
sizeof(struct UDPPseudoHeader),
udp_size, udp->checksum != 0));

return 0;
}

/* Construct a header for UDPv6 probes */
Expand Down Expand Up @@ -561,10 +511,10 @@ int construct_ip4_packet(
int packet_size,
const struct probe_param_t *param)
{
int send_socket = net_state->platform.ip4_send_socket;
int send_socket;
bool is_stream_protocol = false;
int tos, ttl, socket;
bool bind_send_socket = false;
int tos, ttl;
bool bind_send_socket = true;
struct sockaddr_storage current_sockaddr;
int current_sockaddr_len;

Expand All @@ -574,23 +524,34 @@ int construct_ip4_packet(
} else if (param->protocol == IPPROTO_SCTP) {
is_stream_protocol = true;
#endif
} else {
} else if (param->protocol == IPPROTO_ICMP) {
if (net_state->platform.ip4_socket_raw) {
construct_ip4_header(net_state, probe, packet_buffer, packet_size,
param);
send_socket = net_state->platform.icmp4_send_socket;
} else {
send_socket = net_state->platform.ip4_txrx_icmp_socket;
}
if (param->protocol == IPPROTO_ICMP) {
construct_icmp4_header(net_state, probe, packet_buffer,
packet_size, param);
} else if (param->protocol == IPPROTO_UDP) {
construct_udp4_header(net_state, probe, packet_buffer,
packet_size, param);

if (construct_icmp4_packet
(net_state, probe, packet_buffer, packet_size, param)) {
return -1;
}
} else if (param->protocol == IPPROTO_UDP) {
if (net_state->platform.ip4_socket_raw) {
send_socket = net_state->platform.udp4_send_socket;
} else {
errno = EINVAL;
send_socket = net_state->platform.ip4_txrx_udp_socket;
}

if (construct_udp4_packet
(net_state, probe, packet_buffer, packet_size, param)) {
return -1;
}
} else {
errno = EINVAL;
return -1;
}


if (is_stream_protocol) {
send_socket =
open_stream_socket(net_state, param->protocol, probe->sequence,
Expand Down Expand Up @@ -633,54 +594,51 @@ int construct_ip4_packet(
#endif

/*
Bind src port when not using raw socket to pass in ICMP id, kernel
get ICMP id from src_port when using DGRAM socket.
Check the current socket address, and if it is the same
as the source address we intend, we will skip the bind.
This is to accommodate Solaris, which, as of Solaris 11.3,
will return an EINVAL error on bind if the socket is already
bound, even if the same address is used.
*/
if (!net_state->platform.ip4_socket_raw &&
param->protocol == IPPROTO_ICMP &&
!param->is_probing_byte_order) {
current_sockaddr_len = sizeof(struct sockaddr_in);
bind_send_socket = true;
socket = net_state->platform.ip4_txrx_icmp_socket;
if (getsockname(socket, (struct sockaddr *) &current_sockaddr,
&current_sockaddr_len)) {
return -1;
}
struct sockaddr_in *sin_cur =
(struct sockaddr_in *) &current_sockaddr;
current_sockaddr_len = sizeof(struct sockaddr_in);
if (getsockname(send_socket, (struct sockaddr *) &current_sockaddr,
&current_sockaddr_len) == 0) {
struct sockaddr_in *sin_cur = (struct sockaddr_in *) &current_sockaddr;

/* avoid double bind */
if (sin_cur->sin_port) {
bind_send_socket = false;
if (net_state->platform.ip4_socket_raw) {
if (memcmp(&current_sockaddr,
&probe->local_addr, sizeof(struct sockaddr_in)) == 0) {
bind_send_socket = false;
}
} else {
/* avoid double bind for DGRAM socket */
if (sin_cur->sin_port) {
bind_send_socket = false;
}
}
}

/* Bind to our local address */
if (bind_send_socket && bind(socket, (struct sockaddr *)&probe->local_addr,
if (bind_send_socket && bind(send_socket, (struct sockaddr *)&probe->local_addr,
sizeof(struct sockaddr_in))) {
return -1;
}

/* set TOS and TTL for non-raw socket */
if (!net_state->platform.ip4_socket_raw && !param->is_probing_byte_order) {
if (param->protocol == IPPROTO_ICMP) {
socket = net_state->platform.ip4_txrx_icmp_socket;
} else if (param->protocol == IPPROTO_UDP) {
socket = net_state->platform.ip4_txrx_udp_socket;
} else {
return 0;
}
tos = param->type_of_service;
if (setsockopt(socket, SOL_IP, IP_TOS, &tos, sizeof(int))) {
return -1;
}
ttl = param->ttl;
if (setsockopt(socket, SOL_IP, IP_TTL,
&ttl, sizeof(int)) == -1) {
return -1;
}
/* Set the type of service */
tos = param->type_of_service;
if (setsockopt(send_socket, SOL_IP, IP_TOS, &tos, sizeof(int))) {
return -1;
}

/* Set the time-to-live */
ttl = param->ttl;
if (setsockopt(send_socket, SOL_IP, IP_TTL,
&ttl, sizeof(int)) == -1) {
return -1;
}



return 0;
}

Expand Down
55 changes: 28 additions & 27 deletions packet/probe_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,21 @@ int send_packet(
} else if (sockaddr->ss_family == AF_INET) {
sockaddr_length = sizeof(struct sockaddr_in);

if (net_state->platform.ip4_socket_raw) {
send_socket = net_state->platform.ip4_send_socket;
} else {
if (param->protocol == IPPROTO_ICMP) {
if (param->is_probing_byte_order) {
send_socket = net_state->platform.ip4_tmp_icmp_socket;;
} else {
send_socket = net_state->platform.ip4_txrx_icmp_socket;
}
} else if (param->protocol == IPPROTO_UDP) {
if (param->protocol == IPPROTO_ICMP) {
if (net_state->platform.ip4_socket_raw) {
send_socket = net_state->platform.icmp4_send_socket;
} else {
send_socket = net_state->platform.ip4_txrx_icmp_socket;
}
} else if (param->protocol == IPPROTO_UDP) {
if (net_state->platform.ip4_socket_raw) {
send_socket = net_state->platform.udp4_send_socket;
/* we got a ipv4 udp raw socket
* the remote port is in the payload
* we do not set in the sockaddr
*/
*sockaddr_port_offset(&dst) = 0;
} else {
send_socket = net_state->platform.ip4_txrx_udp_socket;
if (param->dest_port) {
*sockaddr_port_offset(&dst) = htons(param->dest_port);
Expand All @@ -105,6 +110,7 @@ int send_packet(
}
}
}

}

if (send_socket == 0) {
Expand Down Expand Up @@ -236,26 +242,19 @@ static
int open_ip4_sockets_raw(
struct net_state_t *net_state)
{
int send_socket;
int send_socket_icmp;
int send_socket_udp;
int recv_socket;
int trueopt = 1;

send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (send_socket == -1) {
send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (send_socket == -1) {
return -1;
}
send_socket_icmp = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (send_socket_icmp == -1) {
return -1;
}

/*
We will be including the IP header in transmitted packets.
Linux doesn't require this, but BSD derived network stacks do.
*/
if (setsockopt
(send_socket, IPPROTO_IP, IP_HDRINCL, &trueopt, sizeof(int))) {
send_socket_udp = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (send_socket_udp == -1) {
close(send_socket_icmp);

close(send_socket);
return -1;
}

Expand All @@ -265,13 +264,15 @@ int open_ip4_sockets_raw(
*/
recv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (recv_socket == -1) {
close(send_socket);
close(send_socket_icmp);
close(send_socket_udp);
return -1;
}

net_state->platform.ip4_present = true;
net_state->platform.ip4_socket_raw = true;
net_state->platform.ip4_send_socket = send_socket;
net_state->platform.icmp4_send_socket = send_socket_icmp;
net_state->platform.udp4_send_socket = send_socket_udp;
net_state->platform.ip4_recv_socket = recv_socket;

return 0;
Expand Down
7 changes: 5 additions & 2 deletions packet/probe_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ struct net_state_platform_t {
/* true if ipv6 socket is raw socket */
bool ip6_socket_raw;

/* Socket used to send raw IPv4 packets */
int ip4_send_socket;
/* Send socket for ICMPv6 packets */
int icmp4_send_socket;

/* Send socket for UDPv6 packets */
int udp4_send_socket;

/* Socket used to receive IPv4 ICMP replies */
int ip4_recv_socket;
Expand Down