"Fossies" - the Fresh Open Source Software Archive

Member "nsd-4.3.6/edns.c" (6 Apr 2021, 4225 Bytes) of package /linux/misc/dns/nsd-4.3.6.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. For more information about "edns.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.3.5_vs_4.3.6.

    1 /*
    2  * edns.c -- EDNS definitions (RFC 2671).
    3  *
    4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
    5  *
    6  * See LICENSE for the license.
    7  *
    8  */
    9 
   10 
   11 #include "config.h"
   12 
   13 #include <string.h>
   14 
   15 #include "dns.h"
   16 #include "edns.h"
   17 #include "nsd.h"
   18 #include "query.h"
   19 
   20 void
   21 edns_init_data(edns_data_type *data, uint16_t max_length)
   22 {
   23     memset(data, 0, sizeof(edns_data_type));
   24     /* record type: OPT */
   25     data->ok[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */
   26     data->ok[2] = TYPE_OPT & 0x00ff;    /* type_lo */
   27     /* udp payload size */
   28     data->ok[3] = (max_length & 0xff00) >> 8; /* size_hi */
   29     data->ok[4] = max_length & 0x00ff;    /* size_lo */
   30 
   31     data->error[1] = (TYPE_OPT & 0xff00) >> 8;  /* type_hi */
   32     data->error[2] = TYPE_OPT & 0x00ff;     /* type_lo */
   33     data->error[3] = (max_length & 0xff00) >> 8;    /* size_hi */
   34     data->error[4] = max_length & 0x00ff;       /* size_lo */
   35     data->error[5] = 1; /* XXX Extended RCODE=BAD VERS */
   36 }
   37 
   38 void
   39 edns_init_nsid(edns_data_type *data, uint16_t nsid_len)
   40 {
   41        /* add nsid length bytes */
   42        data->rdata_nsid[0] = ((OPT_HDR + nsid_len) & 0xff00) >> 8; /* length_hi */
   43        data->rdata_nsid[1] = ((OPT_HDR + nsid_len) & 0x00ff);      /* length_lo */
   44 
   45        /* NSID OPT HDR */
   46        data->nsid[0] = (NSID_CODE & 0xff00) >> 8;
   47        data->nsid[1] = (NSID_CODE & 0x00ff);
   48        data->nsid[2] = (nsid_len & 0xff00) >> 8;
   49        data->nsid[3] = (nsid_len & 0x00ff);
   50 }
   51 
   52 void
   53 edns_init_record(edns_record_type *edns)
   54 {
   55     edns->status = EDNS_NOT_PRESENT;
   56     edns->position = 0;
   57     edns->maxlen = 0;
   58     edns->opt_reserved_space = 0;
   59     edns->dnssec_ok = 0;
   60     edns->nsid = 0;
   61     edns->ede = -1; /* -1 means no Extended DNS Error */
   62     edns->ede_text = NULL;
   63     edns->ede_text_len = 0;
   64 }
   65 
   66 /** handle a single edns option in the query */
   67 static int
   68 edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet,
   69     edns_record_type* edns, struct query* query, nsd_type* nsd)
   70 {
   71     (void) query; /* in case edns options need the query structure */
   72     /* handle opt code and read the optlen bytes from the packet */
   73     switch(optcode) {
   74     case NSID_CODE:
   75         /* is NSID enabled? */
   76         if(nsd->nsid_len > 0) {
   77             edns->nsid = 1;
   78             /* we have to check optlen, and move the buffer along */
   79             buffer_skip(packet, optlen);
   80             /* in the reply we need space for optcode+optlen+nsid_bytes */
   81             edns->opt_reserved_space += OPT_HDR + nsd->nsid_len;
   82         } else {
   83             /* ignore option */
   84             buffer_skip(packet, optlen);
   85         }
   86         break;
   87     default:
   88         buffer_skip(packet, optlen);
   89         break;
   90     }
   91     return 1;
   92 }
   93 
   94 int
   95 edns_parse_record(edns_record_type *edns, buffer_type *packet,
   96     query_type* query, nsd_type* nsd)
   97 {
   98     /* OPT record type... */
   99     uint8_t  opt_owner;
  100     uint16_t opt_type;
  101     uint16_t opt_class;
  102     uint8_t  opt_version;
  103     uint16_t opt_flags;
  104     uint16_t opt_rdlen;
  105 
  106     edns->position = buffer_position(packet);
  107 
  108     if (!buffer_available(packet, (OPT_LEN + OPT_RDATA)))
  109         return 0;
  110 
  111     opt_owner = buffer_read_u8(packet);
  112     opt_type = buffer_read_u16(packet);
  113     if (opt_owner != 0 || opt_type != TYPE_OPT) {
  114         /* Not EDNS.  */
  115         buffer_set_position(packet, edns->position);
  116         return 0;
  117     }
  118 
  119     opt_class = buffer_read_u16(packet);
  120     (void)buffer_read_u8(packet); /* opt_extended_rcode */
  121     opt_version = buffer_read_u8(packet);
  122     opt_flags = buffer_read_u16(packet);
  123     opt_rdlen = buffer_read_u16(packet);
  124 
  125     if (opt_version != 0) {
  126         /* The only error is VERSION not implemented */
  127         edns->status = EDNS_ERROR;
  128         return 1;
  129     }
  130 
  131     if (opt_rdlen > 0) {
  132         if(!buffer_available(packet, opt_rdlen))
  133             return 0;
  134         if(opt_rdlen > 65530)
  135             return 0;
  136         /* there is more to come, read opt code */
  137         while(opt_rdlen >= 4) {
  138             uint16_t optcode = buffer_read_u16(packet);
  139             uint16_t optlen = buffer_read_u16(packet);
  140             opt_rdlen -= 4;
  141             if(opt_rdlen < optlen)
  142                 return 0; /* opt too long, formerr */
  143             opt_rdlen -= optlen;
  144             if(!edns_handle_option(optcode, optlen, packet,
  145                 edns, query, nsd))
  146                 return 0;
  147         }
  148         if(opt_rdlen != 0)
  149             return 0;
  150     }
  151 
  152     edns->status = EDNS_OK;
  153     edns->maxlen = opt_class;
  154     edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK;
  155     return 1;
  156 }
  157 
  158 size_t
  159 edns_reserved_space(edns_record_type *edns)
  160 {
  161     /* MIEK; when a pkt is too large?? */
  162     return edns->status == EDNS_NOT_PRESENT ? 0
  163          : (OPT_LEN + OPT_RDATA + edns->opt_reserved_space);
  164 }