Beispiel #1
0
void MethodCreator::forward_method_to(DexMethod* meth, DexMethod* smeth) {
  auto code = meth->get_code();
  if (code != nullptr) {
    meth->set_code(nullptr);
    delete code;
  }
  MethodCreator mc(meth);
  MethodBlock* block = mc.get_main_block();
  std::vector<Location> args;
  auto proto = smeth->get_proto();
  auto rtype = proto->get_rtype();
  auto meth_args = proto->get_args();
  if (meth_args != nullptr) {
    uint16_t arg_count =
        static_cast<uint16_t>(meth_args->get_type_list().size());
    for (auto i = 0; i < arg_count; ++i) {
      args.push_back(mc.get_local(i));
    }
  }
  block->invoke(smeth, args);
  if (rtype == get_void_type()) {
    block->ret_void();
  } else {
    auto ret = mc.make_local(rtype);
    block->move_result(ret, rtype);
    block->ret(ret);
  }
  mc.create();
}
Beispiel #2
0
/**
 * If the caller is in the primary DEX we want to make sure there are no
 * references in other DEXes that may cause a verification error.
 * Don't inline if so.
 */
bool MultiMethodInliner::refs_not_in_primary(DexMethod* callee) {

  const auto ok_from_primary = [&](DexType* type) {
    if (primary.count(type) == 0 && type_class_internal(type) != nullptr) {
      info.not_in_primary++;
      return false;
    }
    return true;
  };

  for (auto insn : callee->get_code()->get_instructions()) {
    if (insn->has_types()) {
      auto top = static_cast<DexOpcodeType*>(insn);
      if (!ok_from_primary(top->get_type())) {
        return true;
      }
    } else if (insn->has_methods()) {
      auto mop = static_cast<DexOpcodeMethod*>(insn);
      auto meth = mop->get_method();
      if (!ok_from_primary(meth->get_class())) {
        return true;
      }
      auto proto = meth->get_proto();
      if (!ok_from_primary(proto->get_rtype())) {
        return true;
      }
      auto args = proto->get_args();
      if (args == nullptr) continue;
      for (const auto& arg : args->get_type_list()) {
        if (!ok_from_primary(arg)) {
          return true;
        }
      }
    } else if (insn->has_fields()) {
      auto fop = static_cast<DexOpcodeField*>(insn);
      auto field = fop->field();
      if (!ok_from_primary(field->get_class()) ||
          !ok_from_primary(field->get_type())) {
        return true;
      }
    }
  }
  return false;
}
Beispiel #3
0
/**
 * Move all single impl in a single impl method signature to next pass.
 * We make a single optimization per pass over any given single impl so
 * I1, I2 and void I1.m(I2)
 * the first optimization (I1 or I2) moves the other interface to next pass.
 * That is not the case for methods on non optimizable classes, so for
 * I1, I2 and void C.m(I1, I2)
 * then m is changed in a single pass for both I1 and I2.
 */
