/** enter local data as resource records into a response-ip node */ static int respip_enter_rr(struct regional* region, struct resp_addr* raddr, const char* rrstr, const char* netblock) { uint8_t* nm; uint16_t rrtype = 0, rrclass = 0; time_t ttl = 0; uint8_t rr[LDNS_RR_BUF_SIZE]; uint8_t* rdata = NULL; size_t rdata_len = 0; char buf[65536]; char bufshort[64]; struct packed_rrset_data* pd; struct sockaddr* sa; int ret; if(raddr->action != respip_redirect && raddr->action != respip_inform_redirect) { log_err("cannot parse response-ip-data %s: response-ip " "action for %s is not redirect", rrstr, netblock); return 0; } ret = snprintf(buf, sizeof(buf), ". %s", rrstr); if(ret < 0 || ret >= (int)sizeof(buf)) { strlcpy(bufshort, rrstr, sizeof(bufshort)); log_err("bad response-ip-data: %s...", bufshort); return 0; } if(!rrstr_get_rr_content(buf, &nm, &rrtype, &rrclass, &ttl, rr, sizeof(rr), &rdata, &rdata_len)) { log_err("bad response-ip-data: %s", rrstr); return 0; } free(nm); sa = (struct sockaddr*)&raddr->node.addr; if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) { log_err("CNAME response-ip data (%s) can not co-exist with other " "response-ip data for netblock %s", rrstr, netblock); return 0; } else if (raddr->data && raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) { log_err("response-ip data (%s) can not be added; CNAME response-ip " "data already in place for netblock %s", rrstr, netblock); return 0; } else if((rrtype != LDNS_RR_TYPE_CNAME) && ((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) || (sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) { log_err("response-ip data %s record type does not correspond " "to netblock %s address family", rrstr, netblock); return 0; } if(!raddr->data) { raddr->data = new_rrset(region, rrtype, rrclass); if(!raddr->data) return 0; } pd = raddr->data->entry.data; return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr); }
/** change an rrsig rrset for use as data rrset */ static struct rrset_parse* change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg, sldns_buffer* pkt, uint16_t datatype, uint32_t rrset_flags, int hasother, sldns_pkt_section section, struct regional* region) { struct rrset_parse* dataset = sigset; hashvalue_t hash = pkt_hash_rrset(pkt, sigset->dname, datatype, sigset->rrset_class, rrset_flags); log_assert( sigset->type == LDNS_RR_TYPE_RRSIG ); log_assert( datatype != LDNS_RR_TYPE_RRSIG ); if(hasother) { /* need to make new rrset to hold data type */ dataset = new_rrset(msg, sigset->dname, sigset->dname_len, datatype, sigset->rrset_class, hash, rrset_flags, section, region); if(!dataset) return NULL; switch(section) { case LDNS_SECTION_ANSWER: msg->an_rrsets++; break; case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break; case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break; default: log_assert(0); } if(!moveover_rrsigs(pkt, region, sigset, dataset, msg->qtype == LDNS_RR_TYPE_RRSIG || (msg->qtype == LDNS_RR_TYPE_ANY && section != LDNS_SECTION_ANSWER) )) return NULL; return dataset; } /* changeover the type of the rrset to data set */ msgparse_bucket_remove(msg, dataset); /* insert into new hash bucket */ dataset->rrset_bucket_next = msg->hashtable[hash&(PARSE_TABLE_SIZE-1)]; msg->hashtable[hash&(PARSE_TABLE_SIZE-1)] = dataset; dataset->hash = hash; /* use section of data item for result */ change_section(msg, dataset, section); dataset->type = datatype; dataset->flags = rrset_flags; dataset->rrsig_count += dataset->rr_count; dataset->rr_count = 0; /* move sigs to end of siglist */ if(dataset->rrsig_last) dataset->rrsig_last->next = dataset->rr_first; else dataset->rrsig_first = dataset->rr_first; dataset->rrsig_last = dataset->rr_last; dataset->rr_first = 0; dataset->rr_last = 0; return dataset; }
/** * Parse packet RR section, for answer, authority and additional sections. * @param pkt: packet, position at call must be at start of section. * at end position is after section. * @param msg: store results here. * @param region: how to alloc results. * @param section: section enum. * @param num_rrs: how many rrs are in the section. * @param num_rrsets: returns number of rrsets in the section. * @return: 0 if OK, or rcode on error. */ static int parse_section(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region, sldns_pkt_section section, uint16_t num_rrs, size_t* num_rrsets) { uint16_t i; uint8_t* dname, *prev_dname_f = NULL, *prev_dname_l = NULL; size_t dnamelen, prev_dnamelen = 0; uint16_t type, prev_type = 0; uint16_t dclass, prev_dclass = 0; uint32_t rrset_flags = 0; hashvalue_t hash = 0; struct rrset_parse* rrset = NULL; int r; if(num_rrs == 0) return 0; if(sldns_buffer_remaining(pkt) <= 0) return LDNS_RCODE_FORMERR; for(i=0; i<num_rrs; i++) { /* parse this RR. */ dname = sldns_buffer_current(pkt); if((dnamelen = pkt_dname_len(pkt)) == 0) return LDNS_RCODE_FORMERR; if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, len */ return LDNS_RCODE_FORMERR; type = sldns_buffer_read_u16(pkt); sldns_buffer_read(pkt, &dclass, sizeof(dclass)); if(0) { /* debug show what is being parsed. */ if(type == LDNS_RR_TYPE_RRSIG) { uint16_t t; if(pkt_rrsig_covered(pkt, sldns_buffer_current(pkt), &t)) fprintf(stderr, "parse of %s(%d) [%s(%d)]", sldns_rr_descript(type)? sldns_rr_descript(type)->_name: "??", (int)type, sldns_rr_descript(t)? sldns_rr_descript(t)->_name: "??", (int)t); } else fprintf(stderr, "parse of %s(%d)", sldns_rr_descript(type)? sldns_rr_descript(type)->_name: "??", (int)type); fprintf(stderr, " %s(%d) ", sldns_lookup_by_id(sldns_rr_classes, (int)ntohs(dclass))?sldns_lookup_by_id( sldns_rr_classes, (int)ntohs(dclass))->name: "??", (int)ntohs(dclass)); dname_print(stderr, pkt, dname); fprintf(stderr, "\n"); } /* see if it is part of an existing RR set */ if(!find_rrset(msg, pkt, dname, dnamelen, type, dclass, &hash, &rrset_flags, &prev_dname_f, &prev_dname_l, &prev_dnamelen, &prev_type, &prev_dclass, &rrset, section, region)) return LDNS_RCODE_SERVFAIL; if(!rrset) { /* it is a new RR set. hash&flags already calculated.*/ (*num_rrsets)++; rrset = new_rrset(msg, dname, dnamelen, type, dclass, hash, rrset_flags, section, region); if(!rrset) return LDNS_RCODE_SERVFAIL; } else if(0) { fprintf(stderr, "is part of existing: "); dname_print(stderr, pkt, rrset->dname); fprintf(stderr, " type %s(%d)\n", sldns_rr_descript(rrset->type)? sldns_rr_descript(rrset->type)->_name: "??", (int)rrset->type); } /* add to rrset. */ if((r=add_rr_to_rrset(rrset, pkt, msg, region, section, type)) != 0) return r; } return 0; }