test dns module

This commit is contained in:
zhengshuxin 2020-10-24 10:59:00 +08:00
parent 845338db4a
commit c21cc6c733
8 changed files with 270 additions and 84 deletions

View File

@ -151,7 +151,7 @@ ACL_API int acl_rfc1035_query_compare(const ACL_RFC1035_QUERY *a,
/**
* Takes the contents of a DNS reply and fills in an array
* of resource record structures. The records array is allocated
* here, and should be freed by calling RFC1035RRDestroy().
* here, and should be freed by calling acl_rfc1035_message_destroy().
* @param buf {const char*} the data of the DNS reply
* @param sz {size_t} the buf's size
* @return {ACL_RFC1035_MESSAGE*} return the parsing result
@ -161,7 +161,7 @@ ACL_API ACL_RFC1035_MESSAGE *acl_rfc1035_response_unpack(const char *buf, size_t
/**
* Takes the contents of a DNS request and fills in an array
* of resource record structures. The records array is allocated
* here, and should be freed by calling RFC1035RRDestroy().
* here, and should be freed by calling acl_rfc1035_message_destroy().
* @param buf {const char*} the data of the DNS reply
* @param sz {size_t} the buf's size
* @return {ACL_RFC1035_MESSAGE*} return the parsing result

View File

@ -898,7 +898,6 @@ ACL_RFC1035_MESSAGE *acl_rfc1035_request_unpack(const char *buf, size_t sz)
}
return msg;
}
/****************************************************************************/
@ -1075,7 +1074,7 @@ size_t acl_rfc1035_build_reply(const ACL_RFC1035_REPLY *reply, char *buf, size_t
for (i = 0; i < reply->ips->argc; i++) {
memset(&rr, 0, sizeof(rr));
snprintf(rr.name, sizeof(rr.name), "%s", reply->hostname);
ACL_SAFE_STRNCPY(rr.name, reply->hostname, sizeof(rr.name));
rr.type = reply->ip_type;
rr.tclass = ACL_RFC1035_CLASS_IN;
rr.ttl = reply->ttl;
@ -1092,7 +1091,7 @@ size_t acl_rfc1035_build_reply(const ACL_RFC1035_REPLY *reply, char *buf, size_t
if (h.nscount) {
memset(&rr, 0, sizeof(rr));
snprintf(rr.name, sizeof(rr.name), "%s", reply->domain_root);
ACL_SAFE_STRNCPY(rr.name, reply->domain_root, sizeof(rr.name));
rr.type = ACL_RFC1035_TYPE_NS;
rr.tclass = ACL_RFC1035_CLASS_IN;
rr.ttl = reply->ttl;
@ -1104,7 +1103,7 @@ size_t acl_rfc1035_build_reply(const ACL_RFC1035_REPLY *reply, char *buf, size_t
if (h.arcount) {
memset(&rr, 0, sizeof(rr));
snprintf(rr.name, sizeof(rr.name), "%s", reply->dns_name);
ACL_SAFE_STRNCPY(rr.name, reply->dns_name, sizeof(rr.name));
rr.type = reply->ip_type;
rr.tclass = ACL_RFC1035_CLASS_IN;
rr.ttl = reply->ttl;

View File

@ -479,11 +479,8 @@ static struct addrinfo *ns_lookup(const char *ip, unsigned short port,
if (ret == -1) {
break;
}
ret = rfc1035_message_unpack(buf, ret, &message);
if (ret <= 0) {
if (message) {
rfc1035_message_destroy(message);
}
message = rfc1035_response_unpack(buf, ret);
if (message == NULL) {
break;
}

View File

@ -10,10 +10,11 @@
#include "common/strops.h"
#include "common/msg.h"
#include "common/argv.h"
#include "rfc1035.h"
#define RFC1035_MAXLABELSZ 63
#define RFC1035_unpack_error 15
#define RFC1035_UNPACK_ERROR 15
#if 0
#define RFC1035_UNPACK_DEBUG msg_error("unpack error at %s:%d", __FILE__,__LINE__)
@ -195,13 +196,13 @@ static int rfc1035_name_unpack(const char *buf, size_t sz, size_t *off,
if (ns <= 0) {
msg_error("%s: ns(%d) <= 0", myname, (int) ns);
return -RFC1035_unpack_error;
return -RFC1035_UNPACK_ERROR;
}
do {
if (*off >= sz) {
msg_error("%s: *off(%d) >= sz(%d)",
myname, (int) *off, (int) sz);
return -RFC1035_unpack_error;
return -RFC1035_UNPACK_ERROR;
}
c = *(buf + (*off));
if (c > 191) {
@ -260,7 +261,7 @@ static int rfc1035_name_unpack(const char *buf, size_t sz, size_t *off,
/* make sure we didn't allow someone to overflow the name buffer */
if (no > (int) ns) {
msg_error("%s: no(%d) > ns(%d)", myname, no, (int) ns);
return -RFC1035_unpack_error;
return -RFC1035_UNPACK_ERROR;
}
return 0;
}
@ -282,7 +283,7 @@ const char *rfc1035_strerror(int errnum)
"not support the requested kind of query." },
{ 5, "Refused: The name server refuses to "
"perform the specified operation." },
{ RFC1035_unpack_error, "The DNS reply message is corrupt or could "
{ RFC1035_UNPACK_ERROR, "The DNS reply message is corrupt or could "
"not be safely parsed." },
{ -1, NULL },
};
@ -345,48 +346,48 @@ int rfc1035_query_compare(const RFC1035_QUERY * a, const RFC1035_QUERY * b)
*
* Returns > 0 (success) or 0 (error)
*/
static int rfc1035_rr_pack(const RFC1035_RR *RR, char *buf, size_t sz)
static int rfc1035_rr_pack(const RFC1035_RR *rr, char *buf, size_t sz)
{
const char *myname = "rfc1035_rr_pack";
unsigned short s;
unsigned int i;
int off = 0, off_saved;
off = rfc1035_name_pack(buf + off, sz, RR->name);
s = htons(RR->type);
off = rfc1035_name_pack(buf + off, sz, rr->name);
s = htons(rr->type);
memcpy(buf + off, &s,sizeof(s));
off += sizeof(s);
s = htons(RR->tclass);
s = htons(rr->tclass);
memcpy(buf + off, &s ,sizeof(s));
off += sizeof(s);
i = htonl(RR->ttl);
i = htonl(rr->ttl);
memcpy(buf + off, &i ,sizeof(i));
off += sizeof(i);
switch (RR->type) {
switch (rr->type) {
case RFC1035_TYPE_PTR:
case RFC1035_TYPE_NS:
case RFC1035_TYPE_CNAME:
case RFC1035_TYPE_TXT:
if (strlen(RR->rdata) > RFC1035_MAXHOSTNAMESZ) {
if (strlen(rr->rdata) > RFC1035_MAXHOSTNAMESZ) {
return 0;
}
off_saved = off;
off += sizeof(s);
off += rfc1035_name_pack(buf + off, sz, RR->rdata);
off += rfc1035_name_pack(buf + off, sz, rr->rdata);
s = off - off_saved - (unsigned short) sizeof(s);
s = htons(s);
memcpy(buf + off_saved, &s ,sizeof(s));
break;
default:
s = htons(RR->rdlength);
s = htons(rr->rdlength);
memcpy(buf + off, &s ,sizeof(s));
off += sizeof(s);
memcpy(buf + off, RR->rdata, RR->rdlength);
off += RR->rdlength;
memcpy(buf + off, rr->rdata, rr->rdlength);
off += rr->rdlength;
break;
}
@ -529,7 +530,7 @@ static int rfc1035_header_unpack(const char *buf, size_t sz, size_t *off,
if (*off != 0) {
msg_error("%s: *off(%d) != 0", myname, (int) *off);
return -RFC1035_unpack_error;
return -RFC1035_UNPACK_ERROR;
}
/*
@ -579,7 +580,7 @@ static int rfc1035_header_unpack(const char *buf, size_t sz, size_t *off,
if (*off != 12) {
msg_error("%s: *off(%d) != 12", myname, (int) *off);
return -RFC1035_unpack_error;
return -RFC1035_UNPACK_ERROR;
}
return 0;
}
@ -724,7 +725,7 @@ static int rfc1035_rr_unpack(const char *buf, size_t sz, size_t *off, RFC1035_RR
if (*off > sz) {
msg_error("%s: *off(%d) > sz(%d)",
myname, (int) *off, (int) sz);
return -RFC1035_unpack_error;
return -RFC1035_UNPACK_ERROR;
}
return 0;
@ -764,45 +765,40 @@ static RFC1035_RR *rfc1035_unpack2rr(const char *buf, size_t sz,
return rr;
}
int rfc1035_message_unpack(const char *buf, size_t sz, RFC1035_MESSAGE **answer)
RFC1035_MESSAGE *rfc1035_response_unpack(const char *buf, size_t sz)
{
int i, nr;
size_t off = 0;
RFC1035_MESSAGE *msg;
errno = 0;
*answer = NULL;
msg = (RFC1035_MESSAGE*) calloc(1, sizeof(*msg));
if (rfc1035_header_unpack(buf + off, sz - off, &off, msg)) {
RFC1035_UNPACK_DEBUG;
rfc1035_set_errno(RFC1035_unpack_error);
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
rfc1035_message_destroy(msg);
*answer = NULL;
return -RFC1035_unpack_error;
return NULL;
}
if (msg->rcode) {
int ret = -((int) msg->rcode);
RFC1035_UNPACK_DEBUG;
rfc1035_set_errno((int) msg->rcode);
rfc1035_message_destroy(msg);
*answer = NULL;
return ret;
return NULL;
}
if (msg->ancount == 0) {
rfc1035_message_destroy(msg);
*answer = NULL;
return 0;
return NULL;
}
if (msg->qdcount != 1) {
/* This can not be an answer to our queries.. */
RFC1035_UNPACK_DEBUG;
rfc1035_set_errno(RFC1035_unpack_error);
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
rfc1035_message_destroy(msg);
return -RFC1035_unpack_error;
return NULL;
}
msg->query = (RFC1035_QUERY*) calloc((int) msg->qdcount,
@ -811,9 +807,9 @@ int rfc1035_message_unpack(const char *buf, size_t sz, RFC1035_MESSAGE **answer)
for (i = 0; i < (int) msg->qdcount; i++) {
if (rfc1035_query_unpack(buf, sz, &off, &msg->query[i])) {
RFC1035_UNPACK_DEBUG;
rfc1035_set_errno(RFC1035_unpack_error);
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
rfc1035_message_destroy(msg);
return -RFC1035_unpack_error;
return NULL;
}
}
@ -826,12 +822,10 @@ int rfc1035_message_unpack(const char *buf, size_t sz, RFC1035_MESSAGE **answer)
*/
RFC1035_UNPACK_DEBUG;
rfc1035_message_destroy(msg);
*answer = NULL;
rfc1035_set_errno(RFC1035_unpack_error);
return -RFC1035_unpack_error;
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
return NULL;
}
if (msg->nscount > 0) {
msg->authority = rfc1035_unpack2rr(buf, sz, &off,
msg->nscount, &nr);
@ -839,9 +833,8 @@ int rfc1035_message_unpack(const char *buf, size_t sz, RFC1035_MESSAGE **answer)
if (msg->authority == NULL) {
RFC1035_UNPACK_DEBUG;
rfc1035_message_destroy(msg);
*answer = NULL;
rfc1035_set_errno(RFC1035_unpack_error);
return -RFC1035_unpack_error;
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
return NULL;
}
}
@ -852,14 +845,57 @@ int rfc1035_message_unpack(const char *buf, size_t sz, RFC1035_MESSAGE **answer)
if (msg->additional == NULL) {
RFC1035_UNPACK_DEBUG;
rfc1035_message_destroy(msg);
*answer = NULL;
rfc1035_set_errno(RFC1035_unpack_error);
return -RFC1035_unpack_error;
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
return NULL;
}
}
*answer = msg;
return (int) msg->ancount;
return msg;
}
RFC1035_MESSAGE *rfc1035_request_unpack(const char *buf, size_t sz)
{
int i;
size_t off = 0;
RFC1035_MESSAGE *msg;
errno = 0;
msg = (RFC1035_MESSAGE*) calloc(1, sizeof(*msg));
if (rfc1035_header_unpack(buf + off, sz - off, &off, msg)) {
RFC1035_UNPACK_DEBUG;
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
rfc1035_message_destroy(msg);
return NULL;
}
if (msg->rcode) {
RFC1035_UNPACK_DEBUG;
rfc1035_set_errno((int) msg->rcode);
rfc1035_message_destroy(msg);
return NULL;
}
if (msg->qdcount != 1) {
/* This can not be an answer to our queries.. */
RFC1035_UNPACK_DEBUG;
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
rfc1035_message_destroy(msg);
return NULL;
}
msg->query = (RFC1035_QUERY*) calloc((int) msg->qdcount,
sizeof(RFC1035_QUERY));
for (i = 0; i < (int) msg->qdcount; i++) {
if (rfc1035_query_unpack(buf, sz, &off, &msg->query[i])) {
RFC1035_UNPACK_DEBUG;
rfc1035_set_errno(RFC1035_UNPACK_ERROR);
rfc1035_message_destroy(msg);
}
}
return msg;
}
/****************************************************************************/
@ -1004,6 +1040,8 @@ static size_t save_addr2rr(int type, const char *src, RFC1035_RR *rr)
}
}
#define SAFE_FREE(x) do { if ((x)) free ((x)); } while(0)
size_t rfc1035_build_reply(const RFC1035_REPLY *reply, char *buf, size_t sz)
{
RFC1035_MESSAGE h;
@ -1011,6 +1049,11 @@ size_t rfc1035_build_reply(const RFC1035_REPLY *reply, char *buf, size_t sz)
size_t offset = 0;
int i;
if (reply->ips == NULL || reply->ips->argc <= 0) {
msg_error("ips null");
return 0;
}
memset(&h, '\0', sizeof(h));
h.id = reply->qid;
h.qr = 1; /* response */
@ -1031,11 +1074,7 @@ size_t rfc1035_build_reply(const RFC1035_REPLY *reply, char *buf, size_t sz)
for (i = 0; i < reply->ips->argc; i++) {
memset(&rr, 0, sizeof(rr));
#ifdef SYS_WIN
_snprintf(rr.name, sizeof(rr.name), "%s", reply->hostname);
#else
snprintf(rr.name, sizeof(rr.name), "%s", reply->hostname);
#endif
SAFE_STRNCPY(rr.name, reply->hostname, sizeof(rr.name));
rr.type = reply->ip_type;
rr.tclass = htons(RFC1035_CLASS_IN);
rr.ttl = reply->ttl;
@ -1047,16 +1086,12 @@ size_t rfc1035_build_reply(const RFC1035_REPLY *reply, char *buf, size_t sz)
}
offset += rfc1035_rr_pack(&rr, buf + offset, sz - offset);
free(rr.rdata);
SAFE_FREE(rr.rdata);
}
if (h.nscount) {
memset(&rr, 0, sizeof(rr));
#ifdef SYS_WIN
_snprintf(rr.name, sizeof(rr.name), "%s", reply->domain_root);
#else
snprintf(rr.name, sizeof(rr.name), "%s", reply->domain_root);
#endif
SAFE_STRNCPY(rr.name, reply->domain_root, sizeof(rr.name));
rr.type = RFC1035_TYPE_NS;
rr.tclass = RFC1035_CLASS_IN;
rr.ttl = reply->ttl;
@ -1067,16 +1102,12 @@ size_t rfc1035_build_reply(const RFC1035_REPLY *reply, char *buf, size_t sz)
rr.rdata = strdup(reply->dns_name);
#endif
offset += rfc1035_rr_pack(&rr, buf + offset, sz - offset);
free(rr.rdata);
SAFE_FREE(rr.rdata);
}
if (h.arcount) {
memset(&rr, 0, sizeof(rr));
#ifdef SYS_WIN
_snprintf(rr.name, sizeof(rr.name), "%s", reply->dns_name);
#else
snprintf(rr.name, sizeof(rr.name), "%s", reply->dns_name);
#endif
SAFE_STRNCPY(rr.name, reply->dns_name, sizeof(rr.name));
rr.type = reply->ip_type;
rr.tclass = RFC1035_CLASS_IN;
rr.ttl = reply->ttl;
@ -1088,7 +1119,7 @@ size_t rfc1035_build_reply(const RFC1035_REPLY *reply, char *buf, size_t sz)
}
offset += rfc1035_rr_pack(&rr, buf + offset, sz - offset);
free(rr.rdata);
SAFE_FREE(rr.rdata);
}
return offset;

View File

@ -5,12 +5,12 @@
extern "C" {
#endif
#include "common/argv.h"
#ifdef ACL_UNIX
#include <netinet/in.h>
#endif
struct ARGV;
/* RFC1035 - DNS */
#define RFC1035_MAXHOSTNAMESZ 256
@ -151,16 +151,24 @@ void rfc1035_set_query_id(char *buf, size_t sz, unsigned short qid);
int rfc1035_query_compare(const RFC1035_QUERY *a, const RFC1035_QUERY *b);
/**
* Takes the contents of a DNS reply and fills in an array
* Takes the contents of a DNS request and fills in an array
* of resource record structures. The records array is allocated
* here, and should be freed by calling RFC1035RRDestroy().
* here, and should be freed by calling rfc1035_messager_destroy().
* @param buf {const char*} the data of the DNS reply
* @param sz {size_t} the buf's size
* @param answer {RFC1035_MESSAGE*} store the parsing result
* @return {int} Returns number of records unpacked, zero if DNS reply
* indicates zero answers, or an error number < 0.
* @return {RFC1035_MESSAGE*} return the parsing result
*/
int rfc1035_message_unpack(const char *buf, size_t sz, RFC1035_MESSAGE **answer);
RFC1035_MESSAGE *rfc1035_request_unpack(const char *buf, size_t sz);
/**
* Takes the contents of a DNS reply and fills in an array
* of resource record structures. The records array is allocated
* here, and should be freed by calling rfc1035_messager_destroy().
* @param buf {const char*} the data of the DNS reply
* @param sz {size_t} the buf's size
* @return {RFC1035_MESSAGE*} return the parsing result
*/
RFC1035_MESSAGE *rfc1035_response_unpack(const char *buf, size_t sz);
/**
* destroy and free the message created by RFC1035MessageUnpack()

View File

@ -5,7 +5,6 @@
#include <thread>
#include "lib_acl.h"
#include "acl_cpp/lib_acl.hpp"
#include "fiber/libfiber.h"
#include "fiber/go_fiber.hpp"
static char __dns_ip[256];
@ -127,7 +126,7 @@ int main(int argc, char *argv[])
}
acl_msg_stdout_enable(1);
acl_fiber_msg_stdout_enable(1);
acl::fiber::stdout_open(true);
struct timeval begin;
gettimeofday(&begin, NULL);

View File

@ -0,0 +1,3 @@
include ../Makefile_cpp.in
PROG = dns_server
CFLAGS += -std=c++11 -I../../c/src/dns -I../../c/src/common

View File

@ -0,0 +1,149 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "acl_cpp/lib_acl.hpp"
#include "fiber/go_fiber.hpp"
#include "rfc1035.h"
#include "argv.h"
static RFC1035_MESSAGE* parse_request(const char* data, size_t len)
{
RFC1035_MESSAGE *request;
request = rfc1035_request_unpack(data, len);
if (request == NULL) {
logger_error("unpack request error, size=%d", (int) len);
return NULL;
}
RFC1035_QUERY *query = request->query;
if (query == NULL || query->name[0] == 0) {
rfc1035_message_destroy(request);
return NULL;
}
#if 0
printf(">>>ask name=%s, query type=%d, class=%d\n",
query->name, query->qtype, query->qclass);
#endif
switch (query->qtype) {
case RFC1035_TYPE_A:
break;
case RFC1035_TYPE_AAAA:
break;
default:
logger_error("unsport qtype=%d, qclass=%d",
query->qtype, query->qclass);
rfc1035_message_destroy(request);
return NULL;
}
return request;
}
static size_t build_reply(const RFC1035_MESSAGE* request, char* buf, size_t size)
{
ARGV* ips = argv_alloc(5);
argv_add(ips, "192.168.1.1", NULL);
argv_add(ips, "192.168.1.2", NULL);
argv_add(ips, "192.168.1.3", NULL);
RFC1035_REPLY reply;
reply.hostname = request->query->name;
reply.domain_root = NULL;
reply.dns_name = NULL;
reply.dns_ip = NULL;
reply.ips = ips;
reply.ip_type = RFC1035_TYPE_A;
reply.ttl = 600;
reply.qid = request->id;
size_t n = rfc1035_build_reply(&reply, buf, size);
argv_free(ips);
return n;
}
static void handle_pkt(acl::socket_stream& stream, const char* data, size_t len)
{
RFC1035_MESSAGE* request = parse_request(data, len);
if (request == NULL) {
logger_error("parse request error");
return;
}
char buf[1024];
size_t ret = build_reply(request, buf, sizeof(buf));
rfc1035_message_destroy(request);
if (!ret) {
logger_error("build reply error");
return;
}
if (stream.write(buf, ret) == -1) {
logger_error("write error");
}
}
static void dns_server(acl::socket_stream& stream)
{
char buf[1024];
int ret;
while (true) {
ret = stream.read(buf, sizeof(buf), false);
if (ret == -1) {
continue;
}
buf[ret] = 0;
handle_pkt(stream, buf, ret);
}
}
static void usage(const char *procname)
{
printf("usage: %s -h [help]\r\n"
" -s addr\r\n"
, procname);
}
int main(int argc, char *argv[])
{
int ch;
acl::string addr("127.0.0.1:53");
while ((ch = getopt(argc, argv, "hs:")) > 0) {
switch (ch) {
case 'h':
usage(argv[0]);
return 0;
case 's':
addr = optarg;
break;
default:
break;
}
}
if (addr.empty()) {
usage(argv[0]);
return 0;
}
acl::log::stdout_open(true);
acl::fiber::stdout_open(true);
acl::socket_stream stream;
if (!stream.bind_udp(addr)) {
printf("bind %s error %s\r\n", addr.c_str(), acl::last_serror());
return 1;
}
go[&] {
dns_server(stream);
};
acl::fiber::schedule();
return 0;
}