void OptimizationImpl::drop_single_impl_collision(DexType* intf,
                                                  SingleImplData& data,
                                                  DexMethod* method) {
  auto check_type = [&](DexType* type) {
    if (type != intf && single_impls->is_single_impl(type) &&
        !single_impls->is_escaped(type)) {
      single_impls->escape_interface(type, NEXT_PASS);
      assert(optimized.find(type) == optimized.end());
    }
  };

  auto owner = method->get_class();
  if (!single_impls->is_single_impl(owner)) return;
  check_type(owner);
  auto proto = method->get_proto();
  check_type(proto->get_rtype());
  auto args_list = proto->get_args();
  for (auto arg : args_list->get_type_list()) {
    check_type(arg);
  }
}
Beispiel #4
0
int proc_query(js_string *raw, struct sockaddr_in *from, int sock) {

    q_header header; /* Header of the question */
    js_string *lookfor; /* What to look for in the big hash */
    js_string *origq; /* Original query asked by the user */
    js_string *lc; /* Lower-case version of query asked by the user */
    rr *nxstore = 0; /* A pointer to the SOA we return when we hit a
                        NXDOMAIN */
    int length, case_folded, result_code = 0, qtype;
    int has_recursive_authority = 0;
    mhash_e spot_data;
    int have_authority = 0; /* Do we have authority for this record?
                               (must be 1 to return a NXDOMAIN) */
    rr *point;
    uint32 ip;
    int desires_recursion = 0; /* Do they desire recursion? */
    char *num_string; /* The string to put the number of thread running
                         in */
    unsigned int mem_usage; /* The amount of memory a maradns process has
                               allocated */

    /* Sanity checks */
    if(js_has_sanity(raw) == JS_ERROR)
        return JS_SUCCESS;
    if(raw->unit_size != 1)
        return JS_SUCCESS;

    /* Get the header */
    if(read_hdr(raw,&header) == JS_ERROR) { /* Something went wrong,
                                               return error "Format error" */
        udperror(sock,raw,from,FORMAT_ERROR,"Couldn't get header");
        return JS_SUCCESS;
        }

    /* We only answer questions (Thanks to Roy Arends for pointing out this
       security flaw) */
    if(header.qr != 0) {
        return JS_SUCCESS;
        }

    /* We only support a qdcount of 1 */
    if(header.qdcount != 1) {
        udperror(sock,raw,from,NOT_IMPLEMENTED,"Qdcount not 1");
        return JS_SUCCESS;
        }

    /* We only support an opcode of 0 (standard query) */
    if(header.opcode != 0) {
        /* Since TinyDNS also returns NOT_IMPLEMENTED here, no need for
           a fingerprint check.  Note that tinydns, unlike MaraDNS, echos
           the question. */
        udperror(sock,raw,from,NOT_IMPLEMENTED,"non-0 opcode");
        return JS_SUCCESS;
        }

    /* Get the question from the stream */
    if(raw->unit_count < 14) {
        udperror(sock,raw,from,FORMAT_ERROR,"bad question hdr");
        return JS_SUCCESS;
        }

    /* Determine the length of the domain label in the question */
    length = dlabel_length(raw,12);
    if(length < 0 || length > 255) {
        udperror(sock,raw,from,FORMAT_ERROR,"bad question length");
        return JS_SUCCESS;
        }

    if(raw->unit_count < 16 + length) { /* 16 because 12 for the header,
                                           and 4 for the type and class */
        udperror(sock,raw,from,FORMAT_ERROR,"question doesn't fit");
        return JS_SUCCESS;
        }

    /* Return "not implemented" if the class is not 1 (Internet class) */
    if(*(raw->string + length + 14) != 0 &&
       *(raw->string + length + 15) != 1) {
        udperror(sock,raw,from,NOT_IMPLEMENTED,"Class not 1");
        return JS_ERROR;
        }

    /* Create the lookfor string, returning error if appropriate */
    if((lookfor = js_create(256,1)) == 0) {
        udperror(sock,raw,from,SERVER_FAIL,"can't create lookfor string");
        return JS_ERROR;
        }
    if((origq = js_create(256,1)) == 0) {
        js_destroy(lookfor);
        udperror(sock,raw,from,SERVER_FAIL,"can't create origq string");
        return JS_ERROR;
        }
    if((lc = js_create(256,1)) == 0) {
        js_destroy(lookfor); js_destroy(origq);
        udperror(sock,raw,from,SERVER_FAIL,"can't create lc string");
        return JS_ERROR;
        }
    if(js_set_encode(lc,JS_US_ASCII) == JS_ERROR) { /* ASCII because we
                                                     only fold the case of
                                                     A-Z */
        goto serv_fail;
        }

    /* Get the query we will look for from their raw query */
    if(js_substr(raw,lookfor,12,length + 2) == JS_ERROR) {
        goto serv_fail;
        }

    /* And copy it over to the "original query" */
    if(js_copy(lookfor,origq) == JS_ERROR) {
        goto serv_fail;
        }

    /* Get the type of query the client desires */
    qtype = get_rtype(origq);
    if(qtype == JS_ERROR) {
        goto serv_fail;
        }

    if(qtype >= 250 && qtype <= 254) { /* IXFR, AXFR, and 2 more */
        goto not_impl;
        }

    /* Return a timestamp */
    result_code = timestamp(header.id,sock,(struct sockaddr *)from,origq);
    if(result_code == JS_SUCCESS) {
        js_destroy(lookfor); js_destroy(origq); js_destroy(lc);
        return JS_SUCCESS;
        }
    if(result_code == JS_ERROR) {
        goto serv_fail;
        }

    js_destroy(lookfor); js_destroy(origq); js_destroy(lc);

    return JS_SUCCESS;

    /* Work around C's lack of error handling and garbage collection with
       gotos */
    serv_fail:
        js_destroy(lookfor);
        js_destroy(origq);
        js_destroy(lc);
        udperror(sock,raw,from,SERVER_FAIL,"serv_fail in proc_query");
        return JS_ERROR;

    not_impl:
        js_destroy(lookfor);
        js_destroy(origq);
        js_destroy(lc);
        udperror(sock,raw,from,NOT_IMPLEMENTED,"not_impl in proc_query");
        return JS_ERROR;

    }
