lwip-1.4.1 (partial)

Dependents:   IGLOO_board

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dnserver.c Source File

dnserver.c

00001 /*
00002  * The MIT License (MIT)
00003  *
00004  * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
00005  * 
00006  * Permission is hereby granted, free of charge, to any person obtaining a copy
00007  * of this software and associated documentation files (the "Software"), to deal
00008  * in the Software without restriction, including without limitation the rights
00009  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010  * copies of the Software, and to permit persons to whom the Software is
00011  * furnished to do so, subject to the following conditions:
00012  * 
00013  * The above copyright notice and this permission notice shall be included in all
00014  * copies or substantial portions of the Software.
00015  * 
00016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00019  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00020  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00021  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00022  * SOFTWARE.
00023  */
00024 
00025 /*
00026  * version: 1.0 demo (7.02.2015)
00027  * brief:   tiny dns ipv4 server using lwip (pcb)
00028  */
00029 
00030 #include "dnserver.h"
00031 
00032 #define DNS_MAX_HOST_NAME_LEN 128
00033 
00034 static struct udp_pcb *pcb = NULL;
00035 dns_query_proc_t query_proc = NULL;
00036 
00037 #pragma pack(push, 1)
00038 typedef struct
00039 {
00040 #if BYTE_ORDER == LITTLE_ENDIAN
00041     uint8_t rd: 1,     /* Recursion Desired */
00042             tc: 1,     /* Truncation Flag */
00043             aa: 1,     /* Authoritative Answer Flag */
00044             opcode: 4, /* Operation code */
00045             qr: 1;     /* Query/Response Flag */
00046     uint8_t rcode: 4,  /* Response Code */
00047             z: 3,      /* Zero */
00048             ra: 1;     /* Recursion Available */
00049 #else
00050     uint8_t qr: 1,     /* Query/Response Flag */
00051             opcode: 4, /* Operation code */
00052             aa: 1,     /* Authoritative Answer Flag */
00053             tc: 1,     /* Truncation Flag */
00054             rd: 1;     /* Recursion Desired */
00055     uint8_t ra: 1,     /* Recursion Available */
00056             z: 3,      /* Zero */
00057             rcode: 4;  /* Response Code */
00058 #endif
00059 } dns_header_flags_t;
00060 
00061 typedef struct
00062 {
00063     uint16_t id;
00064     dns_header_flags_t flags;
00065     uint16_t n_record[4];
00066 } dns_header_t;
00067 
00068 typedef struct dns_answer
00069 {
00070     uint16_t name;
00071     uint16_t type;
00072     uint16_t Class;
00073     uint32_t ttl;
00074     uint16_t len;
00075     uint32_t addr;
00076 } dns_answer_t;
00077 #pragma pack(pop)
00078 
00079 typedef struct dns_query
00080 {
00081     char name[DNS_MAX_HOST_NAME_LEN];
00082     uint16_t type;
00083     uint16_t Class;
00084 } dns_query_t;
00085 
00086 static int parse_next_query(void *data, int size, dns_query_t *query)
00087 {
00088     int len;
00089     int lables;
00090     uint8_t *ptr;
00091 
00092     len = 0;
00093     lables = 0;
00094     ptr = (uint8_t *)data;
00095 
00096     while (true)
00097     {
00098         uint8_t lable_len;
00099         if (size <= 0) return -1;
00100         lable_len = *ptr++;
00101         size--;
00102         if (lable_len == 0) break;
00103         if (lables > 0)
00104         {
00105             if (len == DNS_MAX_HOST_NAME_LEN) return -2;
00106             query->name[len++] = '.';
00107         }
00108         if (lable_len > size) return -1;
00109         if (len + lable_len >= DNS_MAX_HOST_NAME_LEN) return -2;
00110         memcpy(&query->name[len], ptr, lable_len);
00111         len += lable_len;
00112         ptr += lable_len;
00113         size -= lable_len;
00114         lables++;
00115     }
00116 
00117     if (size < 4) return -1;
00118     query->name[len] = 0;
00119     query->type = *(uint16_t *)ptr;
00120     ptr += 2;
00121     query->Class = *(uint16_t *)ptr;
00122     ptr += 2;
00123     return ptr - (uint8_t *)data;
00124 }
00125 
00126 static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
00127 {
00128     int len;
00129     dns_header_t *header;
00130     static dns_query_t query;
00131     struct pbuf *out;
00132     ip_addr_t host_addr;
00133     dns_answer_t *answer;
00134 
00135     if (p->len <= sizeof(dns_header_t)) goto error;
00136     header = (dns_header_t *)p->payload;
00137     if (header->flags.qr != 0) goto error;
00138     if (ntohs(header->n_record[0]) != 1) goto error;
00139 
00140     len = parse_next_query(header + 1, p->len - sizeof(dns_header_t), &query);
00141     if (len < 0) goto error;
00142     if (!query_proc(query.name, &host_addr)) goto refuse;
00143 
00144     len += sizeof(dns_header_t);
00145     out = pbuf_alloc(PBUF_TRANSPORT, len + 16, PBUF_POOL);
00146     if (out == NULL) goto error;
00147 
00148     memcpy(out->payload, p->payload, len);
00149     header = (dns_header_t *)out->payload;
00150     header->flags.qr = 1;
00151     header->n_record[1] = htons(1);
00152     answer = (struct dns_answer *)((uint8_t *)out->payload + len);
00153     answer->name = htons(0xC00C);
00154     answer->type = htons(1);
00155     answer->Class = htons(1);
00156     answer->ttl = htonl(32);
00157     answer->len = htons(4);
00158     answer->addr = host_addr.addr;
00159     
00160     udp_sendto(upcb, out, addr, port);
00161     pbuf_free(out);
00162     pbuf_free(p);
00163     return;
00164 
00165 refuse:
00166     header->flags.qr = 1;
00167     header->flags.rcode = 5;
00168     udp_sendto(upcb, p, addr, port);
00169     pbuf_free(p);
00170     return;
00171 
00172 error:
00173     pbuf_free(p);
00174 }
00175 
00176 err_t dnserv_init(ip_addr_t *bind, uint16_t port, dns_query_proc_t qp)
00177 {
00178     err_t err;
00179     udp_init();
00180     dnserv_free();
00181     pcb = udp_new();
00182     if (pcb == NULL)
00183         return ERR_MEM;
00184     err = udp_bind(pcb, bind, port);
00185     if (err != ERR_OK)
00186     {
00187         dnserv_free();
00188         return err;
00189     }
00190     udp_recv(pcb, udp_recv_proc, NULL);
00191     query_proc = qp;
00192     return ERR_OK;
00193 }
00194 
00195 void dnserv_free()
00196 {
00197     if (pcb == NULL) return;
00198     udp_remove(pcb);
00199     pcb = NULL;
00200 }