}
}
+/* Return a feature support string for an IP protocol version */
+static
+const char *check_ip_version_support(
+ struct net_state_t *net_state,
+ int ip_version)
+{
+ if (is_ip_version_supported(net_state, ip_version)) {
+ return "ok";
+ } else {
+ return "no";
+ }
+}
+
/* Given a feature name, return a string for the check-support reply */
static
const char *check_support(
}
if (!strcmp(feature, "ip-4")) {
- return "ok";
+ return check_ip_version_support(net_state, 4);
}
if (!strcmp(feature, "ip-6")) {
- return "ok";
+ return check_ip_version_support(net_state, 6);
}
if (!strcmp(feature, "send-probe")) {
return true;
}
+/*
+ Check the probe parameters against currently supported features
+ and report and error if there is a problem.
+
+ Return true if everything is okay, false otherwise.
+*/
+static
+bool validate_probe_parameters(
+ struct net_state_t *net_state,
+ struct probe_param_t *param)
+{
+ if (!is_ip_version_supported(net_state, param->ip_version)) {
+ printf(
+ "%d invalid-argument reason ip-version-not-supported\n",
+ param->command_token);
+
+ return false;
+ }
+
+ if (!is_protocol_supported(net_state, param->protocol)) {
+ printf(
+ "%d invalid-argument reason protocol-not-supported\n",
+ param->command_token);
+
+ return false;
+ }
+
+ return true;
+}
+
/* Handle "send-probe" commands */
static
void send_probe_command(
}
}
+ if (!validate_probe_parameters(net_state, ¶m)) {
+ return;
+ }
+
/* Send the probe using a platform specific mechanism */
send_probe(net_state, ¶m);
}
void init_net_state(
struct net_state_t *net_state);
+bool is_ip_version_supported(
+ struct net_state_t *net_state,
+ int ip_version);
+
bool is_protocol_supported(
struct net_state_t *net_state,
int protocol);
memset(net_state, 0, sizeof(struct net_state_t));
net_state->platform.icmp4 = IcmpCreateFile();
- if (net_state->platform.icmp4 == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "Failure opening ICMPv4 %d\n", GetLastError());
+ net_state->platform.icmp6 = Icmp6CreateFile();
+
+ if (net_state->platform.icmp4 == INVALID_HANDLE_VALUE
+ && net_state->platform.icmp6 == INVALID_HANDLE_VALUE)
+ {
+ fprintf(stderr, "Failure opening ICMP %d\n", GetLastError());
exit(EXIT_FAILURE);
}
+}
- net_state->platform.icmp6 = Icmp6CreateFile();
- if (net_state->platform.icmp6 == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "Failure opening ICMPv6 %d\n", GetLastError());
- exit(EXIT_FAILURE);
+/*
+ If we succeeded at opening the ICMP file handle, we can
+ assume that IP protocol version is supported.
+*/
+bool is_ip_version_supported(
+ struct net_state_t *net_state,
+ int ip_version)
+{
+ if (ip_version == 4) {
+ return (net_state->platform.icmp4 != INVALID_HANDLE_VALUE);
+ } else if (ip_version == 6) {
+ return (net_state->platform.icmp6 != INVALID_HANDLE_VALUE);
}
+
+ return false;
}
/* On Windows, we only support ICMP probes */
/* Open the raw sockets for sending/receiving IPv4 packets */
static
-void open_ip4_sockets(
+int open_ip4_sockets(
struct net_state_t *net_state)
{
int send_socket;
send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (send_socket == -1) {
- perror("Failure opening IPv4 send socket");
- exit(EXIT_FAILURE);
+ return -1;
}
/*
if (setsockopt(
send_socket, IPPROTO_IP, IP_HDRINCL, &trueopt, sizeof(int))) {
- perror("Failure to set IP_HDRINCL");
- exit(EXIT_FAILURE);
+ close(send_socket);
+ return -1;
}
/*
*/
recv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (recv_socket == -1) {
- perror("Failure opening IPv4 receive socket");
- exit(EXIT_FAILURE);
+ close(send_socket);
+ return -1;
}
+ net_state->platform.ip4_present = true;
net_state->platform.ip4_send_socket = send_socket;
net_state->platform.ip4_recv_socket = recv_socket;
+
+ return 0;
}
/* Open the raw sockets for sending/receiving IPv6 packets */
static
-void open_ip6_sockets(
+int open_ip6_sockets(
struct net_state_t *net_state)
{
int send_socket_icmp;
send_socket_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (send_socket_icmp == -1) {
- perror("Failure opening ICMPv6 send socket");
- exit(EXIT_FAILURE);
+ return -1;
}
send_socket_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
if (send_socket_udp == -1) {
- perror("Failure opening UDPv6 send socket");
- exit(EXIT_FAILURE);
+ close(send_socket_icmp);
+
+ return -1;
}
recv_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (recv_socket == -1) {
- perror("Failure opening IPv6 receive socket");
- exit(EXIT_FAILURE);
- }
+ close(send_socket_icmp);
+ close(send_socket_udp);
- set_socket_nonblocking(recv_socket);
+ return -1;
+ }
+ net_state->platform.ip6_present = true;
net_state->platform.icmp6_send_socket = send_socket_icmp;
net_state->platform.udp6_send_socket = send_socket_udp;
net_state->platform.ip6_recv_socket = recv_socket;
+
+ return 0;
}
/*
void init_net_state_privileged(
struct net_state_t *net_state)
{
+ int ip4_err = 0;
+ int ip6_err = 0;
+
memset(net_state, 0, sizeof(struct net_state_t));
net_state->platform.next_sequence = MIN_PORT;
- open_ip4_sockets(net_state);
- open_ip6_sockets(net_state);
+ if (open_ip4_sockets(net_state)) {
+ ip4_err = errno;
+ }
+ if (open_ip6_sockets(net_state)) {
+ ip6_err = errno;
+ }
+
+ /*
+ If we couldn't open either IPv4 or IPv6 sockets, we can't do
+ much, so print errors and exit.
+ */
+ if (!net_state->platform.ip4_present
+ && !net_state->platform.ip6_present) {
+
+ errno = ip4_err;
+ perror("Failure to open IPv4 sockets");
+
+ errno = ip6_err;
+ perror("Failure to open IPv6 sockets");
+
+ exit(EXIT_FAILURE);
+ }
}
/*
set_socket_nonblocking(net_state->platform.ip4_recv_socket);
set_socket_nonblocking(net_state->platform.ip6_recv_socket);
- check_length_order(net_state);
+ if (net_state->platform.ip4_present) {
+ check_length_order(net_state);
+ }
+
check_sctp_support(net_state);
}
+/*
+ Returns true if we were able to open sockets for a particular
+ IP protocol version.
+*/
+bool is_ip_version_supported(
+ struct net_state_t *net_state,
+ int ip_version)
+{
+ if (ip_version == 4) {
+ return net_state->platform.ip4_present;
+ } else if (ip_version == 6) {
+ return net_state->platform.ip6_present;
+ } else {
+ return false;
+ }
+}
+
/* Returns true if we can transmit probes using the specified protocol */
bool is_protocol_supported(
struct net_state_t *net_state,
struct probe_t *probe;
struct probe_t *probe_safe_iter;
- receive_replies_from_icmp_socket(
- net_state, net_state->platform.ip4_recv_socket,
- handle_received_ip4_packet);
+ if (net_state->platform.ip4_present) {
+ receive_replies_from_icmp_socket(
+ net_state, net_state->platform.ip4_recv_socket,
+ handle_received_ip4_packet);
+ }
- receive_replies_from_icmp_socket(
- net_state, net_state->platform.ip6_recv_socket,
- handle_received_ip6_packet);
+ if (net_state->platform.ip6_present) {
+ receive_replies_from_icmp_socket(
+ net_state, net_state->platform.ip6_recv_socket,
+ handle_received_ip6_packet);
+ }
LIST_FOREACH_SAFE(
probe, &net_state->outstanding_probes,
/* We'll use rack sockets to send and recieve probes on Unix systems */
struct net_state_platform_t
{
+ /* true if we were successful at opening IPv4 sockets */
+ bool ip4_present;
+
+ /* true if we were successful at opening IPv6 sockets */
+ bool ip6_present;
+
/* Socket used to send raw IPv4 packets */
int ip4_send_socket;
def udp_port_test(self, address): # type: (unicode) -> None
'Test UDP probes with variations on source port and dest port'
+ if not check_feature(self, 'udp'):
+ return
+
cmd = '80 send-probe protocol udp ' + address
self.write_command(cmd)
reply = self.parse_reply()
test_basic_probe(self, 4, 'tcp')
+ if not check_feature(self, 'tcp'):
+ return
+
# Probe a local port assumed to be open (ssh)
cmd = '80 send-probe ip-4 127.0.0.1 protocol tcp port 22'
self.write_command(cmd)
test_basic_probe(self, 6, 'tcp')
+ if not check_feature(self, 'tcp'):
+ return
+
# Probe a local port assumed to be open (ssh)
cmd = '80 send-probe ip-6 ::1 protocol tcp port 22'
self.write_command(cmd)
struct mtr_ctl *ctl,
struct packet_command_pipe_t *cmdpipe)
{
+ /* Check the IP protocol version */
+ if (ctl->af == AF_INET6) {
+ if (check_feature(ctl, cmdpipe, "ip-6")) {
+ return -1;
+ }
+ } else if (ctl->af == AF_INET) {
+ if (check_feature(ctl, cmdpipe, "ip-4")) {
+ return -1;
+ }
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Check the transport protocol */
if (ctl->mtrtype == IPPROTO_ICMP) {
if (check_feature(ctl, cmdpipe, "icmp")) {
return -1;