Beispiel #5
0
int timestamp(int id, int sock, struct sockaddr *from, js_string *query) {
    unsigned char ip[4];
    unsigned char length, val;
    int counter, critter, lenl, value;
    js_string *reply;
    q_header header;

    /* Sanity checks */
    if(query->unit_size != 1)
        return JS_ERROR;
    if(query->unit_count >= query->max_count)
        return JS_ERROR;

    if(get_rtype(query) != RR_A && get_rtype(query) != RR_ANY)
        return 0;

    if(query->unit_count < 9) /* The minimum possible length for a
                                 ddip domain label */
        return 0;

    if((reply = js_create(512,1)) == 0)
        return JS_ERROR;

    /* Build up the header for this reply */
    if(id > 0 && id < 65535)
        header.id = id;
    else
        goto cleanup;

    header.qr = 1; /* Reply */
    header.opcode = 0; /* Normal DNS */
    header.aa = 0; /* DDIP to A translations are never authoritative */
    header.tc = 0; /* A labels are too short to be truncated */
    header.rd = 0; /* Recursion not desired */
    header.ra = 0; /* Recursion not available */
    header.z = 0; /* This must be 0 unless we are EDNS aware (we aren't) */
    header.rcode = 0; /* Success! */
    header.qdcount = 1;
    header.ancount = 1;
    header.nscount = 0;
    header.arcount = 0;

    /* Make a header of the reply */
    if(make_hdr(&header,reply) == JS_ERROR)
        goto cleanup;

    /* Add the question they asked to the reply */
    if(js_append(query,reply) == JS_ERROR)
        goto cleanup;

    /* Add the class (in) to the answer */
    if(js_adduint16(reply,1) == JS_ERROR)
        goto cleanup;

    /* Make sure the answer is an A record type */
    if(change_rtype(query,RR_A) == JS_ERROR)
        goto cleanup;

    /* We will now add out manufactured A reply */
    if(js_append(query,reply) == JS_ERROR)
        goto cleanup;
    /* Append the class (in) to the answer */
    if(js_adduint16(reply,1) == JS_ERROR)
        goto cleanup;
    /* Append a bogus TTL to the answer */
    /*if(js_adduint32(reply,19770616) == JS_ERROR)*/
    if(js_adduint32(reply,69) == JS_ERROR)
        goto cleanup;
    /* Add the rdlength to the answer */
    if(js_adduint16(reply,4) == JS_ERROR)
        goto cleanup;
    /* Add the actual 4-byte reply to the answer */
    time((time_t *)&ip); /* Endian dependent, but doesn't matter */
    for(counter = 0; counter < 4; counter++) {
        if(js_addbyte(reply,ip[counter]) == JS_ERROR)
            goto cleanup;
        }

    /* Send the reply out */
    sendto(sock,reply->string,reply->unit_count,0,from,
           sizeof(struct sockaddr));

    /* And, we are done */
    js_destroy(reply);
    return JS_SUCCESS;

    /* We use gotos to work around C's lack of error trapping */
    cleanup:
        js_destroy(reply);
        return JS_ERROR;

    }
