/*! \brief Check if query fits the template requirements. */ static int template_match(int state, synth_template_t *tpl, knot_pkt_t *pkt, struct query_data *qdata) { /* Parse address from query name. */ char addr_str[SOCKADDR_STRLEN] = { '\0' }; int ret = addr_parse(qdata, tpl, addr_str); if (ret != KNOT_EOK) { return state; /* Can't identify addr in QNAME, not applicable. */ } /* Match against template netblock. */ struct sockaddr_storage query_addr = { '\0' }; int provided_af = tpl->subnet.ss.ss_family; ret = sockaddr_set(&query_addr, provided_af, addr_str, 0); if (ret == KNOT_EOK) { ret = netblock_match(&tpl->subnet, &query_addr); } if (ret != 0) { return state; /* Out of our netblock, not applicable. */ } /* Check if the request is for an available query type. */ uint16_t qtype = knot_pkt_qtype(qdata->query); switch (tpl->type) { case SYNTH_FORWARD: if (!query_satisfied_by_family(qtype, provided_af)) { qdata->rcode = KNOT_RCODE_NOERROR; return NODATA; } break; case SYNTH_REVERSE: if (qtype != KNOT_RRTYPE_PTR && qtype != KNOT_RRTYPE_ANY) { qdata->rcode = KNOT_RCODE_NOERROR; return NODATA; } break; default: break; } /* Synthetise record from template. */ knot_rrset_t *rr = synth_rr(addr_str, tpl, pkt, qdata); if (rr == NULL) { qdata->rcode = KNOT_RCODE_SERVFAIL; return ERROR; } /* Insert synthetic response into packet. */ if (knot_pkt_put(pkt, 0, rr, KNOT_PF_FREE) != KNOT_EOK) { return ERROR; } /* Authoritative response. */ knot_wire_set_aa(pkt->wire); return HIT; }
static int rosedb_synth(knot_pkt_t *pkt, const knot_dname_t *key, struct iter *it, struct query_data *qdata) { struct entry entry; int ret = KNOT_EOK; uint16_t qtype = knot_pkt_qtype(qdata->query); /* Answer section. */ while (ret == KNOT_EOK) { if (cache_iter_val(it, &entry) == 0) { ret = rosedb_synth_rr(pkt, &entry, qtype); } if (cache_iter_next(it) != 0) { break; } } /* Authority section. */ knot_pkt_begin(pkt, KNOT_AUTHORITY); /* Not found (zone cut if records exist). */ ret = cache_iter_begin(it, key); while (ret == KNOT_EOK) { if (cache_iter_val(it, &entry) == 0) { ret = rosedb_synth_rr(pkt, &entry, KNOT_RRTYPE_NS); ret = rosedb_synth_rr(pkt, &entry, KNOT_RRTYPE_SOA); } if (cache_iter_next(it) != 0) { break; } } /* Our response is authoritative. */ if (knot_wire_get_nscount(pkt->wire) > 0) { knot_wire_set_aa(pkt->wire); if (knot_wire_get_ancount(pkt->wire) == 0) { qdata->rcode = KNOT_RCODE_NXDOMAIN; } } /* Send message to syslog. */ struct sockaddr_storage syslog_addr; if (sockaddr_set(&syslog_addr, AF_INET, entry.syslog_ip, DEFAULT_PORT) == KNOT_EOK) { int sock = net_unbound_socket(AF_INET, &syslog_addr); if (sock > 0) { rosedb_send_log(sock, (struct sockaddr *)&syslog_addr, pkt, entry.threat_code, qdata); close(sock); } } return ret; }
/*! \brief Create zone query packet. */ static knot_pkt_t *zone_query(const zone_t *zone, uint16_t pkt_type, knot_mm_t *mm) { /* Determine query type and opcode. */ uint16_t query_type = KNOT_RRTYPE_SOA; uint16_t opcode = KNOT_OPCODE_QUERY; switch(pkt_type) { case KNOT_QUERY_AXFR: query_type = KNOT_RRTYPE_AXFR; break; case KNOT_QUERY_IXFR: query_type = KNOT_RRTYPE_IXFR; break; case KNOT_QUERY_NOTIFY: opcode = KNOT_OPCODE_NOTIFY; break; } knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, mm); if (pkt == NULL) { return NULL; } knot_wire_set_id(pkt->wire, dnssec_random_uint16_t()); knot_wire_set_opcode(pkt->wire, opcode); if (pkt_type == KNOT_QUERY_NOTIFY) { knot_wire_set_aa(pkt->wire); } knot_pkt_put_question(pkt, zone->name, KNOT_CLASS_IN, query_type); /* Put current SOA (optional). */ zone_contents_t *contents = zone->contents; if (pkt_type == KNOT_QUERY_IXFR) { /* RFC1995, SOA in AUTHORITY. */ knot_pkt_begin(pkt, KNOT_AUTHORITY); knot_rrset_t soa_rr = node_rrset(contents->apex, KNOT_RRTYPE_SOA); knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, &soa_rr, 0); } else if (pkt_type == KNOT_QUERY_NOTIFY) { /* RFC1996, SOA in ANSWER. */ knot_pkt_begin(pkt, KNOT_ANSWER); knot_rrset_t soa_rr = node_rrset(contents->apex, KNOT_RRTYPE_SOA); knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, &soa_rr, 0); } return pkt; }