From 4a943fadfdcff33eda568d67efacb982e61f92bf Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Wed, 20 Mar 2019 13:48:56 +0000 Subject: [PATCH] Add keys logging --- contrib/debian/changelog | 2 +- rbldnsd.c | 5 +-- rbldnsd.h | 9 +++-- rbldnsd_aclkey.c | 21 ++++++++--- rbldnsd_packet.c | 76 +++++++++++++++++++++++----------------- 5 files changed, 70 insertions(+), 43 deletions(-) diff --git a/contrib/debian/changelog b/contrib/debian/changelog index ac6fb41..8ef3fe1 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -11,7 +11,7 @@ rbldnsd (0.998-1) UNRELEASED; urgency=low rbldnsd (0.997a-1) unstable; urgency=low - * change the way how `make dist' behaves + * change the way how `make dist' behaves (no need for a temporary subdir anymore) * fixed sed expression to determine version number, needed for *BSD diff --git a/rbldnsd.c b/rbldnsd.c index 8ba54ab..9166f57 100644 --- a/rbldnsd.c +++ b/rbldnsd.c @@ -1187,6 +1187,7 @@ static struct dnspacket pkt; static void request(int fd) { int q, r; socklen_t salen = sizeof(peer_sa); + struct dnsqinfo qi; q = recvfrom(fd, (void*)pkt.p_buf, sizeof(pkt.p_buf), 0, (struct sockaddr *)&peer_sa, &salen); @@ -1194,11 +1195,11 @@ static void request(int fd) { return; pkt.p_peerlen = salen; - r = replypacket(&pkt, q, zonelist); + r = replypacket(&pkt, q, zonelist, &qi); if (!r) return; if (flog) - logreply(&pkt, flog, flushlog); + logreply(&pkt, flog, flushlog, &qi); /* finally, send a reply */ while(sendto(fd, (void*)pkt.p_buf, r, 0, diff --git a/rbldnsd.h b/rbldnsd.h index 9fb2837..f88a722 100644 --- a/rbldnsd.h +++ b/rbldnsd.h @@ -67,6 +67,7 @@ struct dnsqinfo { /* qi */ int qi_ip6valid; /* true if qi_ip6 is valid */ ip4addr_t qi_ip4; /* parsed IP4 address */ ip6oct_t qi_ip6[IP6ADDR_FULL]; /* parsed IP6 address */ + void *qi_additional; /* additional pointer depending on tflag */ }; #define PACK32(b,n) ((b)[0]=(n)>>24,(b)[1]=(n)>>16,(b)[2]=(n)>>8,(b)[3]=(n)) @@ -125,6 +126,9 @@ ds_dumpfn_t(const struct dataset *ds, const unsigned char *odn, FILE *f); #define NSQUERY_EMPTY 0x040000u #define NSQUERY_ALWAYS 0x080000u +/* special case for keyed ACL */ +#define NSQUERY_KEY 0x0100000u + /* result flags from dataset queryfn */ #define NSQUERY_FOUND 0x01 #define NSQUERY_ADDPEER 0x02 @@ -289,14 +293,15 @@ int update_zone_ns(struct zone *zone, const struct dsns *dsns, unsigned ttl, const struct zone *zonelist); /* parse query and construct a reply to it, return len of answer or 0 */ -int replypacket(struct dnspacket *p, unsigned qlen, struct zone *zone); +int replypacket(struct dnspacket *p, unsigned qlen, struct zone *zone, + struct dnsqinfo *qi); const struct zone * findqzone(const struct zone *zonelist, unsigned dnlen, unsigned dnlab, unsigned char *const *const dnlptr, struct dnsqinfo *qi); /* log a reply */ -void logreply(const struct dnspacket *pkt, FILE *flog, int flushlog); +void logreply(const struct dnspacket *pkt, FILE *flog, int flushlog, const struct dnsqinfo *qi); /* details of DNS packet structure are in rbldnsd_packet.c */ diff --git a/rbldnsd_aclkey.c b/rbldnsd_aclkey.c index b4387ab..ab897c7 100644 --- a/rbldnsd_aclkey.c +++ b/rbldnsd_aclkey.c @@ -192,6 +192,13 @@ ds_aclkey_line(struct dataset *ds, char *s, struct dsctx *dsc) { key.ldn = key_storage; key.len = tail - s; + if (key.len > DNS_MAXLABEL) { + dslog(LOG_ERR, dsc, "cannot insert value %s to acl keys: too long (> %d chars)", + key.ldn, DNS_MAXLABEL); + + return 0; + } + k = kh_put(acl_key_hash, dsd->auth_keys, key, &rrl); switch(rrl) { @@ -222,6 +229,7 @@ int ds_aclkey_query(const struct dataset *ds, struct dnsqinfo *qi, const char *rr; khiter_t k; struct acl_key key; + int add_flags = 0; if (qi->qi_dnlab <= 1) { rr = ds->ds_dsd->def_rr; @@ -250,15 +258,18 @@ int ds_aclkey_query(const struct dataset *ds, struct dnsqinfo *qi, /* Also modify qi */ qi->qi_dnlab --; qi->qi_dnlen0 -= key.len + 1; + add_flags |= NSQUERY_KEY; + /* Zero terminated when parsing */ + qi->qi_additional = (void *)(kh_key(ds->ds_dsd->auth_keys, k).ldn); } } switch((unsigned long)rr) { case 0: return 0; - case RR_IGNORE: return NSQUERY_IGNORE; - case RR_REFUSE: return NSQUERY_REFUSE; - case RR_EMPTY: return NSQUERY_EMPTY; - case RR_PASS: return 0; + case RR_IGNORE: return add_flags|NSQUERY_IGNORE; + case RR_REFUSE: return add_flags|NSQUERY_REFUSE; + case RR_EMPTY: return add_flags|NSQUERY_EMPTY; + case RR_PASS: return add_flags; } /* Substitute zone value and handle it further in check_query_overwrites */ @@ -267,7 +278,7 @@ int ds_aclkey_query(const struct dataset *ds, struct dnsqinfo *qi, pkt->p_substds = ds; } - return NSQUERY_ALWAYS; + return add_flags|NSQUERY_ALWAYS; } /*definedstype(acl, DSTF_SPECIAL, "Access Control List dataset");*/ diff --git a/rbldnsd_packet.c b/rbldnsd_packet.c index 50d3fa2..81096ca 100644 --- a/rbldnsd_packet.c +++ b/rbldnsd_packet.c @@ -275,10 +275,9 @@ findqzone(const struct zone *zone, #endif /* construct reply to a query. */ -int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone) { +int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone, struct dnsqinfo *qi) { struct dnsquery qry; /* query structure */ - struct dnsqinfo qi; /* query info structure */ unsigned char *h = pkt->p_buf; /* packet's header */ const struct dslist *dsl; int found; @@ -336,30 +335,30 @@ int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone) { refuse(DNS_R_REFUSED); } switch(qry.q_type) { - case DNS_T_ANY: qi.qi_tflag = NSQUERY_ANY; break; - case DNS_T_A: qi.qi_tflag = NSQUERY_A; break; - case DNS_T_TXT: qi.qi_tflag = NSQUERY_TXT; break; - case DNS_T_NS: qi.qi_tflag = NSQUERY_NS; break; - case DNS_T_SOA: qi.qi_tflag = NSQUERY_SOA; break; - case DNS_T_MX: qi.qi_tflag = NSQUERY_MX; break; + case DNS_T_ANY: qi->qi_tflag = NSQUERY_ANY; break; + case DNS_T_A: qi->qi_tflag = NSQUERY_A; break; + case DNS_T_TXT: qi->qi_tflag = NSQUERY_TXT; break; + case DNS_T_NS: qi->qi_tflag = NSQUERY_NS; break; + case DNS_T_SOA: qi->qi_tflag = NSQUERY_SOA; break; + case DNS_T_MX: qi->qi_tflag = NSQUERY_MX; break; default: if (qry.q_type >= DNS_T_TSIG) refuse(DNS_R_NOTIMPL); - qi.qi_tflag = NSQUERY_OTHER; + qi->qi_tflag = NSQUERY_OTHER; } - qi.qi_tflag |= found; + qi->qi_tflag |= found; h[p_f2] = DNS_R_NOERROR; /* find matching zone */ zone = (struct zone*) - findqzone(zone, qry.q_dnlen, qry.q_dnlab, qry.q_lptr, &qi); + findqzone(zone, qry.q_dnlen, qry.q_dnlab, qry.q_lptr, qi); if (!zone) /* not authoritative */ refuse(DNS_R_REFUSED); /* check global ACL key, we can do it merely after zone data has been parsed */ if (g_dsaclkey && g_dsaclkey->ds_stamp) { - found = ds_aclkey_query(g_dsaclkey, &qi, pkt); + found = ds_aclkey_query(g_dsaclkey, qi, pkt); if (found & NSQUERY_IGNORE) { do_stats(gstats.q_dropped += 1; gstats.b_in += qlen); return 0; @@ -371,16 +370,16 @@ int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone) { do_stats(zone->z_stats.b_in += qlen); if (zone->z_dsacl && zone->z_dsacl->ds_stamp) { - qi.qi_tflag |= ds_acl_query(zone->z_dsacl, pkt); - if (qi.qi_tflag & NSQUERY_IGNORE) { + qi->qi_tflag |= ds_acl_query(zone->z_dsacl, pkt); + if (qi->qi_tflag & NSQUERY_IGNORE) { do_stats(gstats.q_err += 1); return 0; } } if (zone->z_dsaclkey && zone->z_dsaclkey->ds_stamp) { - qi.qi_tflag |= ds_aclkey_query(zone->z_dsaclkey, &qi, pkt); - if (qi.qi_tflag & NSQUERY_IGNORE) { + qi->qi_tflag |= ds_aclkey_query(zone->z_dsaclkey, qi, pkt); + if (qi->qi_tflag & NSQUERY_IGNORE) { do_stats(gstats.q_dropped += 1); return 0; } @@ -389,23 +388,23 @@ int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone) { if (!zone->z_stamp) /* do not answer if not loaded */ refuse(DNS_R_SERVFAIL); - if (qi.qi_tflag & NSQUERY_REFUSE) + if (qi->qi_tflag & NSQUERY_REFUSE) refuse(DNS_R_REFUSED); - if ((found = call_hook(query_access, (pkt->p_peer, zone, &qi)))) { + if ((found = call_hook(query_access, (pkt->p_peer, zone, qi)))) { if (found < 0) return 0; refuse(DNS_R_REFUSED); } - if (qi.qi_dnlab == 0) { /* query to base zone: SOA and NS */ + if (qi->qi_dnlab == 0) { /* query to base zone: SOA and NS */ found = NSQUERY_FOUND; /* NS and SOA with auth=0 will only touch answer section */ - if ((qi.qi_tflag & NSQUERY_SOA) && !addrr_soa(pkt, zone, 0)) + if ((qi->qi_tflag & NSQUERY_SOA) && !addrr_soa(pkt, zone, 0)) found = 0; else - if ((qi.qi_tflag & NSQUERY_NS) && !addrr_ns(pkt, zone, 0)) + if ((qi->qi_tflag & NSQUERY_NS) && !addrr_ns(pkt, zone, 0)) found = 0; if (!found) { pkt->p_cur = pkt->p_sans; @@ -419,11 +418,11 @@ int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone) { /* search the datasets */ for(dsl = zone->z_dsl; dsl; dsl = dsl->dsl_next) - found |= dsl->dsl_queryfn(dsl->dsl_ds, &qi, pkt); + found |= dsl->dsl_queryfn(dsl->dsl_ds, qi, pkt); if (found & NSQUERY_ADDPEER) { #ifdef NO_IPv6 - addrr_a_txt(pkt, qi.qi_tflag, pkt->p_substrr, + addrr_a_txt(pkt, qi->qi_tflag, pkt->p_substrr, inet_ntoa(((struct sockaddr_in*)pkt->p_peer)->sin_addr), pkt->p_substds); #else @@ -431,7 +430,7 @@ int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone) { if (getnameinfo(pkt->p_peer, pkt->p_peerlen, subst, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) subst[0] = '\0'; - addrr_a_txt(pkt, qi.qi_tflag, pkt->p_substrr, subst, pkt->p_substds); + addrr_a_txt(pkt, qi->qi_tflag, pkt->p_substrr, subst, pkt->p_substds); #endif } @@ -448,12 +447,12 @@ int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone) { addrr_soa(pkt, zone, 1); /* add SOA if any to AUTHORITY */ } else if (zone->z_nns && - /* (!(qi.qi_tflag & NSQUERY_NS) || qi.qi_dnlab) && */ + /* (!(qi->qi_tflag & NSQUERY_NS) || qi->qi_dnlab) && */ !lazy) addrr_ns(pkt, zone, 1); /* add nameserver records to positive reply */ do_stats(zone->z_stats.q_ok += 1); } - (void)call_hook(query_result, (pkt->p_peer, zone, &qi, found)); + (void)call_hook(query_result, (pkt->p_peer, zone, qi, found)); if (rlen() > DNS_MAXPACKET) { /* add OPT record for long replies */ /* as per parsequery(), we always have 11 bytes for minimal OPT record at * the end of our reply packet, OR rlen() does not exceed DNS_MAXPACKET */ @@ -993,8 +992,8 @@ static int version_req(struct dnspacket *pkt, const struct dnsquery *qry) { return 1; } -void logreply(const struct dnspacket *pkt, FILE *flog, int flushlog) { - char cbuf[DNS_MAXDOMAIN + IPSIZE + 50]; +void logreply(const struct dnspacket *pkt, FILE *flog, int flushlog, const struct dnsqinfo *qi) { + char cbuf[DNS_MAXDOMAIN + IPSIZE + 51 + DNS_MAXLABEL]; char *cp = cbuf; const unsigned char *const q = pkt->p_sans - 4; @@ -1012,11 +1011,22 @@ void logreply(const struct dnspacket *pkt, FILE *flog, int flushlog) { #endif *cp++ = ' '; cp += dns_dntop(pkt->p_buf + p_hdrsize, cp, DNS_MAXDOMAIN); - cp += sprintf(cp, " %s %s: %s/%u/%d\n", - dns_typename(((unsigned)q[0]<<8)|q[1]), - dns_classname(((unsigned)q[2]<<8)|q[3]), - dns_rcodename(pkt->p_buf[p_f2] & pf2_rcode), - pkt->p_buf[p_ancnt2], (int)(pkt->p_cur - pkt->p_buf)); + cp += sprintf(cp, " %s %s: %s/%u/%d", + dns_typename(((unsigned) q[0] << 8) | q[1]), + dns_classname(((unsigned) q[2] << 8) | q[3]), + dns_rcodename(pkt->p_buf[p_f2] & pf2_rcode), + pkt->p_buf[p_ancnt2], (int) (pkt->p_cur - pkt->p_buf)); + + if (qi->qi_tflag & NSQUERY_KEY && qi->qi_additional) { + int len = strlen(qi->qi_additional); + + *cp++ = ' '; + memcpy(cp, qi->qi_additional, len); + cp += len; + } + + *cp++ = '\n'; + if (flushlog) write(fileno(flog), cbuf, cp - cbuf); else