Beispiel #6
0
int udpsuccess(rr *where, int id, int sock, struct sockaddr_in *client,
               js_string *query, void **rotate_point, int show_cname_a,
               int rd_val, conn *ect, int force_authoritative,int ra_value) {
    js_string *most = 0; /* Most of the data */
    js_string *ar = 0; /* Then the additional records */

    uint16 first_rr_type;
    int in_ns = 0;
    int ns_delegation = 0;
    int length_save;
    int len_inet = sizeof(struct sockaddr);
    rr *ipwhere = 0;
    /* The following are used for round robin rotation */
    rr *rotate_1st = 0, *rotate_2nd = 0, *rotate_last = 0;
    /* Counters in ensure that we don't give out more than the maximum
       number of A, AN (A), chain, or total records */
    int a_count = 0, an_count = 0;
    fila *zap_point;
    /* These two variables are added to handle PTR records */
    int seen_ptr_record = 0;
    rr *top = where;
    int is_auth = 0;
    int compress_error_happened = 0;

    q_header header;

    /* Initialize the total count */
    total_count = 0;
    /* Initialize the js_string objects */
    if((most = js_create(1024,1)) == 0)
        return JS_ERROR;
#ifdef AUTHONLY
    if((ar = js_create(5000,1)) == 0) {
        js_destroy(most);
        return JS_ERROR;
        }
#else
    if((ar = js_create(600,1)) == 0) {
        js_destroy(most);
        return JS_ERROR;
        }
#endif

    /* Make the header a placeholder for now */
    init_header(&header);
    header.id = id;
    if(make_hdr(&header,most) == JS_ERROR)
        goto giveerror;

    /* Sanity check */
    if(where == 0) {
        goto giveerror;
        }
    if(where->query == 0) {
        goto giveerror;
        }
    if(js_has_sanity(where->query) == JS_ERROR) {
        goto giveerror;
        }
    if(where->data == 0) {
        goto giveerror;
        }
    if(js_has_sanity(where->data) == JS_ERROR) {
        goto giveerror;
        }
    if(js_has_sanity(query) == JS_ERROR) {
        goto giveerror;
        }
    first_rr_type = get_rtype(query);

    /* Somewhat hacky way to determine that this is a NS delegation */
    ns_delegation = 0;
    if(first_rr_type != RR_NS && where->rr_type == RR_NS) {
        ns_delegation = 1;
        }

    /* With the cache, this may be a rtype of RR_ANY.  We need to handle
       this special case */

    /* We have to add this header here--authoritative depends on the
       authorative status of the first record we find */
    if(force_authoritative != 1) {
        header.aa = where->authoritative;
        }
    else {
        header.aa = 1;
        }
    is_auth = where->authoritative;

    /* The data must be between 0 and 65535 bytes in length (16-bit
       unsigned value) */
    if(where->data->unit_count < 0 || where->data->unit_count > 65535) {
        goto giveerror;
        }

    /* Append the question to the answer */
    if(js_append(query,most) == JS_ERROR) {
        goto giveerror;
        }

    /* Append the class (in) to the answer */
    if(js_adduint16(most,1) == JS_ERROR) {
        goto giveerror;
        }

    /* We will increment the ancount, nscount, an arcount, starting at 0 */
    header.ancount = 0;
    header.nscount = 0;
    header.arcount = 0;

    /* Initialize some temporary pointers used for round robin rotation */
    rotate_1st = where;
    rotate_2nd = where->next;
    /* We do not round robin if there is but a single record */
    if(rotate_2nd != 0 && first_rr_type != RR_NS &&
       rotate_2nd->rr_type == RR_NS)
        rotate_2nd = 0;

    /* OK, we now add the answers */
    while(where != 0) {
        /* Increment the number of answers -or- ns records */
        if(first_rr_type != RR_NS && where->rr_type == RR_NS && in_ns == 0) {
            /* Due to the data structure MaraDNS currently uses, the behavior
               is buggy if we round-robin rotate data when we allow more than
               one additional record to be create per answer/authoritative
               record.  */
            if(rotate_2nd != 0 && max_ar_chain == 1 && rotate_last != 0 &&
               first_rr_type != RR_NS) {
                /* If it makes sense to do a round-robin rotation, do so.
                 * Make rotate_1st, which was the first record, the last
                 * record; make rotate_2nd, which was the second record,
                 * the first record; and make rotate_last, which is the last
                 * record in the chain, have its next record be the first
                 * record */
                rotate_1st->next = where;
                rotate_last->next = rotate_1st;
                *rotate_point = rotate_2nd;
                rotate_2nd = 0; /* Make sure we can not rotate again */
                }
            in_ns = 1;
            a_count = 0; /* The NS chain is different than the AN
                            chain of answers: If we only allow eight
                            answers in a chain, we can still have 16
                            answers: 8 records in the answer section then
                            8 records in the authority section */
            }
        if(a_count < max_chain && total_count < max_total && (in_ns == 0
           || is_auth == 1 || ns_delegation == 1)) {
            a_count++;
            total_count++;
            if(!in_ns) {
                header.ancount++;
                }
            else {
                header.nscount++;
                }
            /* Append the name for this answer to the answer */
            if(js_append(where->query,most) == JS_ERROR)
                goto giveerror;
            /* Append the class (in) to the answer */
            if(js_adduint16(most,1) == JS_ERROR)
                goto giveerror;
            /* Append the ttl to the answer */
            if(js_adduint32(most,determine_ttl(where->expire,where->ttl))
               == JS_ERROR)
                goto giveerror;
            /* Add the rdlength to the answer */
            if(js_adduint16(most,where->data->unit_count) == JS_ERROR)
                goto giveerror;
            /* Add the record itself to the answer */
            if(js_append(where->data,most) == JS_ERROR)
                goto giveerror;
            /* If there is an IP, and this is *not* a CNAME record,
               append the IP of the answer to the AR section */
            if(where->ip != 0 && where->rr_type != RR_CNAME) {
                /* Reset the number of an records we have seen */
                an_count = 0;
                ipwhere = where->ip;
                while(ipwhere != 0 && ipwhere->rr_type != RR_NS) {
                    /* We only show a given additional record once */
                    if(ipwhere->seen == 1) { /* If we have displayed this RR
                                                already */
                        /* Go to the next link in the linked list */
                        ipwhere = ipwhere->next;
                        continue;
                        }
                    /* Stop showing records if we have exceeded our limit */
                    if(an_count >= max_ar_chain || total_count >= max_total)
                        break;
                    an_count++;
                    total_count++;
                    /* Increment the number of additional records */
                    header.arcount++;
                    /* Append the name for this answer to the ip */
                    if(js_append(ipwhere->query,ar) == JS_ERROR)
                        goto giveerror;
                    /* Append the class (in) to the ip */
                    if(js_adduint16(ar,1) == JS_ERROR)
                        goto giveerror;
                    /* Append the TTL to the ip */
                    if(js_adduint32(ar,
                      determine_ttl(ipwhere->expire,ipwhere->ttl)) == JS_ERROR)
                        goto giveerror;
                    /* Add the rdlength to the ip */
                    if(js_adduint16(ar,ipwhere->data->unit_count) == JS_ERROR)
                        goto giveerror;
                    /* Add the record itself to the ip */
                    if(js_append(ipwhere->data,ar) == JS_ERROR)
                        goto giveerror;
                    /* Mark that we have seen this record already */
                    if(seenlist_where < 250) {
                        ipwhere->seen = 1;
                        seenlist[seenlist_where] = ipwhere;
                        seenlist_where++;
                        }
                    /* Go to the next link in the linked list */
                    ipwhere = ipwhere->next;
                    }
                }
#ifdef IPV6
              if(where->ip6 != 0 && where->rr_type != RR_CNAME) {
                /* Reset the number of an records we have seen */
                an_count = 0;
                ipwhere = where->ip6;
                while(ipwhere != 0 && ipwhere->rr_type != RR_NS) {
                    /* We only show a given additional record once */
                    if(ipwhere->seen == 1) { /* If we have displayed this RR
                                                already */
                        /* Go to the next link in the linked list */
                        ipwhere = ipwhere->next;
                        continue;
                        }
                    /* Stop showing records if we have exceeded our limit */
                    if(an_count >= max_ar_chain || total_count >= max_total)
                        break;
                    an_count++;
                    total_count++;
                    /* Increment the number of additional records */
                    header.arcount++;
                    /* Append the name for this answer to the ip */
                    if(js_append(ipwhere->query,ar) == JS_ERROR)
                        goto giveerror;
                    /* Append the class (in) to the ip */
                    if(js_adduint16(ar,1) == JS_ERROR)
                        goto giveerror;
                    /* Append the TTL to the ip */
                    if(js_adduint32(ar,
                      determine_ttl(ipwhere->expire,ipwhere->ttl)) == JS_ERROR)
                        goto giveerror;
                    /* Add the rdlength to the ip */
                    if(js_adduint16(ar,ipwhere->data->unit_count) == JS_ERROR)
                        goto giveerror;
                    /* Add the record itself to the ip */
                    if(js_append(ipwhere->data,ar) == JS_ERROR)
                        goto giveerror;
                    /* Mark that we have seen this record already */
                    if(seenlist_where < 250) {
                        ipwhere->seen = 1;
                        seenlist[seenlist_where] = ipwhere;
                        seenlist_where++;
                        }
                    /* Go to the next link in the linked list */
                    ipwhere = ipwhere->next;
                    }
                }
#endif
            /* This code is only used by the recursive code; the
             * authoritative code now uses where->list to attach
             * a CNAME record to its corresponding rddata
             * If there is an IP, and this is a CNAME record, and
             * show_cname_a is set to one (argument to this function)
             * append the IP in question to the answer section */
            if(where->ip != 0 && where->rr_type == RR_CNAME
               && show_cname_a == RR_A && where->list == 0) {
                /* Reset the number of an records we have seen */
                an_count = 0;
                ipwhere = where->ip;
                while(ipwhere != 0 && ipwhere->rr_type != RR_NS) {
                    /* We only show a given additional record once */
                    if(ipwhere->seen == 1) { /* If we have displayed this RR
                                                already */
                        /* Go to the next link in the linked list */
                        ipwhere = ipwhere->next;
                        continue;
                        }
                    /* If the IP in question is 255.255.255.255, we do
                       not show the data in question */
                    if(ipwhere->rr_type == RR_A &&
                       ipwhere->data->unit_count == 4 &&
                       *(ipwhere->data->string) == 0xff &&
                       *(ipwhere->data->string + 1) == 0xff &&
                       *(ipwhere->data->string + 2) == 0xff &&
                       *(ipwhere->data->string + 3) == 0xff) {
                        ipwhere = ipwhere->next;
                        continue;
                        }
                    /* Stop showing records if we have exceeded our limit */
                    if(an_count >= max_ar_chain || total_count >= max_total)
                        break;
                    an_count++;
                    total_count++;
                    /* Increment the number of answer records */
                    header.ancount++;
                    /* Append the name for this answer to the ip */
                    if(js_append(ipwhere->query,most) == JS_ERROR)
                        goto giveerror;
                    /* Append the class (in) to the ip */
                    if(js_adduint16(most,1) == JS_ERROR)
                        goto giveerror;
                    /* Append the TTL to the ip */
                    if(js_adduint32(most,
                      determine_ttl(ipwhere->expire,ipwhere->ttl)) == JS_ERROR)
                        goto giveerror;
                    /* Add the rdlength to the ip */
                    if(js_adduint16(most,ipwhere->data->unit_count)
                       == JS_ERROR)
                        goto giveerror;
                    /* Add the record itself to the ip */
                    if(js_append(ipwhere->data,most) == JS_ERROR)
                        goto giveerror;
                    /* Mark that we have seen this record already */
                    if(seenlist_where < 250) {
                        ipwhere->seen = 1;
                        seenlist[seenlist_where] = ipwhere;
                        seenlist_where++;
                        }
                    /* Go to the next link in the linked list */
                    ipwhere = ipwhere->next;
                    }
                }
            /* Again, this code is only used by the recursive half.
             * The authoritative half now has a way of showing the record
             * that correspods to any RR type attached to a CNAME record.
             *
             * If there is an PTR, and this is a CNAME record, and
             * show_cname_a is set to one (argument to this function)
             * append the IP in question to the answer section */
            else if(top->ptr != 0 && top->rr_type == RR_CNAME
               && show_cname_a == RR_PTR && seen_ptr_record == 0
               && where->list == 0) {
                    /* Mark that we have seen this record already */
                    seen_ptr_record = 1;
                    /* Increment the total number of answers seen */
                    total_count++;
                    /* Increment the number of answer records */
                    header.ancount++;
                    /* Append the name for this answer to the ip */
                    if(js_append(top->data,most) == JS_ERROR)
                        goto giveerror;
                    /* Append the type for this query */
                    if(js_adduint16(most,RR_PTR) == JS_ERROR)
                        goto giveerror;
                    /* Append the class (in) to the ip */
                    if(js_adduint16(most,1) == JS_ERROR)
                        goto giveerror;
                    /* Append the TTL to the ip */
                    if(js_adduint32(most,
                      determine_ttl(top->expire,top->ttl)) == JS_ERROR)
                        goto giveerror;
                    /* Add the rdlength to the ip */
                    if(js_adduint16(most,top->ptr->unit_count)
                       == JS_ERROR)
                        goto giveerror;
                    /* Add the record itself to the ip */
                    if(js_append(top->ptr,most) == JS_ERROR)
                        goto giveerror;
               }
            /* This code is currently only used by the authoritative half;
             * bascially, if we see a CNAME record we see if we have a list
             * which lists all record types for the host name the CNAME
             * is pointing to.  We used this list to add, in the answer
             * section, the answer the person is looking for. */
            else if(where->rr_type == RR_CNAME && where->list != 0) {
               struct rr_list *any_list = 0;
               uint16 this_rr_type = 0;
               int counter = 0;
               /* Start at the top of list of RRs */
               any_list = where->list;
               this_rr_type = first_rr_type; /* The rtype they want */
               /* We go down the list until we find the desired rr_type */
               for(counter = 0; counter < 1000; counter++) {
                   if(any_list->rr_type == this_rr_type) {
                       break;
                       }
                   if(any_list->next == 0) {
                       break;
                       }
                   any_list = any_list->next;
                   }
               /* If we found the desired record type... */
               if(any_list->rr_type == this_rr_type && any_list->data != 0) {
                   rr *answer;
                   int counter = 0;
                   answer = any_list->data;
                   while(answer != 0 && answer->rr_type == this_rr_type &&
                         counter < 100) {
                       /* Then we add this information to the AN section of
                        * the answer */
                       /* Increase the number of answers in the header */
                       header.ancount++;
                       /* RFC 1035 section 3.2.1 header */
                       /* Name + Type */
                       if(js_append(answer->query,most) == JS_ERROR)
                           goto giveerror;
                       /* Class */
                       if(js_adduint16(most,1) == JS_ERROR)
                           goto giveerror;
                       /* TTL */
                       /* Since this currently only returns authoritative
                        * data, answer->expire should always be zero and
                        * determine_ttl is a redundant call.  However, we'll
                        * keep it that way just in case things change in
                        * the future */
                       if(js_adduint32(most,determine_ttl(answer->expire,
                              answer->ttl)) == JS_ERROR)
                           goto giveerror;
                       /* Rdlength */
                       if(answer->data == 0)
                           goto giveerror;
                       if(answer->data->unit_count < 0 ||
                          answer->data->unit_count > 65535)
                           goto giveerror;
                       if(js_adduint16(most,answer->data->unit_count) ==
                           JS_ERROR)
                           goto giveerror;
                       /* rdata */
                       if(js_append(answer->data,most) == JS_ERROR)
                           goto giveerror;
                       counter++;
                       answer = answer->next;
                       }
                   }
               }
            }
        /* Go on to the next record in the linked list */
        rotate_last = where;
        where = where->next;
        /* If it makes sense to do a round-robin rotation, do so */
        if(where == 0 && rotate_2nd != 0 && max_ar_chain == 1 &&
           first_rr_type != RR_NS) {
            /* For records in the cache, we need to make sure that
               the custodian properly points to the first record
               in the chain or we will leak memory */
            if(rotate_1st->zap != 0) {
                zap_point = rotate_1st->zap;
                rotate_1st->zap = 0;
                rotate_2nd->zap = zap_point;
                zap_point->record = rotate_2nd;
                }
            rotate_1st->next = 0;
            rotate_last->next = rotate_1st;
            *rotate_point = rotate_2nd;
            rotate_2nd = 0; /* Make sure we can not rotate again */
            }
        }

    /* Customize the header */
    /* header.id already set */
    header.qr = 1;
    header.opcode = 0;
    header.tc = 0;
    header.rd = rd_val; /* RDBUG udpsuccess */
    header.ra = calc_ra_value(ra_value);
    header.z = 0;
    header.rcode = 0; /* No error */
    header.qdcount = 1;

    /* OBhack: Tack on the header at the beginning without molesting the
       rest of the string */
    length_save = most->unit_count;
    make_hdr(&header,most);
    most->unit_count = length_save;

    /* Add the ar records to the end */
    if(js_append(ar,most) == JS_ERROR) {
        goto giveerror;
        }

    compress_error_happened = 0;
    if(compress_data(most,ar) == JS_ERROR) {
        compress_error_happened = 1;
    }

    /* Check to make sure the data fits in under 512 bytes (4096 bytes
     * if it's a long_packet_ipv4 address) truncate if not */
    if(ar->unit_count > 512 || compress_error_happened == 1) {
        int x;
#ifdef AUTHONLY

        /* If this is an ipv4 connection and we didn't get a compress error */
        if(ect->type == 4 && compress_error_happened == 0) {
            struct sockaddr_in *dq;
            uint32 ip_test;
            dq = (struct sockaddr_in *)(ect->d);
            ip_test = ntohl(dq->sin_addr.s_addr);
            /* See if we are allowed to send a long packet up to
             * 4096 bytes to this ip address */
            if(check_ipv4_acl(ip_test,long_packet) == 1) {
                if(ar->unit_count < 4096) {
                    goto long_packet_ok;
                    }
                }
            }
#endif

        for(x = 0; x < 20; x++) {
                compress_error_happened = 0;
                /* OK, try to squeeze the packet in by removing records */
                if(squeeze_to_fit(most) == 0) {
                        goto giveerror;
                }
                if(most->unit_count > 12) {
                        if(compress_data(most,ar) == JS_ERROR) {
                                compress_error_happened = 1;
                        }
                        if(ar->unit_count <= 512 &&
                            compress_error_happened == 0) {
                                break;
                        }
                } else if(most->unit_count == 12) {
                        if(js_copy(most,ar) == JS_ERROR) {
                                goto giveerror;
                        }
                } else {
                        goto giveerror;
                }
            }
        }

#ifdef AUTHONLY
long_packet_ok:
#endif

    if(compress_error_happened == 1) {
        goto giveerror;
    }

    /* Success! Put out the good data */
    if(ect == 0) {
        sendto(sock,ar->string,ar->unit_count,0,
            (struct sockaddr *)client,len_inet);
    } else {
        mara_send(ect,sock,ar);
    }

    js_destroy(most);
    js_destroy(ar);

    /* Clean up the seenlist_where list */
    while(seenlist_where > 0) {
        seenlist_where--;
        if(seenlist[seenlist_where] != 0)
            (seenlist[seenlist_where])->seen = 0;
        }

    return JS_SUCCESS;

    /* We use gotos to make up for C's lack of error trapping */
    giveerror:
        js_destroy(ar);
        udperror(sock,most,client,0,SERVER_FAIL,"giveerror in udpsuccess",2,
                        rd_val,ect,1);
        js_destroy(most);

        /* Clean up the seenlist_where list */
        while(seenlist_where > 0) {
            seenlist_where--;
            if(seenlist[seenlist_where] != 0)
                (seenlist[seenlist_where])->seen = 0;
            }
        return JS_ERROR;

    }