lwip-1.4.1 (partial)
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Wed Jul 13 2022 09:48:37 by 1.7.2