+static int parse_request(unsigned char *buf, int len,
+ char *name, unsigned int size)
+{
+ struct domain_hdr *hdr = (void *) buf;
+ uint16_t qdcount = ntohs(hdr->qdcount);
+ unsigned char *ptr;
+ char *last_label = NULL;
+ int label_count = 0;
+ unsigned int remain, used = 0;
+
+ if (len < 12)
+ return -EINVAL;
+
+ DBG("id 0x%04x qr %d opcode %d qdcount %d",
+ hdr->id, hdr->qr, hdr->opcode, qdcount);
+
+ if (hdr->qr != 0 || qdcount != 1)
+ return -EINVAL;
+
+ memset(name, 0, size);
+
+ ptr = buf + 12;
+ remain = len - 12;
+
+ while (remain > 0) {
+ uint8_t len = *ptr;
+
+ if (len == 0x00) {
+ if (label_count > 0)
+ last_label = (char *) (ptr + 1);
+ break;
+ }
+
+ label_count++;
+
+ if (used + len + 1 > size)
+ return -ENOBUFS;
+
+ strncat(name, (char *) (ptr + 1), len);
+ strcat(name, ".");
+
+ used += len + 1;
+
+ ptr += len + 1;
+ remain -= len + 1;
+ }
+
+ DBG("query %s (%d labels)", name, label_count);
+
+ return 0;
+}
+
+static void send_response(int sk, unsigned char *buf, int len,
+ const struct sockaddr *to, socklen_t tolen)
+{
+ struct domain_hdr *hdr = (void *) buf;
+ int err;
+
+ if (len < 12)
+ return;
+
+ DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
+
+ hdr->qr = 1;
+ hdr->rcode = 2;
+
+ hdr->ancount = 0;
+ hdr->nscount = 0;
+ hdr->arcount = 0;
+
+ err = sendto(sk, buf, len, 0, to, tolen);
+}
+
+static int append_query(unsigned char *buf, unsigned int size,
+ const char *query, const char *domain)
+{
+ unsigned char *ptr = buf;
+ char *offset;
+
+ DBG("query %s domain %s", query, domain);
+
+ offset = (char *) query;
+ while (offset != NULL) {
+ char *tmp;
+
+ tmp = strchr(offset, '.');
+ if (tmp == NULL) {
+ if (strlen(offset) == 0)
+ break;
+ *ptr = strlen(offset);
+ memcpy(ptr + 1, offset, strlen(offset));
+ ptr += strlen(offset) + 1;
+ break;
+ }
+
+ *ptr = tmp - offset;
+ memcpy(ptr + 1, offset, tmp - offset);
+ ptr += tmp - offset + 1;
+
+ offset = tmp + 1;
+ }
+
+ offset = (char *) domain;
+ while (offset != NULL) {
+ char *tmp;
+
+ tmp = strchr(offset, '.');
+ if (tmp == NULL) {
+ if (strlen(offset) == 0)
+ break;
+ *ptr = strlen(offset);
+ memcpy(ptr + 1, offset, strlen(offset));
+ ptr += strlen(offset) + 1;
+ break;
+ }
+
+ *ptr = tmp - offset;
+ memcpy(ptr + 1, offset, tmp - offset);
+ ptr += tmp - offset + 1;
+
+ offset = tmp + 1;
+ }
+
+ *ptr++ = 0x00;
+
+ return ptr - buf;
+}
+
+static gboolean request_timeout(gpointer user_data)
+{
+ struct request_data *req = user_data;
+
+ DBG("id 0x%04x", req->srcid);
+
+ request_list = g_slist_remove(request_list, req);
+
+ if (req->resplen > 0 && req->resp != NULL) {
+ int sk, err;
+
+ sk = g_io_channel_unix_get_fd(listener_channel);
+
+ err = sendto(sk, req->resp, req->resplen, 0,
+ (struct sockaddr *) &req->sin, req->len);
+ }
+
+ g_free(req->resp);
+ g_free(req);
+
+ return FALSE;
+}
+