"Fossies" - the Fresh Open Source Software Archive

Member "nss-mdns-0.10/src/dns.c" (6 Feb 2007, 7683 Bytes) of package /linux/misc/dns/old/nss-mdns-0.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* $Id: dns.c 113 2007-02-06 10:17:49Z lennart $ */
    2 
    3 /***
    4   This file is part of nss-mdns.
    5  
    6   nss-mdns is free software; you can redistribute it and/or modify it
    7   under the terms of the GNU Lesser General Public License as
    8   published by the Free Software Foundation; either version 2 of the
    9   License, or (at your option) any later version.
   10  
   11   nss-mdns is distributed in the hope that it will be useful, but
   12   WITHOUT ANY WARRANTY; without even the implied warranty of
   13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   14   General Public License for more details.
   15  
   16   You should have received a copy of the GNU Lesser General Public
   17   License along with nss-mdns; if not, write to the Free Software
   18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   19   USA.
   20 ***/
   21 
   22 #ifdef HAVE_CONFIG_H
   23 #include <config.h>
   24 #endif
   25 
   26 #include <stdlib.h>
   27 #include <string.h>
   28 #include <assert.h>
   29 #include <sys/types.h>
   30 #include <netinet/in.h>
   31 #include <stdio.h>
   32 
   33 #include "dns.h"
   34 
   35 #define SET_16_P(data, value)                              \
   36   do {                                                     \
   37     uint16_t __value = value;                              \
   38     memcpy(data, &__value, sizeof(uint16_t));              \
   39   } while(0)
   40 
   41 #define SET_16(data, idx, value)                         \
   42   SET_16_P(((uint8_t *)data) + idx * sizeof(uint16_t)/sizeof(uint8_t), value) 
   43 
   44 #define GET_16_P(data, value)                   \
   45   do {                                          \
   46     uint8_t *__value = ((uint8_t *)&value);     \
   47     memcpy(__value, data, sizeof(uint16_t));    \
   48   } while(0)
   49     
   50 #define GET_16(data, idx, value) \
   51   GET_16_P(((uint8_t *)data) + idx * sizeof(uint16_t)/sizeof(uint8_t), value) 
   52 
   53 #define GET_32_P(data, value)                   \
   54   do {                                          \
   55     uint8_t *__value = ((uint8_t *)&value);     \
   56     memcpy(__value, data, sizeof(uint32_t));    \
   57   } while(0)
   58     
   59 #define GET_32(data, idx, value) \
   60   GET_32_P(((uint8_t *)data) + idx * sizeof(uint32_t)/sizeof(uint8_t), value) 
   61 
   62 struct dns_packet* dns_packet_new(void) {
   63     struct dns_packet *p;
   64 
   65     if (!(p = malloc(sizeof(struct dns_packet))))
   66         return NULL;
   67     
   68     p->size = p->rindex = 2*6;
   69     memset(p->data, 0, p->size);
   70     return p;
   71 }
   72 
   73 void dns_packet_free(struct dns_packet *p) {
   74     assert(p);
   75     free(p);
   76 }
   77 
   78 void dns_packet_set_field(struct dns_packet *p, unsigned idx, uint16_t v) {
   79     assert(p);
   80     assert(idx < 2*6);
   81 
   82     
   83     SET_16(p->data, idx, htons(v));
   84 }
   85 
   86 uint16_t dns_packet_get_field(struct dns_packet *p, unsigned idx) {
   87     assert(p);
   88     assert(idx < 2*6);
   89     uint16_t r;
   90 
   91     GET_16(p->data, idx, r);
   92 
   93     return ntohs(r);
   94 }
   95 
   96 uint8_t* dns_packet_append_name(struct dns_packet *p, const char *name) {
   97     uint8_t *d, *f = NULL;
   98     assert(p);
   99 
  100     for (;;) {
  101         size_t n = strcspn(name, ".");
  102         if (!n || n > 63)
  103             return NULL;
  104         
  105         d = dns_packet_extend(p, n+1);
  106         if (!f)
  107             f = d;
  108         
  109         d[0] = n;
  110         memcpy(d+1, name, n);
  111 
  112         name += n;
  113 
  114         /* no trailing dot */
  115         if (!*name)
  116             break;
  117 
  118         name ++;
  119 
  120         /* trailing dot */
  121         if (!*name)
  122             break;
  123     }
  124 
  125     d = dns_packet_extend(p, 1);
  126     d[0] = 0;
  127 
  128     return f;
  129 }
  130 
  131 uint8_t* dns_packet_append_uint16(struct dns_packet *p, uint16_t v) {
  132     uint8_t *d;
  133     assert(p);
  134     
  135     d = dns_packet_extend(p, sizeof(uint16_t));
  136     SET_16_P(d, htons(v));
  137     
  138     return d;
  139 }
  140 
  141 uint8_t *dns_packet_extend(struct dns_packet *p, size_t l) {
  142     uint8_t *d;
  143     assert(p);
  144 
  145     assert(p->size+l <= sizeof(p->data));
  146 
  147     d = p->data + p->size;
  148     p->size += l;
  149     
  150     return d;
  151 }
  152 
  153 uint8_t *dns_packet_append_name_compressed(struct dns_packet *p, const char *name, uint8_t *prev) {
  154     uint8_t *d;
  155     signed long k;
  156     assert(p);
  157 
  158     if (!prev)
  159         return dns_packet_append_name(p, name);
  160     
  161     k = prev - p->data;
  162     if (k < 0 || k >= 0x4000 || (size_t) k >= p->size)
  163         return dns_packet_append_name(p, name);
  164 
  165     d = dns_packet_extend(p, sizeof(uint16_t));
  166     SET_16_P(d, htons((0xC000 | k)));
  167     
  168     return prev;
  169 }
  170 
  171 int dns_packet_check_valid(struct dns_packet *p) {
  172     uint16_t flags;
  173     assert(p);
  174 
  175     if (p->size < 12)
  176         return -1;
  177 
  178     flags = dns_packet_get_field(p, DNS_FIELD_FLAGS);
  179 
  180     if (flags & DNS_FLAG_OPCODE || flags & DNS_FLAG_RCODE)
  181         return -1;
  182 
  183     return 0;
  184 }
  185 
  186 int dns_packet_check_valid_response(struct dns_packet *p) {
  187     uint16_t flags;
  188     assert(p);
  189     
  190     if (dns_packet_check_valid(p) < 0)
  191         return -1;
  192 
  193     flags = dns_packet_get_field(p, DNS_FIELD_FLAGS);
  194 
  195     if (!(flags & DNS_FLAG_QR))
  196         return -1;
  197 
  198     return 0;
  199 }
  200 
  201 static ssize_t consume_labels(struct dns_packet *p, size_t idx, char *ret_name, size_t l) {
  202     ssize_t ret = 0;
  203     int compressed = 0;
  204     int first_label = 1;
  205     int j;
  206     
  207     assert(p && ret_name && l);
  208     
  209     for (j = 0; j < 63; j++) {
  210         uint8_t n;
  211 
  212         if (idx+1 > p->size)
  213             return -1;
  214 
  215         n = p->data[idx];
  216 
  217         if (!n) {
  218             idx++;
  219             if (!compressed)
  220                 ret++;
  221 
  222             if (l < 1)
  223                 return -1;
  224             *ret_name = 0;
  225             
  226             return ret;
  227             
  228         } else if (n <= 63) {
  229             /* Uncompressed label */
  230             idx++;
  231             if (!compressed)
  232                 ret++;
  233         
  234             if (idx + n > p->size)
  235                 return -1;
  236 
  237             if ((size_t) n + 1 > l)
  238                 return -1;
  239 
  240             if (!first_label) {
  241                 *(ret_name++) = '.';
  242                 l--;
  243             } else
  244                 first_label = 0;
  245 
  246             memcpy(ret_name, p->data + idx, n);
  247             idx += n;
  248             ret_name += n;
  249             l -= n;
  250             
  251             if (!compressed)
  252                 ret += n;
  253         } else if ((n & 0xC0) == 0xC0) {
  254             size_t nptr;
  255             /* Compressed label */
  256 
  257             if (idx+2 > p->size)
  258                 return -1;
  259 
  260             nptr = ((size_t) (p->data[idx] & ~0xC0)) << 8 | p->data[idx+1];
  261 
  262             if (nptr >= idx || nptr < 12)
  263                 return -1;
  264 
  265             idx = nptr;
  266 
  267             if (!compressed)
  268                 ret += 2;
  269             
  270             compressed = 1;
  271         } else
  272             return -1;
  273     }
  274 
  275     return -1;
  276 }
  277 
  278 int dns_packet_consume_name(struct dns_packet *p, char *ret_name, size_t l) {
  279     ssize_t r;
  280     
  281     if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
  282         return -1;
  283 
  284     p->rindex += r;
  285     return 0;
  286 }
  287 
  288 int dns_packet_consume_uint16(struct dns_packet *p, uint16_t *ret_v) {
  289     assert(p && ret_v);
  290     uint16_t r;
  291 
  292     if (p->rindex + sizeof(uint16_t) > p->size)
  293         return -1;
  294     
  295     GET_16_P(p->data + p->rindex, r);
  296     *ret_v =  ntohs(r);
  297     p->rindex += sizeof(uint16_t);
  298 
  299     return 0;
  300 }
  301 
  302 int dns_packet_consume_uint32(struct dns_packet *p, uint32_t *ret_v) {
  303     assert(p && ret_v);
  304     uint32_t r;
  305 
  306     if (p->rindex + sizeof(uint32_t) > p->size)
  307         return -1;
  308 
  309     GET_32_P(p->data + p->rindex, r);
  310     *ret_v = ntohl(r);
  311     p->rindex += sizeof(uint32_t);
  312     
  313     return 0;
  314 }
  315 
  316 int dns_packet_consume_bytes(struct dns_packet *p, void *ret_data, size_t l) {
  317     assert(p && ret_data && l > 0);
  318     
  319     if (p->rindex + l > p->size)
  320         return -1;
  321 
  322     memcpy(ret_data, p->data + p->rindex, l);
  323     p->rindex += l;
  324 
  325     return 0;
  326 }
  327 
  328 int dns_packet_consume_seek(struct dns_packet *p, size_t length) {
  329     assert(p);
  330 
  331     if (!length)
  332         return 0;
  333     
  334     if (p->rindex + length > p->size)
  335         return -1;
  336 
  337     p->rindex += length;
  338     return 0;
  339 }