int parse_sflow_datagram(const char *bp, int len) { const char *p = bp; u_int32_t addr_type, agent_id = 0, seqno, uptime, nrecords; int i; timestamp = time(NULL); /* timestamp for this sflow datagram */ endp = bp + len; /* sflow datagram header */ sflow_version = buffer_read_4(&p); if (sflow_version != 4 && sflow_version != 5) { warnx("unkonwn sflow version 0x%x", sflow_version); return (len); } addr_type = buffer_read_4(&p); switch (addr_type) { case 1: /* IPv4 */ buffer_skip(&p, 4); break; case 2: /* IPv6 */ buffer_skip(&p, 16); break; default: return (-1); } if (sflow_version >= 5) { agent_id = buffer_read_4(&p); } seqno = buffer_read_4(&p); uptime = buffer_read_4(&p); nrecords = buffer_read_4(&p); #if 1 if (verbose > 1) fprintf(stderr, "sflow datagram: ver=%u, agent_id=%u, addr_type=%u, nrecords=%u\n", sflow_version, agent_id, addr_type, nrecords); #endif for (i = 0; i < nrecords; i++) { if (sflow_version >= 5) parse_sflow5(&p); else { if (parse_sflow4_sample(&p) < 0) { /* if parsing failed for v4, give up */ if (verbose > 0) fprintf(stderr, "parse_sflow4 failed\n"); break; } } } return (len); }
int get_record(buffer_type *buffer, struct decompress_ctx * decompress, struct rr *record) { int ret; if (buffer == NULL || record == NULL) return -1; ret = dns_name_from_wire(buffer, decompress, record->name); if (ret == -1) return -1; if (!buffer_available(buffer, 2 * sizeof(u_int16_t))) return -1; record->type = buffer_read_u16(buffer); buffer_skip(buffer, sizeof(u_int16_t) + sizeof(u_int32_t) + sizeof(u_int16_t)); switch (record->type) { case TYPE_A: if (!buffer_available(buffer, sizeof(u_int32_t))) return -1; buffer_read(buffer, record->rdata, 4); break; case TYPE_CNAME: ret = dns_name_from_wire(buffer, decompress, record->rdata); if (ret == -1) return ret; break; default: return -1; } return 0; }
int packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr) { size_t truncation_mark; uint16_t rdlength = 0; size_t rdlength_pos; uint16_t j; assert(q); assert(owner); assert(rr); /* * If the record does not in fit in the packet the packet size * will be restored to the mark. */ truncation_mark = buffer_position(q->packet); encode_dname(q, owner); buffer_write_u16(q->packet, rr->type); buffer_write_u16(q->packet, rr->klass); buffer_write_u32(q->packet, rr->ttl); /* Reserve space for rdlength. */ rdlength_pos = buffer_position(q->packet); buffer_skip(q->packet, sizeof(rdlength)); for (j = 0; j < rr->rdata_count; ++j) { switch (rdata_atom_wireformat_type(rr->type, j)) { case RDATA_WF_COMPRESSED_DNAME: encode_dname(q, rdata_atom_domain(rr->rdatas[j])); break; case RDATA_WF_UNCOMPRESSED_DNAME: { const dname_type *dname = domain_dname( rdata_atom_domain(rr->rdatas[j])); buffer_write(q->packet, dname_name(dname), dname->name_size); break; } default: buffer_write(q->packet, rdata_atom_data(rr->rdatas[j]), rdata_atom_size(rr->rdatas[j])); break; } } if (!query_overflow(q)) { rdlength = (buffer_position(q->packet) - rdlength_pos - sizeof(rdlength)); buffer_write_u16_at(q->packet, rdlength_pos, rdlength); return 1; } else { buffer_set_position(q->packet, truncation_mark); query_clear_dname_offsets(q, truncation_mark); assert(!query_overflow(q)); return 0; } }
/** * IXFR. * */ static query_state query_process_ixfr(query_type* q) { uint16_t count = 0; ods_log_assert(q); ods_log_assert(q->buffer); ods_log_assert(buffer_pkt_qdcount(q->buffer) == 1); /* skip header and question section */ buffer_skip(q->buffer, BUFFER_PKT_HEADER_SIZE); if (!buffer_skip_rr(q->buffer, 1)) { ods_log_error("[%s] dropped packet: zone %s received bad ixfr " "request (bad question section)", query_str, q->zone->name); return QUERY_DISCARDED; } /* answer section is empty */ ods_log_assert(buffer_pkt_ancount(q->buffer) == 0); /* examine auth section */ q->startpos = buffer_position(q->buffer); count = buffer_pkt_nscount(q->buffer); if (count) { if (!buffer_skip_dname(q->buffer) || !query_parse_soa(q->buffer, &(q->serial))) { ods_log_error("[%s] dropped packet: zone %s received bad ixfr " "request (bad soa in auth section)", query_str, q->zone->name); return QUERY_DISCARDED; } ods_log_debug("[%s] found ixfr request zone %s serial=%u", query_str, q->zone->name, q->serial); return QUERY_PROCESSED; } ods_log_debug("[%s] ixfr request zone %s has no auth section", query_str, q->zone->name); q->serial = 0; return QUERY_PROCESSED; }
off_t buffer_copy_IntInt(int Iin, int Tin, void *Pfilter, int Tfilter, int Iout, int Tout, off_t limit, struct dpkg_error *err) { struct buffer_data read_data = { .type = Tin, .arg.i = Iin }; struct buffer_data filter = { .type = Tfilter, .arg.ptr = Pfilter }; struct buffer_data write_data = { .type = Tout, .arg.i = Iout }; return buffer_copy(&read_data, &filter, &write_data, limit, err); } off_t buffer_copy_IntPtr(int Iin, int Tin, void *Pfilter, int Tfilter, void *Pout, int Tout, off_t limit, struct dpkg_error *err) { struct buffer_data read_data = { .type = Tin, .arg.i = Iin }; struct buffer_data filter = { .type = Tfilter, .arg.ptr = Pfilter }; struct buffer_data write_data = { .type = Tout, .arg.ptr = Pout }; return buffer_copy(&read_data, &filter, &write_data, limit, err); } static off_t buffer_skip(struct buffer_data *input, off_t limit, struct dpkg_error *err) { struct buffer_data output; struct buffer_data filter; switch (input->type) { case BUFFER_READ_FD: if (lseek(input->arg.i, limit, SEEK_CUR) != -1) return limit; if (errno != ESPIPE) return dpkg_put_errno(err, _("failed to seek")); break; default: internerr("unknown data type %i", input->type); } output.type = BUFFER_WRITE_NULL; output.arg.ptr = NULL; filter.type = BUFFER_FILTER_NULL; filter.arg.ptr = NULL; return buffer_copy(input, &filter, &output, limit, err); } off_t buffer_skip_Int(int I, int T, off_t limit, struct dpkg_error *err) { struct buffer_data input = { .type = T, .arg.i = I }; return buffer_skip(&input, limit, err); }
void xfrd_handle_passed_packet(buffer_type* packet, int acl_num) { uint8_t qnamebuf[MAXDOMAINLEN]; uint16_t qtype, qclass; const dname_type* dname; region_type* tempregion = region_create(xalloc, free); xfrd_zone_t* zone; buffer_skip(packet, QHEADERSZ); if(!packet_read_query_section(packet, qnamebuf, &qtype, &qclass)) { region_destroy(tempregion); return; /* drop bad packet */ } dname = dname_make(tempregion, qnamebuf, 1); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: got passed packet for %s, acl " "%d", dname_to_string(dname,0), acl_num)); /* find the zone */ zone = (xfrd_zone_t*)rbtree_search(xfrd->zones, dname); if(!zone) { log_msg(LOG_INFO, "xfrd: incoming packet for unknown zone %s", dname_to_string(dname,0)); region_destroy(tempregion); return; /* drop packet for unknown zone */ } region_destroy(tempregion); /* handle */ if(OPCODE(packet) == OPCODE_NOTIFY) { xfrd_soa_t soa; int have_soa = 0; int next; /* get serial from a SOA */ if(ANCOUNT(packet) == 1 && packet_skip_dname(packet) && xfrd_parse_soa_info(packet, &soa)) { have_soa = 1; } if(xfrd_handle_incoming_notify(zone, have_soa?&soa:NULL)) { if(zone->zone_handler.fd == -1 && zone->tcp_conn == -1 && !zone->tcp_waiting && !zone->udp_waiting) { xfrd_set_refresh_now(zone); } } next = find_same_master_notify(zone, acl_num); if(next != -1) { zone->next_master = next; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: notify set next master to query %d", next)); } } else { /* TODO handle incoming IXFR udp reply via port 53 */ } }
/*-------------------------------------------------------------------------*\ * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF * are not returned by the function and are discarded from the buffer \*-------------------------------------------------------------------------*/ static int recvline(p_buffer buf, luaL_Buffer *b) { int err = IO_DONE; while (err == IO_DONE) { size_t count, pos; const char *data; err = buffer_get(buf, &data, &count); pos = 0; while (pos < count && data[pos] != '\n') { /* we ignore all \r's */ if (data[pos] != '\r') luaL_addchar(b, data[pos]); pos++; } if (pos < count) { /* found '\n' */ buffer_skip(buf, pos+1); /* skip '\n' too */ break; /* we are done */ } else /* reached the end of the buffer */ buffer_skip(buf, pos); } return err; }
static char* unmarshal_str(region_type* r, struct buffer* b) { uint8_t nonnull = unmarshal_u8(b); if(nonnull) { char* result = region_strdup(r, (char*)buffer_current(b)); size_t len = strlen((char*)buffer_current(b)); buffer_skip(b, len+1); return result; } else return NULL; }
/* * Check the RRs in an IXFR/AXFR reply. * returns 0 on error, 1 on correct parseable packet. * done = 1 if the last SOA in an IXFR/AXFR has been seen. * soa then contains that soa info. * (soa contents is modified by the routine) */ static int xfrd_xfr_check_rrs(xfrd_zone_t* zone, buffer_type* packet, size_t count, int *done, xfrd_soa_t* soa) { /* first RR has already been checked */ uint16_t type, rrlen; size_t i, soapos; for(i=0; i<count; ++i,++zone->msg_rr_count) { if(!packet_skip_dname(packet)) return 0; if(!buffer_available(packet, 10)) return 0; soapos = buffer_position(packet); type = buffer_read_u16(packet); (void)buffer_read_u16(packet); /* class */ (void)buffer_read_u32(packet); /* ttl */ rrlen = buffer_read_u16(packet); if(!buffer_available(packet, rrlen)) return 0; if(type == TYPE_SOA) { /* check the SOAs */ size_t mempos = buffer_position(packet); buffer_set_position(packet, soapos); if(!xfrd_parse_soa_info(packet, soa)) return 0; if(zone->msg_rr_count == 1 && ntohl(soa->serial) != zone->msg_new_serial) { /* 2nd RR is SOA with lower serial, this is an IXFR */ zone->msg_is_ixfr = 1; if(!zone->soa_disk_acquired) return 0; /* got IXFR but need AXFR */ if(ntohl(soa->serial) != ntohl(zone->soa_disk.serial)) return 0; /* bad start serial in IXFR */ zone->msg_old_serial = ntohl(soa->serial); } else if(ntohl(soa->serial) == zone->msg_new_serial) { /* saw another SOA of new serial. */ if(zone->msg_is_ixfr == 1) { zone->msg_is_ixfr = 2; /* seen middle SOA in ixfr */ } else { /* 2nd SOA for AXFR or 3rd newSOA for IXFR */ *done = 1; } } buffer_set_position(packet, mempos); } buffer_skip(packet, rrlen); } /* packet seems to have a valid DNS RR structure */ return 1; }
/** * Add RR to query. * */ int query_add_rr(query_type* q, ldns_rr* rr) { size_t i = 0; size_t tc_mark = 0; size_t rdlength_pos = 0; uint16_t rdlength = 0; ods_log_assert(q); ods_log_assert(q->buffer); ods_log_assert(rr); /* set truncation mark, in case rr does not fit */ tc_mark = buffer_position(q->buffer); /* owner type class ttl */ if (!buffer_available(q->buffer, ldns_rdf_size(ldns_rr_owner(rr)))) { goto query_add_rr_tc; } buffer_write_rdf(q->buffer, ldns_rr_owner(rr)); if (!buffer_available(q->buffer, sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(rdlength))) { goto query_add_rr_tc; } buffer_write_u16(q->buffer, (uint16_t) ldns_rr_get_type(rr)); buffer_write_u16(q->buffer, (uint16_t) ldns_rr_get_class(rr)); buffer_write_u32(q->buffer, (uint32_t) ldns_rr_ttl(rr)); /* skip rdlength */ rdlength_pos = buffer_position(q->buffer); buffer_skip(q->buffer, sizeof(rdlength)); /* write rdata */ for (i=0; i < ldns_rr_rd_count(rr); i++) { if (!buffer_available(q->buffer, ldns_rdf_size(ldns_rr_rdf(rr, i)))) { goto query_add_rr_tc; } buffer_write_rdf(q->buffer, ldns_rr_rdf(rr, i)); } if (!query_overflow(q)) { /* write rdlength */ rdlength = buffer_position(q->buffer) - rdlength_pos - sizeof(rdlength); buffer_write_u16_at(q->buffer, rdlength_pos, rdlength); /* position updated by buffer_write() */ return 1; } query_add_rr_tc: buffer_set_position(q->buffer, tc_mark); ods_log_assert(!query_overflow(q)); return 0; }
int packet_skip_dname(buffer_type *packet) { while (1) { uint8_t label_size; if (!buffer_available(packet, 1)) return 0; label_size = buffer_read_u8(packet); if (label_size == 0) { return 1; } else if ((label_size & 0xc0) != 0) { if (!buffer_available(packet, 1)) return 0; buffer_skip(packet, 1); return 1; } else if (!buffer_available(packet, label_size)) { return 0; } else { buffer_skip(packet, label_size); } } }
int packet_skip_rr(buffer_type *packet, int question_section) { if (!packet_skip_dname(packet)) return 0; if (question_section) { if (!buffer_available(packet, 4)) return 0; buffer_skip(packet, 4); } else { uint16_t rdata_size; if (!buffer_available(packet, 10)) return 0; buffer_skip(packet, 8); rdata_size = buffer_read_u16(packet); if (!buffer_available(packet, rdata_size)) return 0; buffer_skip(packet, rdata_size); } return 1; }
/*-------------------------------------------------------------------------*\ * Reads a fixed number of bytes (buffered) \*-------------------------------------------------------------------------*/ static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { int err = IO_DONE; size_t total = 0; while (err == IO_DONE) { size_t count; const char *data; err = buffer_get(buf, &data, &count); count = MIN(count, wanted - total); luaL_addlstring(b, data, count); buffer_skip(buf, count); total += count; if (total >= wanted) break; } return err; }
int skip_record(buffer_type *buffer) { char* p; u_int16_t rdlength; p = buffer_current(buffer); while (*p != '\0') { if (buffer_available(buffer, *p + 1)) buffer_skip(buffer, *p + 1); else return -1; p = buffer_current(buffer); } if (*p != '\0') return -1; if (!buffer_available(buffer, 11)) return -1; buffer_skip(buffer, 1); buffer_skip(buffer, 8); rdlength = buffer_read_u16(buffer); if (buffer_available(buffer, rdlength)) return 0; return -1; }
/*-------------------------------------------------------------------------*\ * Reads everything until the connection is closed (buffered) \*-------------------------------------------------------------------------*/ static int recvall(p_buffer buf, luaL_Buffer *b) { int err = IO_DONE; size_t total = 0; while (err == IO_DONE) { const char *data; size_t count; err = buffer_get(buf, &data, &count); total += count; luaL_addlstring(b, data, count); buffer_skip(buf, count); } if (err == IO_CLOSED) { if (total > 0) return IO_DONE; else return IO_CLOSED; } else return err; }
static int rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) return 1; buffer_reserve(output, size * 2 + 1); length = __b64_ntop(rdata_atom_data(rdata), size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; }
static int rdata_nxt_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { size_t i; uint8_t *bitmap = rdata_atom_data(rdata); size_t bitmap_size = rdata_atom_size(rdata); for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, "%s ", rrtype_to_string(i)); } } buffer_skip(output, -1); return 1; }
static int rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) { /* single zero represents empty buffer */ buffer_write(output, "0", 1); return 1; } buffer_reserve(output, size * 2 + 1); length = b64_ntop(rdata_atom_data(rdata), size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; }
static int rdata_base32_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) { buffer_write(output, "-", 1); return 1; } size -= 1; /* remove length byte from count */ buffer_reserve(output, size * 2 + 1); length = b32_ntop(rdata_atom_data(rdata)+1, size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; }
void xfrd_setup_packet(buffer_type* packet, uint16_t type, uint16_t klass, const dname_type* dname) { /* Set up the header */ buffer_clear(packet); ID_SET(packet, qid_generate()); FLAGS_SET(packet, 0); OPCODE_SET(packet, OPCODE_QUERY); QDCOUNT_SET(packet, 1); ANCOUNT_SET(packet, 0); NSCOUNT_SET(packet, 0); ARCOUNT_SET(packet, 0); buffer_skip(packet, QHEADERSZ); /* The question record. */ buffer_write(packet, dname_name(dname), dname->name_size); buffer_write_u16(packet, type); buffer_write_u16(packet, klass); }
static int rdata_nsec_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { size_t saved_position = buffer_position(output); buffer_type packet; int insert_space = 0; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); while (buffer_available(&packet, 2)) { uint8_t window = buffer_read_u8(&packet); uint8_t bitmap_size = buffer_read_u8(&packet); uint8_t *bitmap = buffer_current(&packet); int i; if (!buffer_available(&packet, bitmap_size)) { buffer_set_position(output, saved_position); return 0; } for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, "%s%s", insert_space ? " " : "", rrtype_to_string( window * 256 + i)); insert_space = 1; } } buffer_skip(&packet, bitmap_size); } return 1; }
static int rdata_services_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; buffer_type packet; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); if (buffer_available(&packet, 1)) { uint8_t protocol_number = buffer_read_u8(&packet); ssize_t bitmap_size = buffer_remaining(&packet); uint8_t *bitmap = buffer_current(&packet); struct protoent *proto = getprotobynumber(protocol_number); if (proto) { int i; buffer_printf(output, "%s", proto->p_name); for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { struct servent *service = getservbyport((int)htons(i), proto->p_name); if (service) { buffer_printf(output, " %s", service->s_name); } else { buffer_printf(output, " %d", i); } } } buffer_skip(&packet, bitmap_size); result = 1; } } return result; }
/* parse the received packet. returns xfrd packet result code. */ static enum xfrd_packet_result xfrd_parse_received_xfr_packet(xfrd_zone_t* zone, buffer_type* packet, xfrd_soa_t* soa) { size_t rr_count; size_t qdcount = QDCOUNT(packet); size_t ancount = ANCOUNT(packet), ancount_todo; int done = 0; /* has to be axfr / ixfr reply */ if(!buffer_available(packet, QHEADERSZ)) { log_msg(LOG_INFO, "packet too small"); return xfrd_packet_bad; } /* only check ID in first response message. Could also check that * AA bit and QR bit are set, but not needed. */ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "got query with ID %d and %d needed", ID(packet), zone->query_id)); if(ID(packet) != zone->query_id) { log_msg(LOG_ERR, "xfrd: zone %s received bad query id from %s, " "dropped", zone->apex_str, zone->master->ip_address_spec); return xfrd_packet_bad; } /* check RCODE in all response messages */ if(RCODE(packet) != RCODE_OK) { log_msg(LOG_ERR, "xfrd: zone %s received error code %s from " "%s", zone->apex_str, rcode2str(RCODE(packet)), zone->master->ip_address_spec); if (RCODE(packet) == RCODE_IMPL || RCODE(packet) == RCODE_FORMAT) { return xfrd_packet_notimpl; } return xfrd_packet_bad; } /* check TSIG */ if(zone->master->key_options) { if(!xfrd_xfr_process_tsig(zone, packet)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "dropping xfr reply due " "to bad TSIG")); return xfrd_packet_bad; } } buffer_skip(packet, QHEADERSZ); /* skip question section */ for(rr_count = 0; rr_count < qdcount; ++rr_count) { if (!packet_skip_rr(packet, 1)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: bad RR in " "question section", zone->apex_str, zone->master->ip_address_spec); return xfrd_packet_bad; } } if(zone->msg_rr_count == 0 && ancount == 0) { if(zone->tcp_conn == -1 && TC(packet)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: TC flagged")); return xfrd_packet_tcp; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: too short xfr packet: no " "answer")); return xfrd_packet_bad; } ancount_todo = ancount; if(zone->msg_rr_count == 0) { /* parse the first RR, see if it is a SOA */ if(!packet_skip_dname(packet) || !xfrd_parse_soa_info(packet, soa)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "no SOA begins answer" " section", zone->apex_str, zone->master->ip_address_spec)); return xfrd_packet_bad; } if(zone->soa_disk_acquired != 0 && zone->state != xfrd_zone_expired /* if expired - accept anything */ && compare_serial(ntohl(soa->serial), ntohl(zone->soa_disk.serial)) < 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s ignoring old serial from %s", zone->apex_str, zone->master->ip_address_spec)); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s ignoring old serial from %s", zone->apex_str, zone->master->ip_address_spec)); return xfrd_packet_bad; } if(zone->soa_disk_acquired != 0 && zone->soa_disk.serial == soa->serial) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s got " "update indicating " "current serial", zone->apex_str)); /* (even if notified) the lease on the current soa is renewed */ zone->soa_disk_acquired = xfrd_time(); if(zone->soa_nsd.serial == soa->serial) zone->soa_nsd_acquired = xfrd_time(); xfrd_set_zone_state(zone, xfrd_zone_ok); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is ok", zone->apex_str)); if(zone->soa_notified_acquired == 0) { /* not notified or anything, so stop asking around */ zone->round_num = -1; /* next try start a new round */ xfrd_set_timer_refresh(zone); return xfrd_packet_newlease; } /* try next master */ return xfrd_packet_bad; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "IXFR reply has ok serial (have \ %u, reply %u).", ntohl(zone->soa_disk.serial), ntohl(soa->serial))); /* serial is newer than soa_disk */ if(ancount == 1) { /* single record means it is like a notify */ (void)xfrd_handle_incoming_notify(zone, soa); } else if(zone->soa_notified_acquired && zone->soa_notified.serial && compare_serial(ntohl(zone->soa_notified.serial), ntohl(soa->serial)) < 0) { /* this AXFR/IXFR notifies me that an even newer serial exists */ zone->soa_notified.serial = soa->serial; } zone->msg_new_serial = ntohl(soa->serial); zone->msg_rr_count = 1; zone->msg_is_ixfr = 0; if(zone->soa_disk_acquired) zone->msg_old_serial = ntohl(zone->soa_disk.serial); else zone->msg_old_serial = 0; ancount_todo = ancount - 1; } if(zone->tcp_conn == -1 && TC(packet)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s received TC from %s. retry tcp.", zone->apex_str, zone->master->ip_address_spec)); return xfrd_packet_tcp; } if(zone->tcp_conn == -1 && ancount < 2) { /* too short to be a real ixfr/axfr data transfer: need at */ /* least two RRs in the answer section. */ /* The serial is newer, so try tcp to this master. */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: udp reply is short. Try " "tcp anyway.")); return xfrd_packet_tcp; } if(!xfrd_xfr_check_rrs(zone, packet, ancount_todo, &done, soa)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s sent bad xfr " "reply.", zone->apex_str)); return xfrd_packet_bad; } if(zone->tcp_conn == -1 && done == 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: udp reply incomplete")); return xfrd_packet_bad; } if(done == 0) return xfrd_packet_more; if(zone->master->key_options) { if(zone->tsig.updates_since_last_prepare != 0) { log_msg(LOG_INFO, "xfrd: last packet of reply has no " "TSIG"); return xfrd_packet_bad; } } return xfrd_packet_transfer; }
int dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet, int allow_pointers) { int done = 0; uint8_t visited[(MAX_PACKET_SIZE+7)/8]; size_t dname_length = 0; const uint8_t *label; ssize_t mark = -1; memset(visited, 0, (buffer_limit(packet)+7)/8); while (!done) { if (!buffer_available(packet, 1)) { /* error("dname out of bounds"); */ return 0; } if (get_bit(visited, buffer_position(packet))) { /* error("dname loops"); */ return 0; } set_bit(visited, buffer_position(packet)); label = buffer_current(packet); if (label_is_pointer(label)) { size_t pointer; if (!allow_pointers) { return 0; } if (!buffer_available(packet, 2)) { /* error("dname pointer out of bounds"); */ return 0; } pointer = label_pointer_location(label); if (pointer >= buffer_limit(packet)) { /* error("dname pointer points outside packet"); */ return 0; } buffer_skip(packet, 2); if (mark == -1) { mark = buffer_position(packet); } buffer_set_position(packet, pointer); } else if (label_is_normal(label)) { size_t length = label_length(label) + 1; done = label_is_root(label); if (!buffer_available(packet, length)) { /* error("dname label out of bounds"); */ return 0; } if (dname_length + length >= MAXDOMAINLEN+1) { /* error("dname too large"); */ return 0; } buffer_read(packet, buf + dname_length, length); dname_length += length; } else { /* error("bad label type"); */ return 0; } } if (mark != -1) { buffer_set_position(packet, mark); } return dname_length; }
static void handle_tcp_writing(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types) { struct tcp_handler_data *data = (struct tcp_handler_data *) handler->user_data; ssize_t sent; struct query *q = data->query; if (event_types & NETIO_EVENT_TIMEOUT) { /* Connection timed out. */ cleanup_tcp_handler(netio, handler); return; } assert(event_types & NETIO_EVENT_WRITE); if (data->bytes_transmitted < sizeof(q->tcplen)) { /* Writing the response packet length. */ uint16_t n_tcplen = htons(q->tcplen); sent = write(handler->fd, (const char *) &n_tcplen + data->bytes_transmitted, sizeof(n_tcplen) - data->bytes_transmitted); if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } data->bytes_transmitted += sent; if (data->bytes_transmitted < sizeof(q->tcplen)) { /* * Writing not complete, wait until socket * becomes writable again. */ return; } assert(data->bytes_transmitted == sizeof(q->tcplen)); } assert(data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)); sent = write(handler->fd, buffer_current(q->packet), buffer_remaining(q->packet)); if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } buffer_skip(q->packet, sent); data->bytes_transmitted += sent; if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) { /* * Still more data to write when socket becomes * writable again. */ return; } assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen)); if (data->query_state == QUERY_IN_AXFR) { /* Continue processing AXFR and writing back results. */ buffer_clear(q->packet); data->query_state = query_axfr(data->nsd, q); if (data->query_state != QUERY_PROCESSED) { query_add_optional(data->query, data->nsd); /* Reset data. */ buffer_flip(q->packet); q->tcplen = buffer_remaining(q->packet); data->bytes_transmitted = 0; /* Reset timeout. */ handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0; timespec_add(handler->timeout, netio_current_time(netio)); /* * Write data if/when the socket is writable * again. */ return; } } /* * Done sending, wait for the next request to arrive on the * TCP socket by installing the TCP read handler. */ if (data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) { (void) shutdown(handler->fd, SHUT_WR); } data->bytes_transmitted = 0; handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0; timespec_add(handler->timeout, netio_current_time(netio)); handler->event_types = NETIO_EVENT_READ | NETIO_EVENT_TIMEOUT; handler->event_handler = handle_tcp_reading; }
static void handle_udp(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { struct udp_handler_data *data = (struct udp_handler_data *) handler->user_data; int received, sent; struct query *q = data->query; if (!(event_types & NETIO_EVENT_READ)) { return; } /* Account... */ #ifdef BIND8_STATS if (data->socket->addr->ai_family == AF_INET) { STATUP(data->nsd, qudp); } else if (data->socket->addr->ai_family == AF_INET6) { STATUP(data->nsd, qudp6); } #endif /* Initialize the query... */ query_reset(q, UDP_MAX_MESSAGE_LEN, 0); received = recvfrom(handler->fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *)&q->addr, &q->addrlen); if (received == -1) { if (errno != EAGAIN && errno != EINTR) { log_msg(LOG_ERR, "recvfrom failed: %s", strerror(errno)); STATUP(data->nsd, rxerr); /* No zone statup */ } } else { buffer_skip(q->packet, received); buffer_flip(q->packet); /* Process and answer the query... */ if (server_process_query(data->nsd, q) != QUERY_DISCARDED) { #ifdef BIND8_STATS if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) { STATUP(data->nsd, nona); ZTATUP(q->zone, nona); } # ifdef USE_ZONE_STATS if (data->socket->addr->ai_family == AF_INET) { ZTATUP(q->zone, qudp); } else if (data->socket->addr->ai_family == AF_INET6) { ZTATUP(q->zone, qudp6); } # endif #endif /* Add EDNS0 and TSIG info if necessary. */ query_add_optional(q, data->nsd); buffer_flip(q->packet); sent = sendto(handler->fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *) &q->addr, q->addrlen); if (sent == -1) { log_msg(LOG_ERR, "sendto failed: %s", strerror(errno)); STATUP(data->nsd, txerr); ZTATUP(q->zone, txerr); } else if ((size_t) sent != buffer_remaining(q->packet)) { log_msg(LOG_ERR, "sent %d in place of %d bytes", sent, (int) buffer_remaining(q->packet)); #ifdef BIND8_STATS } else { /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(q->packet)); ZTATUP2(q->zone, rcode, RCODE(q->packet)); if (TC(q->packet)) { STATUP(data->nsd, truncated); ZTATUP(q->zone, truncated); } #endif /* BIND8_STATS */ } #ifdef BIND8_STATS } else { STATUP(data->nsd, dropped); # ifdef USE_ZONE_STATS if (q->zone) { ZTATUP(q->zone, dropped); } # endif #endif } } }
static void handle_tcp_reading(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types) { struct tcp_handler_data *data = (struct tcp_handler_data *) handler->user_data; ssize_t received; if (event_types & NETIO_EVENT_TIMEOUT) { /* Connection timed out. */ cleanup_tcp_handler(netio, handler); return; } if (data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) { /* No more queries allowed on this tcp connection. */ cleanup_tcp_handler(netio, handler); return; } assert(event_types & NETIO_EVENT_READ); if (data->bytes_transmitted == 0) { query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1); } /* * Check if we received the leading packet length bytes yet. */ if (data->bytes_transmitted < sizeof(uint16_t)) { received = read(handler->fd, (char *) &data->query->tcplen + data->bytes_transmitted, sizeof(uint16_t) - data->bytes_transmitted); if (received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more * data is available. */ return; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } else if (received == 0) { /* EOF */ cleanup_tcp_handler(netio, handler); return; } data->bytes_transmitted += received; if (data->bytes_transmitted < sizeof(uint16_t)) { /* * Not done with the tcplen yet, wait for more * data to become available. */ return; } assert(data->bytes_transmitted == sizeof(uint16_t)); data->query->tcplen = ntohs(data->query->tcplen); /* * Minimum query size is: * * Size of the header (12) * + Root domain name (1) * + Query class (2) * + Query type (2) */ if (data->query->tcplen < QHEADERSZ + 1 + sizeof(uint16_t) + sizeof(uint16_t)) { VERBOSITY(2, (LOG_WARNING, "packet too small, dropping tcp connection")); cleanup_tcp_handler(netio, handler); return; } if (data->query->tcplen > data->query->maxlen) { VERBOSITY(2, (LOG_WARNING, "insufficient tcp buffer, dropping connection")); cleanup_tcp_handler(netio, handler); return; } buffer_set_limit(data->query->packet, data->query->tcplen); } assert(buffer_remaining(data->query->packet) > 0); /* Read the (remaining) query data. */ received = read(handler->fd, buffer_current(data->query->packet), buffer_remaining(data->query->packet)); if (received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more data is * available. */ return; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } else if (received == 0) { /* EOF */ cleanup_tcp_handler(netio, handler); return; } data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if (buffer_remaining(data->query->packet) > 0) { /* * Message not yet complete, wait for more data to * become available. */ return; } assert(buffer_position(data->query->packet) == data->query->tcplen); /* Account... */ #ifdef BIND8_STATS # ifndef INET6 STATUP(data->nsd, ctcp); # else if (data->query->addr.ss_family == AF_INET) { STATUP(data->nsd, ctcp); } else if (data->query->addr.ss_family == AF_INET6) { STATUP(data->nsd, ctcp6); } # endif #endif /* BIND8_STATS */ /* We have a complete query, process it. */ /* tcp-query-count: handle query counter ++ */ data->query_count++; buffer_flip(data->query->packet); data->query_state = server_process_query(data->nsd, data->query); if (data->query_state == QUERY_DISCARDED) { /* Drop the packet and the entire connection... */ STATUP(data->nsd, dropped); #if defined(BIND8_STATS) && defined(USE_ZONE_STATS) if (data->query->zone) { ZTATUP(data->query->zone, dropped); } #endif cleanup_tcp_handler(netio, handler); return; } #ifdef BIND8_STATS if (RCODE(data->query->packet) == RCODE_OK && !AA(data->query->packet)) { STATUP(data->nsd, nona); ZTATUP(data->query->zone, nona); } # ifdef USE_ZONE_STATS # ifndef INET6 ZTATUP(data->query->zone, ctcp); # else if (data->query->addr.ss_family == AF_INET) { ZTATUP(data->query->zone, ctcp); } else if (data->query->addr.ss_family == AF_INET6) { ZTATUP(data->query->zone, ctcp6); } # endif # endif /* USE_ZONE_STATS */ #endif /* BIND8_STATS */ query_add_optional(data->query, data->nsd); /* Switch to the tcp write handler. */ buffer_flip(data->query->packet); data->query->tcplen = buffer_remaining(data->query->packet); data->bytes_transmitted = 0; handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0L; timespec_add(handler->timeout, netio_current_time(netio)); handler->event_types = NETIO_EVENT_WRITE | NETIO_EVENT_TIMEOUT; handler->event_handler = handle_tcp_writing; }
int parse_sflow4_sample(const char **p) { u_int32_t sample_type, packetdata_type; u_int32_t seqno, src_id, srate, total, drops, input, output; u_int32_t protocol, framelen, snaplen; u_int32_t interval, counters_version; u_int32_t nextended, extended_type, addr_type; u_int32_t aspath_len, asn_len, community_len, str_len; int i; sample_type = buffer_read_4(p); if (verbose > 1) fprintf(stderr, "sflow4: sample_type:%u\n", sample_type); switch (sample_type) { case 1: /* flow sample */ seqno = buffer_read_4(p); src_id = buffer_read_4(p); srate = buffer_read_4(p); total = buffer_read_4(p); drops = buffer_read_4(p); input = buffer_read_4(p); output = buffer_read_4(p); sampling_rate = srate; packetdata_type = buffer_read_4(p); if (verbose > 1) fprintf(stderr, "flow_sample: packetdata_type:%u, srate:%u\n", packetdata_type, srate); switch (packetdata_type) { case 1: /* header */ protocol = buffer_read_4(p); framelen = buffer_read_4(p); snaplen = buffer_read_4(p); if (verbose > 0) fprintf(stderr, "header: framelen:%u, snaplen:%u, proto:%u\n", framelen, snaplen, protocol); /* clear aguri_flow to be filled in parsers */ memset(&aguri_flow, 0, sizeof(aguri_flow)); switch (protocol) { case 1: /* ethernet */ snapend = *p + snaplen; etherhdr_parse(*p, snaplen); break; default: if (verbose > 0) fprintf(stderr, "unknown proto:%u\n", protocol); break; } buffer_skip(p, snaplen); if (aguri_flow.agflow_fs.fs_ipver != 0) { /* flow info was filled by the parser: * for frame_length, we remove 4 bytes of FCS * to be consistent with pcap */ aguri_flow.agflow_packets = htonl(1 * srate); aguri_flow.agflow_bytes = htonl((framelen - 4) * srate); aguri_flow.agflow_first = aguri_flow.agflow_last = htonl((u_int32_t)timestamp); if (debug == 0) { if (fwrite(&aguri_flow, sizeof(aguri_flow), 1, stdout) != 1) err(1, "fwrite failed!"); } else print_flow(&aguri_flow); } break; case 2: /* IPv4 */ buffer_skip(p, 8*4); if (verbose > 0) fprintf(stderr, "packetdata IPv4 not supported\n"); break; case 3: /* IPv6 */ buffer_skip(p, 14*4); if (verbose > 0) fprintf(stderr, "packetdata IPv6 not supported\n"); break; default: if (verbose > 0) fprintf(stderr, "unknown packetdata_type:%u\n", packetdata_type); return (-1); } /* extended data */ nextended = buffer_read_4(p); if (verbose > 0) fprintf(stderr, "extended data:%u\n", nextended); for (i = 0; i < nextended; i++) { extended_type = buffer_read_4(p); switch (extended_type) { case 1: /* switch */ buffer_skip(p, 4*4); break; case 2: /* router */ addr_type = buffer_read_4(p); switch (addr_type) { case 1: /* IPv4 */ buffer_skip(p, 4); break; case 2: /* IPv6 */ buffer_skip(p, 16); break; default: return (-1); } buffer_skip(p, 2*4); break; case 3: /* gateway */ buffer_skip(p, 3*4); aspath_len = buffer_read_4(p); while (aspath_len-- > 0) { buffer_skip(p, 4); if (sflow_version >= 4) { asn_len = buffer_read_4(p); while (asn_len-- > 0) buffer_skip(p, 4); } } community_len = buffer_read_4(p); buffer_skip(p, community_len * 4); buffer_skip(p, 4); break; case 4: /* user */ str_len = buffer_read_4(p); buffer_skip(p, str_len); str_len = buffer_read_4(p); buffer_skip(p, str_len); break; case 5: /* url */ buffer_skip(p, 4); str_len = buffer_read_4(p); buffer_skip(p, str_len); break; default: return (-1); } } break; case 2: /* counter sample */ seqno = buffer_read_4(p); src_id = buffer_read_4(p); interval = buffer_read_4(p); counters_version = buffer_read_4(p); if (verbose > 0) fprintf(stderr, "counter sample: type:%u\n", counters_version); switch (counters_version) { case 1: /* generic */ buffer_skip(p, 22*4); break; case 2: /* ethernet */ buffer_skip(p, 22*4); buffer_skip(p, 13*4); break; case 3: /* tokenring */ buffer_skip(p, 22*4); buffer_skip(p, 18*4); break; case 4: /* fddi */ buffer_skip(p, 22*4); break; case 5: /* 100basevg */ buffer_skip(p, 22*4); buffer_skip(p, 20*4); break; case 6: /* wan */ buffer_skip(p, 22*4); break; case 7: /* vlan */ buffer_skip(p, 7*4); break; default: if (verbose > 0) fprintf(stderr, "counter sample %d not supported\n", counters_version); return (-1); } break; default: if (verbose > 0) fprintf(stderr, "unknown sample_type %u\n", sample_type); return (-1); } return (0); }
int parse_sflow5(const char **p) { u_int32_t format, len; u_int32_t seqno, src_id, srate, total, drops, input, output, nrecords; u_int32_t record_type, record_len; u_int32_t protocol, framelen, stripped; int snaplen, i; format = buffer_read_4(p) & 0xfff; len = buffer_read_4(p); if (verbose > 1) fprintf(stderr, "sflow5: format:%u, len:%u\n", format, len); switch (format) { case 1: /* flow sample */ seqno = buffer_read_4(p); src_id = buffer_read_4(p); srate = buffer_read_4(p); total = buffer_read_4(p); drops = buffer_read_4(p); input = buffer_read_4(p); output = buffer_read_4(p); nrecords = buffer_read_4(p); sampling_rate = srate; if (verbose > 1) fprintf(stderr, "flow sample: srate:%u, nrecords:%u\n", srate, nrecords); for (i = 0; i < nrecords; i++) { record_type = buffer_read_4(p); record_len = buffer_read_4(p); /* clear aguri_flow to be filled in parsers */ memset(&aguri_flow, 0, sizeof(aguri_flow)); switch (record_type) { case 1: /* raw packet header */ protocol = buffer_read_4(p); framelen = buffer_read_4(p); stripped = buffer_read_4(p); record_len -= 12; if (verbose > 1) fprintf(stderr, "record type: raw header: proto:%u, rlen:%u flen:%u, stripped:%u\n", protocol, record_len, framelen, stripped); switch (protocol) { case 1: /* ethernet */ /* read the first 4 bytes for snaplen */ snaplen = ntohl(*((u_int32_t *)*p)); snapend = *p + 4 + snaplen; /* frame_length holds ethernet frame * length; we remove 4 bytes of FCS to * be consistent with pcap */ frame_length = framelen - 4; etherhdr_parse(*p + 4, snaplen); break; default: break; } buffer_skip(p, record_len); break; default: if (verbose > 1) fprintf(stderr, "record type:%u, len:%u\n", record_type, record_len); buffer_skip(p, record_len); break; } /* switch */ if (aguri_flow.agflow_fs.fs_ipver != 0) { /* flow info was filled by the parser: * for frame_length, we remove 4 bytes of FCS * to be consistent with pcap */ aguri_flow.agflow_packets = htonl(1 * srate); aguri_flow.agflow_bytes = htonl((framelen - 4) * srate); aguri_flow.agflow_first = aguri_flow.agflow_last = htonl((u_int32_t)timestamp); if (debug == 0) { if (fwrite(&aguri_flow, sizeof(aguri_flow), 1, stdout) != 1) err(1, "fwrite failed!"); } else print_flow(&aguri_flow); } } /* nrecords in sample */ break; case 2: /* counter sample */ buffer_skip(p, len); break; case 3: /* expanded flow sample */ buffer_skip(p, len); break; case 4: /* expanded counter sample */ buffer_skip(p, len); break; default: buffer_skip(p, len); break; } return (0); }
/** * NOTIFY. * */ static query_state query_process_notify(query_type* q, ldns_rr_type qtype, void* engine) { engine_type* e = (engine_type*) engine; dnsin_type* dnsin = NULL; uint16_t count = 0; uint16_t rrcount = 0; uint32_t serial = 0; size_t pos = 0; char address[128]; if (!e || !q || !q->zone) { return QUERY_DISCARDED; } ods_log_assert(e->dnshandler); ods_log_assert(q->zone->name); ods_log_debug("[%s] incoming notify for zone %s", query_str, q->zone->name); if (buffer_pkt_rcode(q->buffer) != LDNS_RCODE_NOERROR || buffer_pkt_qr(q->buffer) || !buffer_pkt_aa(q->buffer) || buffer_pkt_tc(q->buffer) || buffer_pkt_rd(q->buffer) || buffer_pkt_ra(q->buffer) || buffer_pkt_ad(q->buffer) || buffer_pkt_cd(q->buffer) || buffer_pkt_qdcount(q->buffer) != 1 || buffer_pkt_ancount(q->buffer) > 1 || qtype != LDNS_RR_TYPE_SOA) { return query_formerr(q); } if (!q->zone->adinbound || q->zone->adinbound->type != ADAPTER_DNS) { ods_log_error("[%s] zone %s is not configured to have input dns " "adapter", query_str, q->zone->name); return query_notauth(q); } ods_log_assert(q->zone->adinbound->config); dnsin = (dnsin_type*) q->zone->adinbound->config; if (!acl_find(dnsin->allow_notify, &q->addr, q->tsig_rr)) { if (addr2ip(q->addr, address, sizeof(address))) { ods_log_info("[%s] unauthorized notify for zone %s from client %s: " "no acl matches", query_str, q->zone->name, address); } else { ods_log_info("[%s] unauthorized notify for zone %s from unknown " "client: no acl matches", query_str, q->zone->name); } return query_notauth(q); } ods_log_assert(q->zone->xfrd); /* skip header and question section */ buffer_skip(q->buffer, BUFFER_PKT_HEADER_SIZE); count = buffer_pkt_qdcount(q->buffer); for (rrcount = 0; rrcount < count; rrcount++) { if (!buffer_skip_rr(q->buffer, 1)) { ods_log_error("[%s] dropped packet: zone %s received bad notify " "(bad question section)", query_str, q->zone->name); return QUERY_DISCARDED; } } pos = buffer_position(q->buffer); /* examine answer section */ count = buffer_pkt_ancount(q->buffer); if (count) { if (!buffer_skip_dname(q->buffer) || !query_parse_soa(q->buffer, &serial)) { ods_log_error("[%s] dropped packet: zone %s received bad notify " "(bad soa in answer section)", query_str, q->zone->name); return QUERY_DISCARDED; } lock_basic_lock(&q->zone->xfrd->serial_lock); q->zone->xfrd->serial_notify = serial; q->zone->xfrd->serial_notify_acquired = time_now(); if (!util_serial_gt(q->zone->xfrd->serial_notify, q->zone->xfrd->serial_disk)) { ods_log_debug("[%s] ignore notify: already got zone %s serial " "%u on disk", query_str, q->zone->name, q->zone->xfrd->serial_notify); lock_basic_unlock(&q->zone->xfrd->serial_lock); goto send_notify_ok; } lock_basic_unlock(&q->zone->xfrd->serial_lock); } else { lock_basic_lock(&q->zone->xfrd->serial_lock); q->zone->xfrd->serial_notify = 0; q->zone->xfrd->serial_notify_acquired = 0; lock_basic_unlock(&q->zone->xfrd->serial_lock); } /* forward notify to xfrd */ xfrd_set_timer_now(q->zone->xfrd); dnshandler_fwd_notify(e->dnshandler, buffer_begin(q->buffer), buffer_remaining(q->buffer)); send_notify_ok: /* send notify ok */ buffer_pkt_set_qr(q->buffer); buffer_pkt_set_aa(q->buffer); buffer_pkt_set_ancount(q->buffer, 0); buffer_clear(q->buffer); /* lim = pos, pos = 0; */ buffer_set_position(q->buffer, pos); buffer_set_limit(q->buffer, buffer_capacity(q->buffer)); q->reserved_space = edns_rr_reserved_space(q->edns_rr); q->reserved_space += tsig_rr_reserved_space(q->tsig_rr); return QUERY_PROCESSED; }