Requested by tester.
return true;
}
+
+/**
+ * buffer must length INET6_ADDRSTRLEN.
+ */
+char const *
+sockaddr2str(struct sockaddr_storage *sockaddr, char *buffer)
+{
+ void *addr = NULL;
+ char const *addr_str;
+
+ if (sockaddr == NULL)
+ return "(null)";
+
+ switch (sockaddr->ss_family) {
+ case AF_INET:
+ addr = &((struct sockaddr_in *) sockaddr)->sin_addr;
+ break;
+ case AF_INET6:
+ addr = &((struct sockaddr_in6 *) sockaddr)->sin6_addr;
+ break;
+ default:
+ return "(protocol unknown)";
+ }
+
+ addr_str = inet_ntop(sockaddr->ss_family, addr, buffer,
+ INET6_ADDRSTRLEN);
+ return (addr_str != NULL) ? addr_str : "(unprintable address)";
+}
+
#include <stdbool.h>
#include <netinet/in.h>
+#include <sys/socket.h>
#include "asn1/asn1c/IPAddress.h"
#include "asn1/asn1c/IPAddressRange.h"
bool ipv4_covered(struct in_addr *, uint8_t, struct in_addr *);
bool ipv6_covered(struct in6_addr *, uint8_t, struct in6_addr *);
+char const *sockaddr2str(struct sockaddr_storage *, char *);
+
#endif /* SRC_ADDRESS_H_ */
#include <stdlib.h>
#include <string.h>
+#include "address.h"
#include "clients.h"
#include "common.h"
#include "log.h"
#include "rtr/err_pdu.h"
#include "rtr/pdu_handler.h"
+char const *
+pdutype2str(enum pdu_type type)
+{
+ switch (type) {
+ case PDU_TYPE_SERIAL_NOTIFY:
+ return "Serial Notify";
+ case PDU_TYPE_SERIAL_QUERY:
+ return "Serial Query";
+ case PDU_TYPE_RESET_QUERY:
+ return "Reset Query";
+ case PDU_TYPE_CACHE_RESPONSE:
+ return "Cache Response";
+ case PDU_TYPE_IPV4_PREFIX:
+ return "IPv4 Prefix";
+ case PDU_TYPE_IPV6_PREFIX:
+ return "IPv6 Prefix";
+ case PDU_TYPE_END_OF_DATA:
+ return "End of Data";
+ case PDU_TYPE_CACHE_RESET:
+ return "Cache Reset";
+ case PDU_TYPE_ROUTER_KEY:
+ return "Router Key";
+ case PDU_TYPE_ERROR_REPORT:
+ return "Error Report";
+ }
+
+ return "(unknown)";
+}
+
static int
pdu_header_from_reader(struct pdu_reader *reader, struct pdu_header *header)
{
}
int
-pdu_load(int fd, struct rtr_request *request,
- struct pdu_metadata const **metadata)
+pdu_load(int fd, struct sockaddr_storage *client_addr,
+ struct rtr_request *request, struct pdu_metadata const **metadata)
{
unsigned char hdr_bytes[RTRPDU_HDR_LEN];
struct pdu_reader reader;
/* No error response because the PDU might have been an error */
return error;
+#ifdef DEBUG
+ {
+ char buffer[INET6_ADDRSTRLEN];
+ pr_debug("Received a %s PDU from %s.",
+ pdutype2str(header.pdu_type),
+ sockaddr2str(client_addr, buffer));
+ }
+#endif
+
error = validate_rtr_version(fd, &header, hdr_bytes);
if (error)
return error; /* Error response PDU already sent */
/*
* DO NOT USE THE err_pdu_* functions directly. Wrap them with
* RESPOND_ERROR() INSTEAD.
+ * TODO I think this comment should be above validate_rtr_version(),
+ * and validate_rtr_version() is buggy.
*/
+
if (header.length < RTRPDU_HDR_LEN)
return RESPOND_ERROR(err_pdu_send_invalid_request_truncated(fd,
version, hdr_bytes, "Invalid header length. (< 8 bytes)"));
PDU_TYPE_ERROR_REPORT = 10,
};
+char const *pdutype2str(enum pdu_type);
+
/*
* Note: It's probably best not to use sizeof for these lengths, because it
* risks including padding, and this is not the place for it.
void (*destructor)(void *);
};
-int pdu_load(int, struct rtr_request *, struct pdu_metadata const **);
+int pdu_load(int, struct sockaddr_storage *, struct rtr_request *,
+ struct pdu_metadata const **);
struct pdu_metadata const *pdu_get_metadata(uint8_t);
struct pdu_header *pdu_get_header(void *);
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <arpa/inet.h> /* inet_ntop */
+#include <sys/types.h> /* AF_INET, AF_INET6 (needed in OpenBSD) */
+#include <sys/socket.h> /* AF_INET, AF_INET6 (needed in OpenBSD) */
#include "clients.h"
#include "config.h"
}
static int
-send_response(int fd, unsigned char *data, size_t data_len)
+send_response(int fd, uint8_t pdu_type, unsigned char *data, size_t data_len)
{
int error;
+ pr_debug("Sending %s PDU to client.", pdutype2str(pdu_type));
+
error = write(fd, data, data_len);
if (error < 0)
return pr_errno(errno, "Error sending response");
if (len != RTRPDU_SERIAL_NOTIFY_LEN)
pr_crit("Serialized Serial Notify is %zu bytes.", len);
- return send_response(fd, data, len);
+ return send_response(fd, pdu.header.pdu_type, data, len);
}
int
if (len != RTRPDU_CACHE_RESET_LEN)
pr_crit("Serialized Cache Reset is %zu bytes.", len);
- return send_response(fd, data, len);
+ return send_response(fd, pdu.header.pdu_type, data, len);
}
int
if (len != RTRPDU_CACHE_RESPONSE_LEN)
pr_crit("Serialized Cache Response is %zu bytes.", len);
- return send_response(fd, data, len);
+ return send_response(fd, pdu.header.pdu_type, data, len);
+}
+
+static void
+pr_debug_prefix4(struct ipv4_prefix_pdu *pdu)
+{
+#ifdef DEBUG
+ char buffer[INET_ADDRSTRLEN];
+ char const *addr_str;
+
+ addr_str = inet_ntop(AF_INET, &pdu->ipv4_prefix, buffer,
+ INET_ADDRSTRLEN);
+
+ pr_debug("Encoded prefix %s/%u into a PDU.", addr_str,
+ pdu->prefix_length);
+#endif
}
static int
len = serialize_ipv4_prefix_pdu(&pdu, data);
if (len != RTRPDU_IPV4_PREFIX_LEN)
pr_crit("Serialized IPv4 Prefix is %zu bytes.", len);
+ pr_debug_prefix4(&pdu);
+
+ return send_response(fd, pdu.header.pdu_type, data, len);
+}
+
+static void
+pr_debug_prefix6(struct ipv6_prefix_pdu *pdu)
+{
+#ifdef DEBUG
+ char buffer[INET6_ADDRSTRLEN];
+ char const *addr_str;
+
+ addr_str = inet_ntop(AF_INET6, &pdu->ipv6_prefix, buffer,
+ INET6_ADDRSTRLEN);
- return send_response(fd, data, len);
+ pr_debug("Encoded prefix %s/%u into a PDU.", addr_str,
+ pdu->prefix_length);
+#endif
}
static int
len = serialize_ipv6_prefix_pdu(&pdu, data);
if (len != RTRPDU_IPV6_PREFIX_LEN)
pr_crit("Serialized IPv6 Prefix is %zu bytes.", len);
+ pr_debug_prefix6(&pdu);
- return send_response(fd, data, len);
+ return send_response(fd, pdu.header.pdu_type, data, len);
}
int
pr_crit("Serialized Router Key PDU is %zu bytes, not the expected %u.",
len, pdu.header.length);
- return send_response(fd, data, len);
+ return send_response(fd, pdu.header.pdu_type, data, len);
}
struct simple_param {
if (len != GET_END_OF_DATA_LENGTH(version))
pr_crit("Serialized End of Data is %zu bytes.", len);
- error = send_response(fd, data, len);
+ error = send_response(fd, pdu.header.pdu_type, data, len);
if (error)
return error;
pr_crit("Serialized Error Report PDU is %zu bytes, not the expected %u.",
len, pdu.header.length);
- error = send_response(fd, data, len);
+ error = send_response(fd, pdu.header.pdu_type, data, len);
free(data);
return error;
return 0;
}
-
/*
* Creates the socket that will stay put and wait for new connections started
* from the clients.
{
struct sockaddr_storage sockaddr;
char buffer[INET6_ADDRSTRLEN];
- void *addr = NULL;
char const *addr_str;
- if (clients_get_addr(fd, &sockaddr) != 0) {
- addr_str = "(unknown)";
- goto done;
- }
- switch (sockaddr.ss_family) {
- case AF_INET:
- addr = &((struct sockaddr_in *) &sockaddr)->sin_addr;
- break;
- case AF_INET6:
- addr = &((struct sockaddr_in6 *) &sockaddr)->sin6_addr;
- break;
- default:
- addr_str = "(protocol unknown)";
- goto done;
- }
-
- addr_str = inet_ntop(sockaddr.ss_family, addr, buffer,
- INET6_ADDRSTRLEN);
- if (addr_str == NULL)
- addr_str = "(unprintable address)";
+ addr_str = (clients_get_addr(fd, &sockaddr) == 0)
+ ? sockaddr2str(&sockaddr, buffer)
+ : "(unknown)";
-done:
pr_errno(error, "close() failed on socket of client %s", addr_str);
}
close(param.fd);
return NULL;
}
+
while (true) { /* For each PDU... */
- error = pdu_load(param.fd, &request, &meta);
+ error = pdu_load(param.fd, ¶m.addr, &request, &meta);
if (error)
break;
sizeof_client_addr = sizeof(client_addr);
+ pr_debug("Waiting for client connections...");
do {
client_fd = accept(server_fd, (struct sockaddr *) &client_addr,
&sizeof_client_addr);
return -EINVAL;
}
+#ifdef DEBUG
+ {
+ char buffer[INET6_ADDRSTRLEN];
+ pr_debug("Client accepted: %s",
+ sockaddr2str(&client_addr, buffer));
+ }
+#endif
+
/*
* Note: My gut says that errors from now on (even the unknown
* ones) should be treated as temporary; maybe the next
return inet_ntop(AF_INET6, addr, addr_buffer2, sizeof(addr_buffer2));
}
+char const *
+fnstack_peek(void)
+{
+ return NULL;
+}
+
char const *
config_get_tal(void)
{
expected_pdu_add(PDU_TYPE_ERROR_REPORT);
/* Run and validate, before handling */
- ck_assert_int_eq(-EINVAL, pdu_load(fd, &request, &meta));
+ ck_assert_int_eq(-EINVAL, pdu_load(fd, NULL, &request, &meta));
ck_assert_uint_eq(false, has_expected_pdus());
/* Clean up */