uIP 1.0
|
00001 /** 00002 * \addtogroup apps 00003 * @{ 00004 */ 00005 00006 /** 00007 * \defgroup resolv DNS resolver - работа с именами DNS 00008 * @{ 00009 * 00010 * Функции uIP DNS resolver используются для поиска имени хоста 00011 * (в базе данных имен DNS) и привязки его к цифровому адресу IP. 00012 * Это поддерживает список распознанных имен хостов, который может 00013 * быть опрошен функцией resolv_lookup(). Новые имена хостов 00014 * могут быть распознаны с использованием функции resolv_query(). 00015 * 00016 * Когда имя хоста было распознано (или найдено несуществующим), 00017 * код резолвера вызывает функцию обратного вызова (callback), 00018 * которая называется resolv_found(). Эта функция должна быть 00019 * реализована модулем, который использует резолвер. 00020 */ 00021 00022 /** 00023 * \file 00024 * Резолвер - преобразователь имени DNS хоста в адрес IP. 00025 * \author Adam Dunkels <adam@dunkels.com> 00026 * 00027 * Этот файл реализует преобразователь DNS имени хоста в адрес IP. 00028 */ 00029 00030 /* 00031 * Copyright (c) 2002-2003, Adam Dunkels. 00032 * Все права зарезервированы. * 00033 * Повторное распространение, использование в исходном и двоичном виде, 00034 * с модификацией или без - разрешается, если выполняются следующие 00035 * условия: 00036 * 1. Распространение исходного кода должно сохранить вышеуказанную пометку 00037 * копирайта, этот список условий и следующую правовую оговорку. 00038 * 2. Распространение исходного кода должно сохранить вышеуказанную пометку 00039 * копирайта, этот список условий и следующую правовую оговорку в 00040 * документации и/или других материалах, которые будут предоставлены 00041 * вместе с распространяемыми материалами. 00042 * 3. Имя автора не может использоваться, чтобы подтвердить или продвинуть 00043 * продукты, написанные с использованием этого программного обеспечения 00044 * без специального на то разрешения. 00045 * 00046 * ЭТО ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ АВТОРОМ ``КАК ЕСТЬ'', БЕЗ 00047 * КАКОЙ-ЛИБО ЛЮБОЙ РАСШИРЕННОЙ ИЛИ ПОДРАЗУМЕВАЕМОЙ ГАРАНТИИ, ВКЛЮЧАЯ, 00048 * НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМ, ГАРАНТИИ ВЫСОКОГО СПРОСА И ПРИГОДНОСТИ 00049 * ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. АВТОР НИ ПРИ КАКИХ УСЛОВИЯХ НЕ ОТВЕТСТВЕНЕН 00050 * ЗА ЛЮБЫЕ УБЫТКИ - ПРЯМЫЕ, КОСВЕННЫЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ, ОБРАЗЦОВЫЕ 00051 * ИЛИ ПОСЛЕДОВАТЕЛЬНЫЕ (ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМ, ТРЕБОВАНИЯ 00052 * ЗАМЕНЫ ТОВАРА ИЛИ СЕРВИСА; ПОТЕРИ ИСПОЛЬЗОВАНИЯ, ДАННЫХ ИЛИ ВЫГОДЫ; 00053 * ИЛИ ПРЕКРАЩЕНИЕ БИЗНЕСА), ОДНАКО ВЫЗВАННЫЕ ПО ЛЮБОЙ ТЕОРИИ ОТВЕТСТВЕННОСТИ, 00054 * ЛИБО В КОНТРАКТЕ, ПРЯМОЙ ОТВЕТСТВЕННОСТИ, ЛИБО В НАРУШЕНИИ ЗАКОННЫХ ПРАВ 00055 * (ВКЛЮЧАЯ ТАК ИЛИ ИНАЧЕ НЕБРЕЖНОСТЬ), ВОЗНИКАЮЩИЕ ВСЕГДА ИЗ ИСПОЛЬЗОВАНИЯ 00056 * ЭТОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ДАЖЕ ЕСЛИ БЫЛО ПРЕДУПРЕЖДЕНИЕ О ВОЗМОЖНОСТИ 00057 * ТАКОГО ПОВРЕЖДЕНИЯ. 00058 * 00059 * Этот файл является частью стека uIP TCP/IP. 00060 * 00061 * $Id: resolv.c,v 1.5 2006/06/11 21:46:37 adam Exp $ 00062 * 00063 */ 00064 00065 #include "resolv.h" 00066 #include "uip.h" 00067 00068 #include <string.h> 00069 00070 #ifndef NULL 00071 #define NULL (void *)0 00072 #endif /* NULL */ 00073 00074 /** \internal Максимальное количество попыток запроса имени. */ 00075 #define MAX_RETRIES 8 00076 00077 /** \internal Заголовок сообщения DNS. */ 00078 struct dns_hdr { 00079 u16_t id; 00080 u8_t flags1, flags2; 00081 #define DNS_FLAG1_RESPONSE 0x80 00082 #define DNS_FLAG1_OPCODE_STATUS 0x10 00083 #define DNS_FLAG1_OPCODE_INVERSE 0x08 00084 #define DNS_FLAG1_OPCODE_STANDARD 0x00 00085 #define DNS_FLAG1_AUTHORATIVE 0x04 00086 #define DNS_FLAG1_TRUNC 0x02 00087 #define DNS_FLAG1_RD 0x01 00088 #define DNS_FLAG2_RA 0x80 00089 #define DNS_FLAG2_ERR_MASK 0x0f 00090 #define DNS_FLAG2_ERR_NONE 0x00 00091 #define DNS_FLAG2_ERR_NAME 0x03 00092 u16_t numquestions; 00093 u16_t numanswers; 00094 u16_t numauthrr; 00095 u16_t numextrarr; 00096 }; 00097 00098 /** \internal Структура сообщения ответа DNS. */ 00099 struct dns_answer { 00100 /* Запись ответа DNS начинается либо с имени домена, либо 00101 с указателя на имя, где-то уже присутствующее в пакете. */ 00102 u16_t type; 00103 u16_t class; 00104 u16_t ttl[2]; 00105 u16_t len; 00106 uip_ipaddr_t ipaddr; 00107 }; 00108 00109 struct namemap { 00110 #define STATE_UNUSED 0 00111 #define STATE_NEW 1 00112 #define STATE_ASKING 2 00113 #define STATE_DONE 3 00114 #define STATE_ERROR 4 00115 u8_t state; 00116 u8_t tmr; 00117 u8_t retries; 00118 u8_t seqno; 00119 u8_t err; 00120 char name[32]; 00121 uip_ipaddr_t ipaddr; 00122 }; 00123 00124 #ifndef UIP_CONF_RESOLV_ENTRIES 00125 #define RESOLV_ENTRIES 4 00126 #else /* UIP_CONF_RESOLV_ENTRIES */ 00127 #define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES 00128 #endif /* UIP_CONF_RESOLV_ENTRIES */ 00129 00130 00131 static struct namemap names[RESOLV_ENTRIES]; 00132 00133 static u8_t seqno; 00134 00135 static struct uip_udp_conn *resolv_conn = NULL; 00136 00137 00138 /*---------------------------------------------------------------------------*/ 00139 /** \internal 00140 * Просматривает компактно закодированное имя DNS и возвращает его конец. 00141 * 00142 * \return The end of the name. 00143 */ 00144 /*---------------------------------------------------------------------------*/ 00145 static unsigned char * 00146 parse_name(unsigned char *query) 00147 { 00148 unsigned char n; 00149 00150 do { 00151 n = *query++; 00152 00153 while(n > 0) { 00154 /* printf("%c", *query);*/ 00155 ++query; 00156 --n; 00157 }; 00158 /* printf(".");*/ 00159 } while(*query != 0); 00160 /* printf("\n");*/ 00161 return query + 1; 00162 } 00163 /*---------------------------------------------------------------------------*/ 00164 /** \internal 00165 * Пробегает по списку имен, чтобы посмотреть, есть ли в списке имена, 00166 * которые еще не опрошены, и если так, то посылвает запрос. 00167 */ 00168 /*---------------------------------------------------------------------------*/ 00169 static void 00170 check_entries(void) 00171 { 00172 register struct dns_hdr *hdr; 00173 char *query, *nptr, *nameptr; 00174 static u8_t i; 00175 static u8_t n; 00176 register struct namemap *namemapptr; 00177 00178 for(i = 0; i < RESOLV_ENTRIES; ++i) { 00179 namemapptr = &names[i]; 00180 if(namemapptr->state == STATE_NEW || 00181 namemapptr->state == STATE_ASKING) { 00182 if(namemapptr->state == STATE_ASKING) { 00183 if(--namemapptr->tmr == 0) { 00184 if(++namemapptr->retries == MAX_RETRIES) { 00185 namemapptr->state = STATE_ERROR; 00186 resolv_found(namemapptr->name, NULL); 00187 continue; 00188 } 00189 namemapptr->tmr = namemapptr->retries; 00190 } else { 00191 /* printf("Timer %d\n", namemapptr->tmr);*/ 00192 /* Его таймер не истек, так что перейдем 00193 к следующей записи. */ 00194 continue; 00195 } 00196 } else { 00197 namemapptr->state = STATE_ASKING; 00198 namemapptr->tmr = 1; 00199 namemapptr->retries = 0; 00200 } 00201 hdr = (struct dns_hdr *)uip_appdata; 00202 memset(hdr, 0, sizeof(struct dns_hdr)); 00203 hdr->id = htons(i); 00204 hdr->flags1 = DNS_FLAG1_RD; 00205 hdr->numquestions = HTONS(1); 00206 query = (char *)uip_appdata + 12; 00207 nameptr = namemapptr->name; 00208 --nameptr; 00209 /* Преобразует имя хоста в подходящий для запроса формат. */ 00210 do { 00211 ++nameptr; 00212 nptr = query; 00213 ++query; 00214 for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) { 00215 *query = *nameptr; 00216 ++query; 00217 ++n; 00218 } 00219 *nptr = n; 00220 } while(*nameptr != 0); 00221 { 00222 static unsigned char endquery[] = 00223 {0,0,1,0,1}; 00224 memcpy(query, endquery, 5); 00225 } 00226 uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata)); 00227 break; 00228 } 00229 } 00230 } 00231 /*---------------------------------------------------------------------------*/ 00232 /** \internal 00233 * Вызывается, когда поступят новые данные UDP. 00234 */ 00235 /*---------------------------------------------------------------------------*/ 00236 static void 00237 newdata(void) 00238 { 00239 char *nameptr; 00240 struct dns_answer *ans; 00241 struct dns_hdr *hdr; 00242 static u8_t nquestions, nanswers; 00243 static u8_t i; 00244 register struct namemap *namemapptr; 00245 00246 hdr = (struct dns_hdr *)uip_appdata; 00247 /* printf("ID %d\n", htons(hdr->id)); 00248 printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE); 00249 printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK); 00250 printf("Num questions %d, answers %d, authrr %d, extrarr %d\n", 00251 htons(hdr->numquestions), 00252 htons(hdr->numanswers), 00253 htons(hdr->numauthrr), 00254 htons(hdr->numextrarr)); 00255 */ 00256 00257 /* ID в заголовке DNS должен быть нашей записью в таблице имен. */ 00258 i = htons(hdr->id); 00259 namemapptr = &names[i]; 00260 if(i < RESOLV_ENTRIES && 00261 namemapptr->state == STATE_ASKING) { 00262 00263 /* Эта запись теперь завершена. */ 00264 namemapptr->state = STATE_DONE; 00265 namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; 00266 00267 /* Проверка на ошибку. Если так, то вызов callback для оповещения. */ 00268 if(namemapptr->err != 0) { 00269 namemapptr->state = STATE_ERROR; 00270 resolv_found(namemapptr->name, NULL); 00271 return; 00272 } 00273 00274 /* Мы заботимся только о вопросе (вопросах) и ответах. Так что authrr 00275 и extrarr просто отбрасываются. */ 00276 nquestions = htons(hdr->numquestions); 00277 nanswers = htons(hdr->numanswers); 00278 00279 /* Пропуск имени в вопросе. XXX: в действительности нужно проверить 00280 это имя, чтобы убедиться в соответствии. */ 00281 nameptr = parse_name((char *)uip_appdata + 12) + 4; 00282 00283 while(nanswers > 0) { 00284 /* Первый байт записи ответа ресурса определяет, сжатая ли тут 00285 запись или нормальная. */ 00286 if(*nameptr & 0xc0) { 00287 /* Сжатое имя. */ 00288 nameptr +=2; 00289 /* printf("Compressed anwser\n");*/ 00290 } else { 00291 /* Не сжатое имя. */ 00292 nameptr = parse_name((char *)nameptr); 00293 } 00294 00295 ans = (struct dns_answer *)nameptr; 00296 /* printf("Answer: type %x, class %x, ttl %x, length %x\n", 00297 htons(ans->type), htons(ans->class), (htons(ans->ttl[0]) 00298 << 16) | htons(ans->ttl[1]), htons(ans->len));*/ 00299 00300 /* Проверка на тип адреса IP и Internet class. Другие 00301 отбрасываются. */ 00302 if(ans->type == HTONS(1) && 00303 ans->class == HTONS(1) && 00304 ans->len == HTONS(4)) { 00305 /* printf("IP address %d.%d.%d.%d\n", 00306 htons(ans->ipaddr[0]) >> 8, 00307 htons(ans->ipaddr[0]) & 0xff, 00308 htons(ans->ipaddr[1]) >> 8, 00309 htons(ans->ipaddr[1]) & 0xff);*/ 00310 /* XXX: мы действительно должны сделать проверку, что этот 00311 адрес IP тот, что нам нужен. */ 00312 namemapptr->ipaddr[0] = ans->ipaddr[0]; 00313 namemapptr->ipaddr[1] = ans->ipaddr[1]; 00314 00315 resolv_found(namemapptr->name, namemapptr->ipaddr); 00316 return; 00317 } else { 00318 nameptr = nameptr + 10 + htons(ans->len); 00319 } 00320 --nanswers; 00321 } 00322 } 00323 } 00324 /*---------------------------------------------------------------------------*/ 00325 /** \internal 00326 * Главная фукнция UDP. 00327 */ 00328 /*---------------------------------------------------------------------------*/ 00329 void 00330 resolv_appcall(void) 00331 { 00332 if(uip_udp_conn->rport == HTONS(53)) { 00333 if(uip_poll()) { 00334 check_entries(); 00335 } 00336 if(uip_newdata()) { 00337 newdata(); 00338 } 00339 } 00340 } 00341 /*---------------------------------------------------------------------------*/ 00342 /** 00343 * Ставит имя в очередь, так что будет отправлен запрос на имя. 00344 * 00345 * \param name Запрашиваемое имя хоста. 00346 */ 00347 /*---------------------------------------------------------------------------*/ 00348 void 00349 resolv_query(char *name) 00350 { 00351 static u8_t i; 00352 static u8_t lseq, lseqi; 00353 register struct namemap *nameptr; 00354 00355 lseq = lseqi = 0; 00356 00357 for(i = 0; i < RESOLV_ENTRIES; ++i) { 00358 nameptr = &names[i]; 00359 if(nameptr->state == STATE_UNUSED) { 00360 break; 00361 } 00362 if(seqno - nameptr->seqno > lseq) { 00363 lseq = seqno - nameptr->seqno; 00364 lseqi = i; 00365 } 00366 } 00367 00368 if(i == RESOLV_ENTRIES) { 00369 i = lseqi; 00370 nameptr = &names[i]; 00371 } 00372 00373 /* printf("Using entry %d\n", i);*/ 00374 00375 strcpy(nameptr->name, name); 00376 nameptr->state = STATE_NEW; 00377 nameptr->seqno = seqno; 00378 ++seqno; 00379 } 00380 /*---------------------------------------------------------------------------*/ 00381 /** 00382 * Ищет имя хоста в массиве известных имен. 00383 * 00384 * \note Эта функция просматривает только внутренний массив известных 00385 * имен хостов, и не отправляет запрос, если имя хоста не найдено. Для 00386 * отправки запроса на распознание имени хоста может использоваться 00387 * функция resolv_query(). 00388 * 00389 * \return Указатель на 4-байтное представление адреса IP хоста, 00390 * или NULL, если имя хоста не было найдено в массиве имен. 00391 */ 00392 /*---------------------------------------------------------------------------*/ 00393 u16_t * 00394 resolv_lookup(char *name) 00395 { 00396 static u8_t i; 00397 struct namemap *nameptr; 00398 00399 /* Просмотр списка, чтобы узнать, есть ли в нем искомое имя. Если нет, 00400 то вернем NULL. */ 00401 for(i = 0; i < RESOLV_ENTRIES; ++i) { 00402 nameptr = &names[i]; 00403 if(nameptr->state == STATE_DONE && 00404 strcmp(name, nameptr->name) == 0) { 00405 return nameptr->ipaddr; 00406 } 00407 } 00408 return NULL; 00409 } 00410 /*---------------------------------------------------------------------------*/ 00411 /** 00412 * Получение текущего сконфигурированного сервера DNS. 00413 * 00414 * \return Указатель на 4-байтное представление адреса IP текущего 00415 * сконфигурированного сервера DNS, или NULL, если сервер DNS не был 00416 * сконфигурирован. 00417 */ 00418 /*---------------------------------------------------------------------------*/ 00419 u16_t * 00420 resolv_getserver(void) 00421 { 00422 if(resolv_conn == NULL) { 00423 return NULL; 00424 } 00425 return resolv_conn->ripaddr; 00426 } 00427 /*---------------------------------------------------------------------------*/ 00428 /** 00429 * Конфигурирует сервер DNS, который будет использован для запросов. 00430 * 00431 * \param dnsserver Указатель на 4-байтное представление адреса IP сервера 00432 * DNS, который будет сконфигурирован. 00433 */ 00434 /*---------------------------------------------------------------------------*/ 00435 void 00436 resolv_conf(u16_t *dnsserver) 00437 { 00438 if(resolv_conn != NULL) { 00439 uip_udp_remove(resolv_conn); 00440 } 00441 00442 resolv_conn = uip_udp_new(dnsserver, HTONS(53)); 00443 } 00444 /*---------------------------------------------------------------------------*/ 00445 /** 00446 * Инициализирует распознаватель имен. 00447 */ 00448 /*---------------------------------------------------------------------------*/ 00449 void 00450 resolv_init(void) 00451 { 00452 static u8_t i; 00453 00454 for(i = 0; i < RESOLV_ENTRIES; ++i) { 00455 names[i].state = STATE_DONE; 00456 } 00457 00458 } 00459 /*---------------------------------------------------------------------------*/ 00460 00461 /** @} */ 00462 /** @} */