📄 dns_clnt.c
字号:
/***********************************************************************//* *//* Module: dns_clnt.c *//* Release: 2001.3 *//* Version: 2001.1 *//* Purpose: DNS Client Implementation *//* *//*---------------------------------------------------------------------*//* *//* Copyright 2001, Blunk Microsystems *//* ALL RIGHTS RESERVED *//* *//* Licensees have the non-exclusive right to use, modify, or extract *//* this computer program for software development at a single site. *//* This program may be resold or disseminated in executable format *//* only. The source code may not be redistributed or resold. *//* *//* *//***********************************************************************/#include "tcp_ipp.h"#include <string.h>/***********************************************************************//* Configuration *//***********************************************************************/#define DNS_NSIZE 24#define DNS_TSIZE 30#define DNS_TRIES 5/***********************************************************************//* Symbol Definitions *//***********************************************************************/#define IP_ADDRESS 1#define CNAME 5/***********************************************************************//* Type Definitions *//***********************************************************************/typedef struct{ ui16 identification; ui16 flags; ui16 num_questions; ui16 num_answers; ui16 num_authorities; ui16 num_additionals; ui8 question[500];} DnsReqType;/*** Format of entry in DNS cache*/typedef struct{ ui32 ip_addr; /* cached IP address */ char name[DNS_NSIZE]; /* host name */} DnsEntry;/***********************************************************************//* Global Variable Definitions *//***********************************************************************/static DnsEntry DnsTbl[DNS_TSIZE];static DnsEntry *OldestEntry = &DnsTbl[0];/***********************************************************************//* Local Function Definitions *//***********************************************************************//***********************************************************************//* skip_name: Move pointer past DNS encoded name *//* *//***********************************************************************/static ui8 *skip_name(ui8 *name){ int i; do { i = *name; if (i & 0xC0) return name + 2; else name += i + 1; } while (*name); return name + 1;}/***********************************************************************//* ask_server: Move pointer past DNS encoded name *//* *//***********************************************************************/static ui32 ask_server(ui32 server, const char *name, uint nlen){ int i, rc, sock, timeo; ui8 *dest, *mark; struct sockaddr_in sockaddr; DnsReqType *dns_req; ui16 type, num_answers; ui32 lword; const char *cp; /*-------------------------------------------------------------------*/ /* Allocate buffer for DNS request. */ /*-------------------------------------------------------------------*/ semPend(Net.IntSem, WAIT_FOREVER); dns_req = tcpGetBuf(sizeof(DnsReqType)); semPost(Net.IntSem); if (dns_req == NULL) { NetError(NULL, ENOBUFS); return 0; } /*-------------------------------------------------------------------*/ /* Form the request. */ /*-------------------------------------------------------------------*/ dns_req->identification = htons(33); dns_req->flags = htons(0x0100); dns_req->num_questions = htons(1); dns_req->num_answers = htons(0); dns_req->num_authorities = htons(0); dns_req->num_additionals = htons(0); /*-------------------------------------------------------------------*/ /* Put name into DNS name format. */ /*-------------------------------------------------------------------*/ dest = dns_req->question; for (cp = name; *cp;) { mark = dest++; for (i = 0; *cp && (*cp != '.'); ++i) { *dest++ = (ui8)*cp++; if (((dest - (ui8 *)dns_req) + 5) > sizeof(DnsReqType)) { semPend(Net.IntSem, WAIT_FOREVER); tcpRetBuf(&dns_req); semPost(Net.IntSem); NetError(NULL, EFAULT); return 0; } } *mark = (ui8)i; if (*cp == '.') ++cp; } *dest++ = 0; /*-------------------------------------------------------------------*/ /* Append query type and class values (network order). */ /*-------------------------------------------------------------------*/ *dest++ = 0; *dest++ = 1; *dest++ = 0; *dest++ = 1; /*-------------------------------------------------------------------*/ /* Create a socket. */ /*-------------------------------------------------------------------*/ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { semPend(Net.IntSem, WAIT_FOREVER); tcpRetBuf(&dns_req); semPost(Net.IntSem); return 0; } /*-------------------------------------------------------------------*/ /* Initialize the address structure. */ /*-------------------------------------------------------------------*/ memset(&sockaddr, 0, sizeof(struct sockaddr_in)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(53); sockaddr.sin_addr.s_addr = server; /*-------------------------------------------------------------------*/ /* Bind destination address to socket. */ /*-------------------------------------------------------------------*/ rc = connect(sock, &sockaddr, sizeof(struct sockaddr_in)); if (rc == -1) goto error; /*-------------------------------------------------------------------*/ /* Send request and wait for response, with exponential backoff. */ /*-------------------------------------------------------------------*/ for (i = 0, timeo = 750;; ++i, timeo *= 2) { /*-----------------------------------------------------------------*/ /* Pass request to server. */ /*-----------------------------------------------------------------*/ rc = send(sock, (void *)dns_req, dest - (ui8 *)dns_req, 0); if (rc == -1) goto error; /*-----------------------------------------------------------------*/ /* Set recv() timeout. */ /*-----------------------------------------------------------------*/ rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(int)); if (rc < 0) goto error; /*-----------------------------------------------------------------*/ /* Check for response. */ /*-----------------------------------------------------------------*/ rc = recv(sock, dns_req, sizeof(DnsReqType), 0); if (rc > 0) break; else if (errno != ETIMEDOUT) goto error; /*-----------------------------------------------------------------*/ /* Fail after so many tries. */ /*-----------------------------------------------------------------*/ if (i == DNS_TRIES) goto error; } /*-------------------------------------------------------------------*/ /* Check for error response. */ /*-------------------------------------------------------------------*/ if (ntohs(dns_req->flags) & 0x000F) goto error; /*-------------------------------------------------------------------*/ /* Determine the number of answers provided. */ /*-------------------------------------------------------------------*/ memcpy(&num_answers, &dns_req->num_answers, sizeof(short)); num_answers = ntohs(num_answers); /*-------------------------------------------------------------------*/ /* Loop through answers, looking for Host Address. */ /*-------------------------------------------------------------------*/ for (i = 0;;) { /*-----------------------------------------------------------------*/ /* Skip answer's name, advancing to and reading its type. */ /*-----------------------------------------------------------------*/ dest = skip_name(dest); memcpy(&type, dest, sizeof(short)); type = ntohs(type); /*-----------------------------------------------------------------*/ /* Skip Canonical name answers. */ /*-----------------------------------------------------------------*/ if (type == CNAME) { ui16 word; dest += 8; /* advance to data length field */ memcpy(&word, dest, sizeof(short)); word = ntohs(word); dest += word + 2; /* advance to next resource record */ } /*-----------------------------------------------------------------*/ /* Read IP address and break if answer is Host Address. */ /*-----------------------------------------------------------------*/ else if (type == IP_ADDRESS) { memcpy(&lword, dest + 10, sizeof(long)); break; } /*-----------------------------------------------------------------*/ /* Anything else is an error. */ /*-----------------------------------------------------------------*/ else goto error; /*-----------------------------------------------------------------*/ /* Return error if every answer has been checked. */ /*-----------------------------------------------------------------*/ if (++i == num_answers) goto error; } /*-------------------------------------------------------------------*/ /* If the host name fits, save it in the DNS cache. */ /*-------------------------------------------------------------------*/ if (nlen < DNS_NSIZE) { OldestEntry->ip_addr = lword; strcpy(OldestEntry->name, name); if (++OldestEntry == &DnsTbl[DNS_TSIZE]) OldestEntry = &DnsTbl[0]; } /*-------------------------------------------------------------------*/ /* Close socket and return IP address or 0 for success or failure. */ /*-------------------------------------------------------------------*/ semPend(Net.IntSem, WAIT_FOREVER); tcpRetBuf(&dns_req); semPost(Net.IntSem); closesocket(sock); return lword;error: semPend(Net.IntSem, WAIT_FOREVER); tcpRetBuf(&dns_req); semPost(Net.IntSem); closesocket(sock); NetError(NULL, EDNS_FAILED); return 0;}/***********************************************************************//* Global Function Definitions *//***********************************************************************//***********************************************************************//* getHostByName: Request IP address resolution from DNS server *//* *//* Input: name = NULL-terminated host name *//* *//* Returns: IP address if no errors, else 0 *//* *//***********************************************************************/ui32 getHostByName(const char *name){ uint nlen; DnsEntry *entry; ui32 addr; HostDesc *host; /*-------------------------------------------------------------------*/ /* Check if name is in application's HostsTable. */ /*-------------------------------------------------------------------*/ for (host = &HostsTable[0]; host->ip_addr; ++host) { /*-----------------------------------------------------------------*/ /* Return if host name match is found. */ /*-----------------------------------------------------------------*/ if (strcmp(host->name, name) == 0) return host->ip_addr; } /*-------------------------------------------------------------------*/ /* Acquire exclusive access to DNS client. */ /*-------------------------------------------------------------------*/ semPend(Net.DnsSem, WAIT_FOREVER); /*-------------------------------------------------------------------*/ /* Check if host name is already in DNS cache. */ /*-------------------------------------------------------------------*/ nlen = strlen(name); if (nlen < DNS_NSIZE) for (entry = &DnsTbl[0]; entry < &DnsTbl[DNS_TSIZE]; ++entry) if (strcmp(entry->name, name) == 0) { addr = entry->ip_addr; goto exit; } /*-------------------------------------------------------------------*/ /* If primary DNS server provided, return if it responds. */ /*-------------------------------------------------------------------*/ if (PriDnsServer) { addr = ask_server(PriDnsServer, name, nlen); if (addr) goto exit; } /*-------------------------------------------------------------------*/ /* If secondary DNS server provided, return if it responds. */ /*-------------------------------------------------------------------*/ if (SecDnsServer) { addr = ask_server(SecDnsServer, name, nlen); if (addr) goto exit; } /*-------------------------------------------------------------------*/ /* Either no DNS server configured or none responsed. */ /*-------------------------------------------------------------------*/ NetError(NULL, EDNS_SERVER); addr = 0;exit: /*-------------------------------------------------------------------*/ /* Release exclusive access to DNS client. */ /*-------------------------------------------------------------------*/ semPost(Net.DnsSem); return addr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -