Skip to content
Snippets Groups Projects
Commit 279964bb authored by Marek Vavrusa's avatar Marek Vavrusa
Browse files

Ported new DNS packet handling code to UDP handler.

Commit refs #756.
parent b6654b99
No related branches found
No related tags found
No related merge requests found
......@@ -171,7 +171,7 @@ int main(int argc, char **argv)
int rc = pid_write(pidfile);
if (rc < 0) {
log_server_warning("Failed to create "
"PID file '%s'.", pidfile);
"PID file '%s'.\n", pidfile);
}
// Change directory if daemonized
......
......@@ -174,3 +174,19 @@ int socket_close(int socket)
return KNOT_EOK;
}
int socket_initaddr(sockaddr_t *addr, int af)
{
if (af == PF_INET6) {
#ifndef DISABLE_IPV6
addr->ptr = (struct sockaddr*)&addr->addr6;
addr->len = sizeof(struct sockaddr_in6);
#else
return KNOT_ENOTSUP;
#endif
}
addr->ptr = (struct sockaddr*)&addr->addr4;
addr->len = sizeof(struct sockaddr_in);
return KNOT_EOK;
}
......@@ -20,12 +20,25 @@
/* POSIX only. */
#include <sys/socket.h>
#include <netinet/in.h>
/*! \brief Socket-related constants. */
enum {
SOCKET_MTU_SZ = 8192, /*!< \todo Determine UDP MTU size. */
} socket_const_t;
/*! \brief Universal socket address. */
typedef struct sockaddr_t {
struct sockaddr* ptr; /*!< Pointer to used sockaddr. */
socklen_t len; /*!< Length of used sockaddr. */
union {
struct sockaddr_in addr4; /*!< IPv4 sockaddr. */
#ifndef DISABLE_IPV6
struct sockaddr_in6 addr6; /*!< IPv6 sockaddr. */
#endif
};
} sockaddr_t;
/*!
* \brief Create socket.
*
......@@ -98,6 +111,20 @@ int socket_listen(int fd, int backlog_size);
*/
int socket_close(int fd);
/*!
* \brief Initialize sockaddr structure.
*
* Members ptr and len will be initialized to correct address family.
*
* \param addr Socket address structure
* \param af Requested address family.
*
* \retval KNOT_EOK on success.
* \retval KNOT_ENOTSUP on unsupported address family (probaly INET6).
*/
int socket_initaddr(sockaddr_t *addr, int af);
#endif // _KNOT_SOCKET_H_
/*! @} */
......@@ -15,6 +15,7 @@
#include "knot/server/name-server.h"
#include "knot/stat/stat.h"
#include "knot/server/server.h"
#include "dnslib/packet.h"
int udp_master(dthread_t *thread)
{
......@@ -29,8 +30,17 @@ int udp_master(dthread_t *thread)
}
sockaddr_t addr;
if (socket_initaddr(&addr, handler->type) != KNOT_EOK) {
log_server_error("Socket type %d is not supported, "
"IPv6 support is probably disabled.\n",
handler->type);
return KNOT_ENOTSUP;
}
/* Set socket options. */
int flag = 1;
#ifndef DISABLE_IPV6
if (handler->type == AF_INET6) {
/* Disable dual-stack for performance reasons. */
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag));
......@@ -40,6 +50,7 @@ int udp_master(dthread_t *thread)
setsockopt(fd, IPPROTO_IPV6, IPV6_MTU, &flag, sizeof(flag));
flag = 1; */
}
#endif
if (handler->type == AF_INET) {
/* Disable fragmentation. */
......@@ -48,65 +59,34 @@ int udp_master(dthread_t *thread)
flag = 1;
}
/*!
* \todo Use custom allocator.
* Although this is much cheaper,
* 16kB worth of buffers *may* pose a problem.
*/
uint8_t inbuf[SOCKET_MTU_SZ];
uint8_t outbuf[SOCKET_MTU_SZ];
struct sockaddr* addr = 0;
socklen_t addrlen = 0;
struct sockaddr_in faddr4;
if (handler->type == AF_INET) {
addr = (struct sockaddr*)&faddr4;
addrlen = sizeof(faddr4);
}
#ifndef DISABLE_IPV6
struct sockaddr_in6 faddr6;
if (handler->type == AF_INET6) {
addr = (struct sockaddr*)&faddr6;
addrlen = sizeof(faddr6);
}
#endif
/*
* Check addr len.
*/
if (!addr) {
debug_net("udp: received invalid socket type %d,"
"AF_INET (%d) or AF_INET6 (%d) expected.\n",
handler->type, AF_INET, AF_INET6);
return KNOT_EINVAL;
}
/* in case of STAT_COMPILE the following code will declare thread_stat
* variable in following fashion: stat_t *thread_stat;
*/
stat_t *thread_stat;
stat_t *thread_stat = 0;
STAT_INIT(thread_stat); //XXX new stat instance every time.
stat_set_protocol(thread_stat, stat_UDP);
// Loop until all data is read
debug_net("udp: thread started (worker %p).\n", thread);
int res = 0;
ssize_t n = 0;
uint8_t qbuf[SOCKET_MTU_SZ];
dnslib_query_t qtype = DNSLIB_QUERY_NORMAL;
while (n >= 0) {
n = recvfrom(sock, inbuf, SOCKET_MTU_SZ, 0,
addr, &addrlen);
n = recvfrom(sock, qbuf, sizeof(qbuf), 0,
addr.ptr, &addr.len);
// Cancellation point
/* Cancellation point. */
if (dt_is_cancelled(thread)) {
break;
}
// faddr has to be read immediately.
stat_get_first(thread_stat, addr);
/* faddr has to be read immediately. */
stat_get_first(thread_stat, addr.ptr);
// Error and interrupt handling
/* Error and interrupt handling. */
if (unlikely(n <= 0)) {
if (errno != EINTR && errno != 0) {
debug_net("udp: recvfrom() failed: %d\n",
......@@ -121,29 +101,59 @@ int udp_master(dthread_t *thread)
}
}
// Answer request
debug_net("udp: received %zd bytes.\n", n);
size_t answer_size = SOCKET_MTU_SZ;
int res = ns_answer_request(ns, inbuf, n, outbuf,
&answer_size);
dnslib_response_t *resp = dnslib_response_new(4 * 1024); // 4K
size_t resp_len = sizeof(qbuf);
/* Parse query. */
res = ns_parse_query(qbuf, sizeof(qbuf), resp, &qtype);
if (unlikely(res < 0)) {
/* Send error response. */
if (res != KNOT_EMALF ) {
uint16_t pkt_id = dnslib_packet_get_id(qbuf);
ns_error_response(ns, pkt_id, res,
qbuf, &resp_len);
}
dnslib_response_free(&resp);
continue;
}
/* Handle query. */
switch(qtype) {
case DNSLIB_QUERY_NORMAL:
res = ns_answer_normal(ns, resp, qbuf, &resp_len);
break;
case DNSLIB_QUERY_AXFR:
/*! \todo Enqueue xfr request. */
break;
case DNSLIB_QUERY_IXFR:
case DNSLIB_QUERY_NOTIFY:
case DNSLIB_QUERY_UPDATE:
break;
}
debug_net("udp: got answer of size %zd.\n",
answer_size);
resp_len);
dnslib_response_free(&resp);
// Send answer
if (res == 0) {
assert(answer_size > 0);
assert(resp_len > 0);
debug_net("udp: answer wire format (size %zd):\n",
(unsigned) answer_size);
debug_net_hex((const char *) outbuf, answer_size);
debug_net_hex((const char *) outbuf, resp_len);
// Send datagram
res = sendto(sock, outbuf, answer_size,
0, addr, addrlen);
res = sendto(sock, qbuf, resp_len,
0, addr.ptr, addr.len);
// Check result
if (res != (int)answer_size) {
if (res != (int)resp_len) {
debug_net("udp: %s: failed: %d - %d.\n",
"socket_sendto()",
res, errno);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment