Commit 0c1d8493 authored by Lubos Slovak's avatar Lubos Slovak

Proper handling of malformed packets.

- No error returned if the incoming packet has less than 2 bytes.
- Other cases should be handled properly.

refs #1867 @30min
parent bbd6089b
......@@ -132,6 +132,13 @@ static void tcp_sweep(fdset_t *set, int fd, void* data)
*
* \param w Associated I/O event.
* \param revents Returned events.
*
* \note We do not know if the packet makes sense or if it is
* a bunch of random bytes. There is no way to find out
* without parsing. However, it is irrelevant if we copy
* these random bytes to the response, so we may do it
* and ensure that in case of good packet the response
* is proper.
*/
static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen)
{
......@@ -177,24 +184,26 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
knot_packet_t *packet =
knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
if (packet == NULL) {
/*! \todo The packet may have less bytes than required. */
uint16_t pkt_id = knot_wire_get_id(qbuf);
uint8_t flags1 = knot_wire_get_flags1(qbuf);
knot_ns_error_response(ns, pkt_id, &flags1, KNOT_RCODE_SERVFAIL,
qbuf, &resp_len);
tcp_reply(fd, qbuf, resp_len);
int ret = knot_ns_error_response_from_query(ns, qbuf, n,
KNOT_RCODE_SERVFAIL,
qbuf, &resp_len);
if (ret == KNOT_EOK) {
tcp_reply(fd, qbuf, resp_len);
}
return KNOTD_EOK;
}
int parse_res = knot_ns_parse_packet(qbuf, n, packet, &qtype);
if (unlikely(parse_res != KNOT_EOK)) {
if (parse_res > 0) { /* Returned RCODE */
/*! \todo The packet may have less bytes than required*/
uint16_t pkt_id = knot_wire_get_id(qbuf);
uint8_t flags1 = knot_wire_get_flags1(qbuf);
knot_ns_error_response(ns, pkt_id, &flags1, parse_res,
qbuf, &resp_len);
tcp_reply(fd, qbuf, resp_len);
int ret = knot_ns_error_response_from_query(ns, qbuf, n,
parse_res, qbuf, &resp_len);
if (ret == KNOT_EOK) {
tcp_reply(fd, qbuf, resp_len);
}
}
knot_packet_free(&packet);
return KNOTD_EOK;
......
......@@ -47,6 +47,7 @@
#include "libknot/packet/packet.h"
#include "knot/server/zones.h"
#include "knot/server/notify.h"
#include "libknot/util/error.h"
/* Check for sendmmsg syscall. */
#ifdef HAVE_SENDMMSG
......@@ -83,11 +84,15 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len,
knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
if (packet == NULL) {
dbg_net("udp: failed to create packet on fd=%d\n", fd);
/*! \todo The packet may have less bytes than required. */
uint16_t pkt_id = knot_wire_get_id(qbuf);
uint8_t flags1 = knot_wire_get_flags1(qbuf);
knot_ns_error_response(ns, pkt_id, &flags1, KNOT_RCODE_SERVFAIL,
qbuf, resp_len);
int ret = knot_ns_error_response_from_query(ns, qbuf, qbuflen,
KNOT_RCODE_SERVFAIL,
qbuf, resp_len);
if (ret != KNOT_EOK) {
return KNOTD_EMALF;
}
return KNOTD_EOK; /* Created error response. */
}
......@@ -96,11 +101,15 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len,
if (unlikely(res != KNOTD_EOK)) {
dbg_net("udp: failed to parse packet on fd=%d\n", fd);
if (res > 0) { /* Returned RCODE */
/*! \todo The packet may have less bytes than required. */
uint16_t pkt_id = knot_wire_get_id(qbuf);
uint8_t flags1 = knot_wire_get_flags1(qbuf);
knot_ns_error_response(ns, pkt_id, &flags1, res,
qbuf, resp_len);
int ret = knot_ns_error_response_from_query(ns, qbuf,
qbuflen,
res, qbuf,
resp_len);
if (ret != KNOT_EOK) {
knot_packet_free(&packet);
return KNOTD_EMALF;
}
}
knot_packet_free(&packet);
......
......@@ -2867,6 +2867,33 @@ void knot_ns_error_response(const knot_nameserver_t *nameserver,
/*----------------------------------------------------------------------------*/
int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver,
const uint8_t *query, size_t size,
uint8_t rcode, uint8_t *response_wire,
size_t *rsize)
{
if (size < 2) {
// ignore packet
return KNOT_EFEWDATA;
}
uint16_t pkt_id = knot_wire_get_id(query);
uint8_t *flags1_ptr = NULL;
uint8_t flags1;
if (size > KNOT_WIRE_OFFSET_FLAGS1) {
flags1 = knot_wire_get_flags1(query);
flags1_ptr = &flags1;
}
knot_ns_error_response(nameserver, pkt_id, flags1_ptr,
rcode, response_wire, rsize);
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
void knot_ns_error_response_full(knot_nameserver_t *nameserver,
knot_packet_t *response, uint8_t rcode,
uint8_t *response_wire, size_t *rsize)
......
......@@ -236,6 +236,11 @@ void knot_ns_error_response(const knot_nameserver_t *nameserver,
uint8_t rcode, uint8_t *response_wire,
size_t *rsize);
int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver,
const uint8_t *query, size_t size,
uint8_t rcode, uint8_t *response_wire,
size_t *rsize);
void knot_ns_error_response_full(knot_nameserver_t *nameserver,
knot_packet_t *response, uint8_t rcode,
uint8_t *response_wire, size_t *rsize);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment