static int append_qsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup) { unsigned char *buf, *start, *last; int n; buf = *bufp; start = buf - at; last = buf + left; for(n = 0; n < src->count; ++n) { jdns_packet_question_t *q = (jdns_packet_question_t *)src->item[n]; if(!writelabel(q->qname, buf - start, last - buf, &buf, lookup)) goto error; if(buf + 4 > last) goto error; short2net(q->qtype, &buf); short2net(q->qclass, &buf); } *bufp = buf; return 1; error: return 0; }
static int append_rrsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup) { unsigned char *buf, *start, *last, *rdlengthp; int n, i, rdlength; buf = *bufp; start = buf - at; last = buf + left; for(n = 0; n < src->count; ++n) { jdns_packet_resource_t *r = (jdns_packet_resource_t *)src->item[n]; if(!writelabel(r->qname, buf - start, last - buf, &buf, lookup)) goto error; if(buf + 10 > last) goto error; short2net(r->qtype, &buf); short2net(r->qclass, &buf); long2net(r->ttl, &buf); // skip over rdlength rdlengthp = buf; buf += 2; // play write log rdlength = 0; for(i = 0; i < r->writelog->count; ++i) { jdns_packet_write_t *write = (jdns_packet_write_t *)r->writelog->item[i]; if(write->type == JDNS_PACKET_WRITE_RAW) { if(buf + write->value->size > last) goto error; memcpy(buf, write->value->data, write->value->size); buf += write->value->size; } else // JDNS_PACKET_WRITE_NAME { if(!writelabel(write->value, buf - start, last - buf, &buf, lookup)) goto error; } } i = buf - rdlengthp; // should be rdata size + 2 short2net((unsigned short int)(i - 2), &rdlengthp); } *bufp = buf; return 1; error: return 0; }
// nasty, convert host into label using compression int _host(struct message *m, unsigned char **bufp, unsigned char *name) { unsigned char label[256], *l; int len = 0, x = 1, y = 0, last = 0; if(name == 0) return 0; // make our label while(name[y]) { if(name[y] == '.') { if(!name[y+1]) break; label[last] = x - (last + 1); last = x; }else{ label[x] = name[y]; } if(x++ == 255) return 0; y++; } label[last] = x - (last + 1); if(x == 1) x--; // special case, bad names, but handle correctly len = x + 1; label[x] = 0; // always terminate w/ a 0 // double-loop checking each label against all m->_labels for match for(x = 0; label[x]; x += label[x] + 1) { for(y = 0; m->_labels[y]; y++) if(_lmatch(m,label+x,m->_labels[y])) { // matching label, set up pointer l = label + x; short2net(m->_labels[y] - m->_packet, &l); label[x] |= 0xc0; len = x + 2; break; } if(label[x] & 0xc0) break; } // copy into buffer, point there now memcpy(*bufp,label,len); l = *bufp; *bufp += len; // for each new label, store it's location for future compression for(x = 0; l[x]; x += l[x] + 1) { if(l[x] & 0xc0) break; if(m->_label + 1 >= 19) break; m->_labels[m->_label++] = l + x; } return len; }
int jdns_packet_export(jdns_packet_t *a, int maxsize) { unsigned char *block = 0; unsigned char *buf, *last; unsigned char c; int size; jdns_list_t *lookup = 0; // to hold jdns_packet_label_t // clear out any existing raw data before we begin if(a->raw_data) { jdns_free(a->raw_data); a->raw_data = 0; a->raw_size = 0; } // preallocate size = maxsize; block = (unsigned char *)jdns_alloc(size); memset(block, 0, size); buf = block; last = block + size; if(size < 12) goto error; short2net(a->id, &buf); if(a->opts.qr) buf[0] |= 0x80; c = (unsigned char)a->opts.opcode; buf[0] |= c << 3; if(a->opts.aa) buf[0] |= 0x04; if(a->opts.tc) buf[0] |= 0x02; if(a->opts.rd) buf[0] |= 0x01; if(a->opts.ra) buf[1] |= 0x80; c = (unsigned char)a->opts.z; buf[1] |= c << 4; c = (unsigned char)a->opts.rcode; buf[1] |= c; buf += 2; short2net((unsigned short int)a->questions->count, &buf); short2net((unsigned short int)a->answerRecords->count, &buf); short2net((unsigned short int)a->authorityRecords->count, &buf); short2net((unsigned short int)a->additionalRecords->count, &buf); // append sections lookup = jdns_list_new(); lookup->autoDelete = 1; if(!append_qsection(a->questions, buf - block, last - buf, &buf, lookup)) goto error; if(!append_rrsection(a->answerRecords, buf - block, last - buf, &buf, lookup)) goto error; if(!append_rrsection(a->authorityRecords, buf - block, last - buf, &buf, lookup)) goto error; if(!append_rrsection(a->additionalRecords, buf - block, last - buf, &buf, lookup)) goto error; // done with all sections jdns_list_delete(lookup); // condense size = buf - block; block = (unsigned char *)jdns_realloc(block, size); // finalize a->qdcount = a->questions->count; a->ancount = a->answerRecords->count; a->nscount = a->authorityRecords->count; a->arcount = a->additionalRecords->count; a->raw_data = block; a->raw_size = size; return 1; error: jdns_list_delete(lookup); if(block) jdns_free(block); return 0; }
// lookup list is made of jdns_packet_labels static int writelabel(const jdns_string_t *name, int at, int left, unsigned char **bufp, jdns_list_t *lookup) { unsigned char label[MAX_LABEL_LENGTH]; int n, i, len; unsigned char *l; unsigned char *ref; int refsize; len = name_to_label(name, label); if(len == -1) return 0; ref = *bufp - at; refsize = at + left; for(n = 0; label[n]; n += label[n] + 1) { for(i = 0; i < lookup->count; ++i) { jdns_packet_label_t *pl = (jdns_packet_label_t *)lookup->item[i]; if(matchlabel(label + n, len - n, pl->value->data, pl->value->size, ref, refsize, 8, 8)) { // set up a pointer right here, overwriting // the length byte and the first content // byte of this section within 'label'. // this is safe, because the length value // will always be greater than zero, // ensuring we have two bytes available to // use. l = label + n; short2net((unsigned short int)pl->offset, &l); label[n] |= 0xc0; len = n + 2; // cut things short break; } } if(label[n] & 0xc0) // double loop, so break again break; } if(left < len) return 0; // copy into buffer, point there now memcpy(*bufp, label, len); l = *bufp; *bufp += len; // for each new label, store its location for future compression for(n = 0; l[n]; n += l[n] + 1) { jdns_string_t *str; jdns_packet_label_t *pl; if(l[n] & 0xc0) break; pl = jdns_packet_label_new(); str = jdns_string_new(); jdns_string_set(str, l + n, len - n); pl->offset = l + n - ref; pl->value = str; jdns_list_insert(lookup, pl, -1); } return 1; }