LWIP之DNS域名解析分析 (一)

本文详细分析了LWIP 1.4.0版本中IPv4客户端的DNS域名解析实现,重点关注其提供的API接口,用于发起DNS查询并处理响应,同时介绍了如何建立本地缓存。主要涉及dns.c、dns.h、netdb.c、netdb.h和ip_addr.h等文件。对于更复杂的DNS服务器程序,推荐参考bind 9。
摘要由CSDN通过智能技术生成

原创声明: 本文分析属于 tiandimz 所有,转载请注明出处!谢谢!

本文源码版本为 LWIP 1.4.0

源码下载地址

下面的代码是 dns.c 的全部代码!主要完成ipv4的客户端域名解析部分,不涉及复杂的服务器端的处理过程。

下面进行简要分析,由于LWIP是轻量级的IP协议栈,所以对于DNS的要求也很简单,主要是针对客户端测的实现,能够提供API接口,通过调用接口可以实现DNS查询请求,并能够解析DNS响应,并建立本地缓存!

主要涉及的文件有   dns.c   dns.h    netdb.c   netdb.h   ip_addr.h    ip_addr.c

对于复杂的域名解析服务器的程序,可以参考  bind 9.

dns报文格式请见:

DNS报文格式



#include "lwip/opt.h"    //LWIP的配置选项文件

#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */

#include "lwip/udp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/dns.h"  //dns的头文件

#include <string.h>

/** DNS server IP address     opendns  是一个开放dns服务,我们的请求也是发往这个服务器地址!*/
#ifndef DNS_SERVER_ADDRESS
#define DNS_SERVER_ADDRESS(ipaddr)        (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
#endif

/** DNS server port address */
#ifndef DNS_SERVER_PORT
#define DNS_SERVER_PORT           53    //  DNS通过 udp承载,主要利用  53端口
#endif

/** DNS maximum number of retries when asking for a name, before "timeout". */
#ifndef DNS_MAX_RETRIES
#define DNS_MAX_RETRIES           4    //dns请求超时的重试最大次数   4次
#endif



/** DNS resource record max. TTL (one week as default) */
#ifndef DNS_MAX_TTL
#define DNS_MAX_TTL               604800    //源记录的最大生存时间
#endif

/* DNS protocol flags         DNS的标记位  */
#define DNS_FLAG1_RESPONSE        0x80
#define DNS_FLAG1_OPCODE_STATUS   0x10
#define DNS_FLAG1_OPCODE_INVERSE  0x08
#define DNS_FLAG1_OPCODE_STANDARD 0x00
#define DNS_FLAG1_AUTHORATIVE     0x04
#define DNS_FLAG1_TRUNC           0x02
#define DNS_FLAG1_RD              0x01
#define DNS_FLAG2_RA              0x80
#define DNS_FLAG2_ERR_MASK        0x0f
#define DNS_FLAG2_ERR_NONE        0x00
#define DNS_FLAG2_ERR_NAME        0x03

/* DNS protocol states */
#define DNS_STATE_UNUSED          0
#define DNS_STATE_NEW             1
#define DNS_STATE_ASKING          2
#define DNS_STATE_DONE            3

#ifdef PACK_STRUCT_USE_INCLUDES
#  include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** DNS message header      DNS的消息头部  根据DNS的RFC协议 1035 描述进行设计的,采用结构体和位域来实现*/
struct dns_hdr {
  PACK_STRUCT_FIELD(u16_t id);
  PACK_STRUCT_FIELD(u8_t flags1);
  PACK_STRUCT_FIELD(u8_t flags2);
  PACK_STRUCT_FIELD(u16_t numquestions);
  PACK_STRUCT_FIELD(u16_t numanswers);
  PACK_STRUCT_FIELD(u16_t numauthrr);
  PACK_STRUCT_FIELD(u16_t numextrarr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
#  include "arch/epstruct.h"
#endif
#define SIZEOF_DNS_HDR 12

/** DNS query message structure.
    No packing needed: only used locally on the stack.   dns消息查询结构体          */
struct dns_query {
  /* DNS query record starts with either a domain name or a pointer
     to a name already present somewhere in the packet. */
  u16_t type;
  u16_t cls;
};
#define SIZEOF_DNS_QUERY 4




/** DNS answer message structure.
    No packing needed: only used locally on the stack. DNS应答消息报文格式 */
struct dns_answer {
  /* DNS answer record starts with either a domain name or a pointer
     to a name already present somewhere in the packet. */
  u16_t type;
  u16_t cls;
  u32_t ttl;
  u16_t len;
};
#define SIZEOF_DNS_ANSWER 10

/** DNS table entry   DNS的表格 */
struct dns_table_entry {
  u8_t  state;
  u8_t  numdns;
  u8_t  tmr;
  u8_t  retries;
  u8_t  seqno;
  u8_t  err;
  u32_t ttl;
  char name[DNS_MAX_NAME_LENGTH];//DNS_MAX_NAME_LENGTH  256,域名字符串最大长度 256
  ip_addr_t ipaddr;
  /* pointer to callback on DNS query done     callback  函数指针*/
  dns_found_callback found;
  void *arg;
};

#if DNS_LOCAL_HOSTLIST

#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
/** Local host-list. For hostnames in this list, no
 *  external name resolution is performed */
static struct local_hostlist_entry *local_hostlist_dynamic;   //本地的主机列表
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */

/** Defining this allows the local_hostlist_static to be placed in a different
 * linker section (e.g. FLASH) */
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
/** Defining this allows the local_hostlist_static to be placed in a different
 * linker section (e.g. FLASH) */
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
#define DNS_LOCAL_HOSTLIST_STORAGE_POST
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
  DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;

#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */



static void dns_init_local();   //dns初始化本地列表
#endif /* DNS_LOCAL_HOSTLIST */


/* forward declarations   函数声明包括:dns接受响应报文处理函数和dns检查本地列表函数*/
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); 
static void dns_check_entries(void);

/*-----------------------------------------------------------------------------
 * Globales   一些全局变量
 *----------------------------------------------------------------------------*/

/* DNS variables */
static struct udp_pcb        *dns_pcb;  //因为用UDP承载,所有需要在UDP 的pcb中记录
static u8_t                   dns_seqno; //
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];  //DNS_TABLE_SIZE 为 4 ,只存4个历史域名记录
static ip_addr_t              dns_servers[DNS_MAX_SERVERS];  //DNS_MAX_SERVERS为 2 ,主DNS和辅DNS
/** Contiguous buffer for processing responses   处理响应的缓存  */
static u8_t                   dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
static u8_t*                  dns_payload;

/**
 * Initialize the resolver: set up the UDP pcb and configure the default server
 * (DNS_SERVER_ADDRESS).初始化解析,建立UDP pcb 配置默认的服务器地址
 */
void
dns_init()
{
  ip_addr_t dnsserver;  /*  声明dns服务器地址     */

  dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);   /* 分配内存并对齐    */
  
  /* initialize default DNS server address */
  DNS_SERVER_ADDRESS(&dnsserver);   /* 设置DNS服务器地址   */

  LWIP_DEBUGF(DNS_DEBUG, ("d
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值