int ares_create_query(const char *name, int dnsclass, int type, unsigned short id, int rd, unsigned char **buf, int *buflen, int max_udp_size) { int len; unsigned char *q; const char *p; /* Set our results early, in case we bail out early with an error. */ *buflen = 0; *buf = NULL; /* Compute the length of the encoded name so we can check buflen. * Start counting at 1 for the zero-length label at the end. */ len = 1; for (p = name; *p; p++) { if (*p == '\\' && *(p + 1) != 0) p++; len++; } /* If there are n periods in the name, there are n + 1 labels, and * thus n + 1 length fields, unless the name is empty or ends with a * period. So add 1 unless name is empty or ends with a period. */ if (*name && *(p - 1) != '.') len++; /* Immediately reject names that are longer than the maximum of 255 * bytes that's specified in RFC 1035 ("To simplify implementations, * the total length of a domain name (i.e., label octets and label * length octets) is restricted to 255 octets or less."). We aren't * doing this just to be a stickler about RFCs. For names that are * too long, 'dnscache' closes its TCP connection to us immediately * (when using TCP) and ignores the request when using UDP, and * BIND's named returns ServFail (TCP or UDP). Sending a request * that we know will cause 'dnscache' to close the TCP connection is * painful, since that makes any other outstanding requests on that * connection fail. And sending a UDP request that we know * 'dnscache' will ignore is bad because resources will be tied up * until we time-out the request. */ if (len > MAXCDNAME) return ARES_EBADNAME; *buflen = len + HFIXEDSZ + QFIXEDSZ + (max_udp_size ? EDNSFIXEDSZ : 0); *buf = malloc(*buflen); if (!*buf) return ARES_ENOMEM; /* Set up the header. */ q = *buf; memset(q, 0, HFIXEDSZ); DNS_HEADER_SET_QID(q, id); DNS_HEADER_SET_OPCODE(q, QUERY); if (rd) { DNS_HEADER_SET_RD(q, 1); } else { DNS_HEADER_SET_RD(q, 0); } DNS_HEADER_SET_QDCOUNT(q, 1); if (max_udp_size) { DNS_HEADER_SET_ARCOUNT(q, 1); } /* A name of "." is a screw case for the loop below, so adjust it. */ if (strcmp(name, ".") == 0) name++; /* Start writing out the name after the header. */ q += HFIXEDSZ; while (*name) { if (*name == '.') return ARES_EBADNAME; /* Count the number of bytes in this label. */ len = 0; for (p = name; *p && *p != '.'; p++) { if (*p == '\\' && *(p + 1) != 0) p++; len++; } if (len > MAXLABEL) return ARES_EBADNAME; /* Encode the length and copy the data. */ *q++ = (unsigned char)len; for (p = name; *p && *p != '.'; p++) { if (*p == '\\' && *(p + 1) != 0) p++; *q++ = *p; } /* Go to the next label and repeat, unless we hit the end. */ if (!*p) break; name = p + 1; } /* Add the zero-length label at the end. */ *q++ = 0; /* Finish off the question with the type and class. */ DNS_QUESTION_SET_TYPE(q, type); DNS_QUESTION_SET_CLASS(q, dnsclass); if (max_udp_size) { q += QFIXEDSZ; memset(q, 0, EDNSFIXEDSZ); q++; DNS_RR_SET_TYPE(q, T_OPT); DNS_RR_SET_CLASS(q, max_udp_size); } return ARES_SUCCESS; }
int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id, int rd, unsigned char **buf, int *buflen) { int len; unsigned char *q; const char *p; /* Compute the length of the encoded name so we can check buflen. * Start counting at 1 for the zero-length label at the end. */ len = 1; for (p = name; *p; p++) { if (*p == '\\' && *(p + 1) != 0) p++; len++; } /* If there are n periods in the name, there are n + 1 labels, and * thus n + 1 length fields, unless the name is empty or ends with a * period. So add 1 unless name is empty or ends with a period. */ if (*name && *(p - 1) != '.') len++; *buflen = len + HFIXEDSZ + QFIXEDSZ; *buf = malloc(*buflen); if (!*buf) return ARES_ENOMEM; /* Set up the header. */ q = *buf; memset(q, 0, HFIXEDSZ); DNS_HEADER_SET_QID(q, id); DNS_HEADER_SET_OPCODE(q, QUERY); DNS_HEADER_SET_RD(q, (rd) ? 1 : 0); DNS_HEADER_SET_QDCOUNT(q, 1); /* A name of "." is a screw case for the loop below, so adjust it. */ if (strcmp(name, ".") == 0) name++; /* Start writing out the name after the header. */ q += HFIXEDSZ; while (*name) { if (*name == '.') return ARES_EBADNAME; /* Count the number of bytes in this label. */ len = 0; for (p = name; *p && *p != '.'; p++) { if (*p == '\\' && *(p + 1) != 0) p++; len++; } if (len > MAXLABEL) return ARES_EBADNAME; /* Encode the length and copy the data. */ *q++ = len; for (p = name; *p && *p != '.'; p++) { if (*p == '\\' && *(p + 1) != 0) p++; *q++ = *p; } /* Go to the next label and repeat, unless we hit the end. */ if (!*p) break; name = p + 1; } /* Add the zero-length label at the end. */ *q++ = 0; /* Finish off the question with the type and class. */ DNS_QUESTION_SET_TYPE(q, type); DNS_QUESTION_SET_CLASS(q, dnsclass); return ARES_SUCCESS; }
int evdns_make_query(char *domain, int dnsclass, int type, unsigned int id, int rd, unsigned char *buf) { unsigned char *p = NULL, *q = NULL, *s = NULL, *name = NULL; int buflen = 0, len = 0; if(domain) { p = name = (unsigned char *)domain; while(*p != '\0') { if(*p++ != '\\')++len; } if(*(p-1) != '.') ++len; //add end \0 size len++; if(len > MAXCDNAME) return -1; buflen = len + HFIXEDSZ + QFIXEDSZ; q = buf; memset(q, 0, buflen); DNS_HEADER_SET_QID(q, id); DNS_HEADER_SET_OPCODE(q, 0); if(rd) { DNS_HEADER_SET_RD(q, 1); } else { DNS_HEADER_SET_RD(q, 0); } DNS_HEADER_SET_QDCOUNT(q, 1); if (*name == '.' && *(name + 1) == '\0') name++; /* Start writing out the name after the header. */ q += HFIXEDSZ; p = name; //fprintf(stdout, "%d:dnsquery:%d:%d\n", __LINE__, (q - buf), buflen); do { s = q++; len = 0; while(*p != '.' && *p != '\0') { if (*p == '\\') ++p; else{*q++ = *p++; len++;} } *s = (unsigned char)len; if(*p != '\0')++p; }while(*p != '\0'); *q++ = 0; /* Finish off the question with the type and class. */ DNS_QUESTION_SET_TYPE(q, type); DNS_QUESTION_SET_CLASS(q, dnsclass); /* if((tmpfd = open("/tmp/buf.txt", O_CREAT|O_RDWR, 0644)) > 0) { write(tmpfd, buf, buflen); close(tmpfd); } fprintf(stdout, "%d:dnsquery:%d:%d\n", __LINE__, (q - buf), buflen); */ return buflen; } return 0; }