Browse Source

[Minor] Merge fake DNS records

tags/2.0
Vsevolod Stakhov 4 years ago
parent
commit
66d0f1335c
1 changed files with 185 additions and 167 deletions
  1. 185
    167
      src/libserver/dns.c

+ 185
- 167
src/libserver/dns.c View File

@@ -326,208 +326,222 @@ rspamd_dns_resolv_conf_on_server (struct rdns_resolver *resolver,
}

static void
rspamd_dns_resolver_config_ucl (struct rspamd_config *cfg,
struct rspamd_dns_resolver *dns_resolver,
const ucl_object_t *dns_section)
rspamd_process_fake_reply (struct rspamd_config *cfg,
struct rspamd_dns_resolver *dns_resolver,
const ucl_object_t *cur_arr)
{
const ucl_object_t *fake_replies, *cur;
const ucl_object_t *cur;
ucl_object_iter_t it;

/* Process fake replies */
fake_replies = ucl_object_lookup_any (dns_section, "fake_records",
"fake_replies", NULL);
it = ucl_object_iterate_new (cur_arr);

if (fake_replies && ucl_object_type (fake_replies) == UCL_ARRAY) {
it = ucl_object_iterate_new (fake_replies);
while ((cur = ucl_object_iterate_safe (it, true))) {
const ucl_object_t *type_obj, *name_obj, *code_obj, *replies_obj;
enum rdns_request_type rtype = RDNS_REQUEST_A;
enum dns_rcode rcode = RDNS_RC_NOERROR;
struct rdns_reply_entry *replies = NULL;
const gchar *name = NULL;

if (ucl_object_type (cur) != UCL_OBJECT) {
continue;
}

name_obj = ucl_object_lookup (cur, "name");
if (name_obj == NULL ||
(name = ucl_object_tostring (name_obj)) == NULL) {
msg_err_config ("no name for fake dns reply");
continue;
}

while ((cur = ucl_object_iterate_safe (it, true))) {
const ucl_object_t *type_obj, *name_obj, *code_obj, *replies_obj;
enum rdns_request_type rtype = RDNS_REQUEST_A;
enum dns_rcode rcode = RDNS_RC_NOERROR;
struct rdns_reply_entry *replies = NULL;
const gchar *name = NULL;
type_obj = ucl_object_lookup (cur, "type");
if (type_obj) {
rtype = rdns_type_fromstr (ucl_object_tostring (type_obj));

if (ucl_object_type (cur) != UCL_OBJECT) {
if (rtype == RDNS_REQUEST_INVALID) {
msg_err_config ("invalid type for %s: %s", name,
ucl_object_tostring (type_obj));
continue;
}
}

name_obj = ucl_object_lookup (cur, "name");
if (name_obj == NULL ||
(name = ucl_object_tostring (name_obj)) == NULL) {
msg_err_config ("no name for fake dns reply");
code_obj = ucl_object_lookup_any (cur, "code", "rcode", NULL);
if (code_obj) {
rcode = rdns_rcode_fromstr (ucl_object_tostring (code_obj));

if (rcode == RDNS_RC_INVALID) {
msg_err_config ("invalid rcode for %s: %s", name,
ucl_object_tostring (code_obj));
continue;
}
}

type_obj = ucl_object_lookup (cur, "type");
if (type_obj) {
rtype = rdns_type_fromstr (ucl_object_tostring (type_obj));
if (rcode == RDNS_RC_NOERROR) {
/* We want replies to be set for this rcode */
replies_obj = ucl_object_lookup (cur, "replies");

if (rtype == RDNS_REQUEST_INVALID) {
msg_err_config ("invalid type for %s: %s", name,
ucl_object_tostring (type_obj));
continue;
}
if (replies_obj == NULL || ucl_object_type (replies_obj) != UCL_ARRAY) {
msg_err_config ("invalid replies for fake DNS record %s", name);
continue;
}

code_obj = ucl_object_lookup_any (cur, "code", "rcode", NULL);
if (code_obj) {
rcode = rdns_rcode_fromstr (ucl_object_tostring (code_obj));
ucl_object_iter_t rep_it;
const ucl_object_t *rep_obj;

if (rcode == RDNS_RC_INVALID) {
msg_err_config ("invalid rcode for %s: %s", name,
ucl_object_tostring (code_obj));
continue;
}
}
rep_it = ucl_object_iterate_new (replies_obj);

if (rcode == RDNS_RC_NOERROR) {
/* We want replies to be set for this rcode */
replies_obj = ucl_object_lookup (cur, "replies");
while ((rep_obj = ucl_object_iterate_safe (rep_it, true))) {
const gchar *str_rep = ucl_object_tostring (rep_obj);
struct rdns_reply_entry *rep;
gchar **svec;

if (replies_obj == NULL || ucl_object_type (replies_obj) != UCL_ARRAY) {
msg_err_config ("invalid replies for fake DNS record %s", name);
if (str_rep == NULL) {
msg_err_config ("invalid reply element for fake DNS record %s",
name);
continue;
}

ucl_object_iter_t rep_it;
const ucl_object_t *rep_obj;

rep_it = ucl_object_iterate_new (replies_obj);
rep = calloc (1, sizeof (*rep));
g_assert (rep != NULL);

while ((rep_obj = ucl_object_iterate_safe (rep_it, true))) {
const gchar *str_rep = ucl_object_tostring (rep_obj);
struct rdns_reply_entry *rep;
gchar **svec;
rep->type = rtype;
rep->ttl = 0;

if (str_rep == NULL) {
msg_err_config ("invalid reply element for fake DNS record %s",
name);
continue;
switch (rtype) {
case RDNS_REQUEST_A:
if (inet_pton (AF_INET, str_rep, &rep->content.a.addr) != 1) {
msg_err_config ("invalid A reply element for fake "
"DNS record %s: %s",
name, str_rep);
free (rep);
}

rep = calloc (1, sizeof (*rep));
g_assert (rep != NULL);

rep->type = rtype;
rep->ttl = 0;

switch (rtype) {
case RDNS_REQUEST_A:
if (inet_pton (AF_INET, str_rep, &rep->content.a.addr) != 1) {
msg_err_config ("invalid A reply element for fake "
"DNS record %s: %s",
name, str_rep);
free (rep);
}
else {
DL_APPEND (replies, rep);
}
break;
case RDNS_REQUEST_NS:
rep->content.ns.name = strdup (str_rep);
else {
DL_APPEND (replies, rep);
break;
case RDNS_REQUEST_PTR:
rep->content.ptr.name = strdup (str_rep);
}
break;
case RDNS_REQUEST_NS:
rep->content.ns.name = strdup (str_rep);
DL_APPEND (replies, rep);
break;
case RDNS_REQUEST_PTR:
rep->content.ptr.name = strdup (str_rep);
DL_APPEND (replies, rep);
break;
case RDNS_REQUEST_MX:
svec = g_strsplit_set (str_rep, " :", -1);

if (svec && svec[0] && svec[1]) {
rep->content.mx.priority = strtoul (svec[0], NULL, 10);
rep->content.mx.name = strdup (svec[1]);
DL_APPEND (replies, rep);
break;
case RDNS_REQUEST_MX:
svec = g_strsplit_set (str_rep, " :", -1);

if (svec && svec[0] && svec[1]) {
rep->content.mx.priority = strtoul (svec[0], NULL, 10);
rep->content.mx.name = strdup (svec[1]);
DL_APPEND (replies, rep);
}
else {
msg_err_config ("invalid MX reply element for fake "
"DNS record %s: %s",
name, str_rep);
free (rep);
}

g_strfreev (svec);
break;
case RDNS_REQUEST_TXT:
rep->content.txt.data = strdup (str_rep);
}
else {
msg_err_config ("invalid MX reply element for fake "
"DNS record %s: %s",
name, str_rep);
free (rep);
}

g_strfreev (svec);
break;
case RDNS_REQUEST_TXT:
rep->content.txt.data = strdup (str_rep);
DL_APPEND (replies, rep);
break;
case RDNS_REQUEST_SOA:
svec = g_strsplit_set (str_rep, " :", -1);

/* 7 elements */
if (svec && svec[0] && svec[1] && svec[2] &&
svec[3] && svec[4] && svec[5] && svec[6]) {
rep->content.soa.mname = strdup (svec[0]);
rep->content.soa.admin = strdup (svec[1]);
rep->content.soa.serial = strtoul (svec[2], NULL, 10);
rep->content.soa.refresh = strtol (svec[3], NULL, 10);
rep->content.soa.retry = strtol (svec[4], NULL, 10);
rep->content.soa.expire = strtol (svec[5], NULL, 10);
rep->content.soa.minimum = strtoul (svec[6], NULL, 10);
DL_APPEND (replies, rep);
break;
case RDNS_REQUEST_SOA:
svec = g_strsplit_set (str_rep, " :", -1);

/* 7 elements */
if (svec && svec[0] && svec[1] && svec[2] &&
svec[3] && svec[4] && svec[5] && svec[6]) {
rep->content.soa.mname = strdup (svec[0]);
rep->content.soa.admin = strdup (svec[1]);
rep->content.soa.serial = strtoul (svec[2], NULL, 10);
rep->content.soa.refresh = strtol (svec[3], NULL, 10);
rep->content.soa.retry = strtol (svec[4], NULL, 10);
rep->content.soa.expire = strtol (svec[5], NULL, 10);
rep->content.soa.minimum = strtoul (svec[6], NULL, 10);
DL_APPEND (replies, rep);
}
else {
msg_err_config ("invalid MX reply element for fake "
"DNS record %s: %s",
name, str_rep);
free (rep);
}

g_strfreev (svec);
break;
case RDNS_REQUEST_AAAA:
if (inet_pton (AF_INET6, str_rep, &rep->content.aaa.addr) != 1) {
msg_err_config ("invalid AAAA reply element for fake "
"DNS record %s: %s",
name, str_rep);
free (rep);
}
else {
DL_APPEND (replies, rep);
}
case RDNS_REQUEST_SRV:
default:
msg_err_config ("invalid or unsupported reply element "
"for fake DNS record %s(%s): %s",
name, rdns_str_from_type (rtype), str_rep);
}
else {
msg_err_config ("invalid MX reply element for fake "
"DNS record %s: %s",
name, str_rep);
free (rep);
}

g_strfreev (svec);
break;
case RDNS_REQUEST_AAAA:
if (inet_pton (AF_INET6, str_rep, &rep->content.aaa.addr) != 1) {
msg_err_config ("invalid AAAA reply element for fake "
"DNS record %s: %s",
name, str_rep);
free (rep);
break;
}
else {
DL_APPEND (replies, rep);
}
case RDNS_REQUEST_SRV:
default:
msg_err_config ("invalid or unsupported reply element "
"for fake DNS record %s(%s): %s",
name, rdns_str_from_type (rtype), str_rep);
free (rep);
break;
}
}

ucl_object_iterate_free (rep_it);
ucl_object_iterate_free (rep_it);

if (replies) {
struct rdns_reply_entry *tmp_entry;
guint i = 0;
DL_COUNT (replies, tmp_entry, i);
if (replies) {
struct rdns_reply_entry *tmp_entry;
guint i = 0;
DL_COUNT (replies, tmp_entry, i);

msg_info_config ("added fake record: %s(%s); %d replies", name,
rdns_str_from_type (rtype), i);
rdns_resolver_set_fake_reply (dns_resolver->r,
name, rtype, rcode, replies);
}
else {
msg_warn_config ("record %s has no replies, not adding",
name);
}
msg_info_config ("added fake record: %s(%s); %d replies", name,
rdns_str_from_type (rtype), i);
rdns_resolver_set_fake_reply (dns_resolver->r,
name, rtype, rcode, replies);
}
else {
/* This entry returns some non valid code, no replies are possible */
replies_obj = ucl_object_lookup (cur, "replies");
if (replies_obj) {
msg_warn_config ("replies are set for non-successful return "
"code for %s(%s), they will be ignored", name, rdns_str_from_type (rtype));
}
msg_warn_config ("record %s has no replies, not adding",
name);
}
}
else {
/* This entry returns some non valid code, no replies are possible */
replies_obj = ucl_object_lookup (cur, "replies");

rdns_resolver_set_fake_reply (dns_resolver->r,
name, rtype, rcode, NULL);
if (replies_obj) {
msg_warn_config ("replies are set for non-successful return "
"code for %s(%s), they will be ignored", name, rdns_str_from_type (rtype));
}

rdns_resolver_set_fake_reply (dns_resolver->r,
name, rtype, rcode, NULL);
}
}

ucl_object_iterate_free (it);
ucl_object_iterate_free (it);
}

static void
rspamd_dns_resolver_config_ucl (struct rspamd_config *cfg,
struct rspamd_dns_resolver *dns_resolver,
const ucl_object_t *dns_section)
{
const ucl_object_t *fake_replies;

/* Process fake replies */
fake_replies = ucl_object_lookup_any (dns_section, "fake_records",
"fake_replies", NULL);

if (fake_replies && ucl_object_type (fake_replies) == UCL_ARRAY) {
const ucl_object_t *cur_arr;

DL_FOREACH (fake_replies, cur_arr) {
rspamd_process_fake_reply (cfg, dns_resolver, cur_arr);
}
}
}

@@ -604,15 +618,19 @@ rspamd_dns_resolver_init (rspamd_logger_t *logger,

if (cfg->rcl_obj) {
/* Configure additional options */
const ucl_object_t *opts_section, *dns_section;
const ucl_object_t *opts_section, *dns_section, *tmp;

opts_section = ucl_object_lookup (cfg->rcl_obj, "options");

if (opts_section) {
dns_section = ucl_object_lookup (opts_section, "dns");
/* TODO: implement a more simple merge logic */
DL_FOREACH (opts_section, tmp) {
dns_section = ucl_object_lookup (opts_section, "dns");

if (dns_section) {
rspamd_dns_resolver_config_ucl (cfg, dns_resolver, dns_section);
if (dns_section) {
rspamd_dns_resolver_config_ucl (cfg, dns_resolver,
dns_section);
}
}
}
}

Loading…
Cancel
Save