Android DNS之查询过程分发: nsdispatch()

本文深入解析了nsdispatch()函数的工作原理,介绍了其如何利用ns_src和ns_dtab数据结构来确定DNS查询方式,并详细说明了搜索源与查询表的匹配过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

在上一篇笔记 https://blog.youkuaiyun.com/xiaoyu_750516366/article/details/82750979 中,有一步比较关键的点没有细说,就是nsdispatch()的调用,这一步调用决定了到底后续是怎么进行DNS查询,这篇笔记就来看看该函数的实现逻辑。

数据结构

struct ns_src

ns_src定义了一个搜索源。

/*
 * ns_src - `nsswitch source'
 * Used by the nsparser routines to store a mapping between a source
 * and its dispatch control flags for a given database.
 */
typedef struct {
	//搜索源的名字,查询时,通过name与前面查询表项是否匹配来进行查询,见下文
	const char	*name;
	uint32_t	 flags;
} ns_src;

当前,搜索源src可以取如下值:

/*
 * Currently implemented sources.
 */
#define NSSRC_FILES	"files"		/* local files */
#define	NSSRC_DNS	"dns"		/* DNS; IN for hosts, HS for others */
#define	NSSRC_NIS	"nis"		/* YP/NIS */
#define	NSSRC_COMPAT	"compat"	/* passwd,group in YP compat mode */

查询表项struct ns_dtab

/*
 * ns_dtab `callback' function signature.
 */
typedef	int (*nss_method)(void *, void *, va_list);

/*
 * ns_dtab - `nsswitch dispatch table'
 * Contains an entry for each source and the appropriate function to call.
 */
typedef struct {
	const char	 *src;
	nss_method	 callback;
	void		 *cb_data;
} ns_dtab;

在进行域名解析时,ns_dtab定义了一个查询表项,查询表项用于指定如何搜索一个搜索源。其中src为该查询表项的搜索源路径;nss_method指定了如何查询该搜索源;cb_data指向传递给callback的参数。

为了方便定义ns_dtab,系统还提供了一些宏:

/*
 * Macros to help build an ns_dtab[]
 */
#define NS_FILES_CB(F,C)	{ NSSRC_FILES,	F,	__UNCONST(C) },
#define NS_COMPAT_CB(F,C)	{ NSSRC_COMPAT,	F,	__UNCONST(C) },

#ifdef HESIOD
#   define NS_DNS_CB(F,C)	{ NSSRC_DNS,	F,	__UNCONST(C) },
#else
#   define NS_DNS_CB(F,C)
#endif

#ifdef YP
#   define NS_NIS_CB(F,C)	{ NSSRC_NIS,	F,	__UNCONST(C) },
#else
#   define NS_NIS_CB(F,C)
#endif
#define	NS_NULL_CB		{ .src = NULL },

搜索接口nsdispatch

@retval:
@disp_tab: 查询表
@database:流程中没有使用,只是检查了该参数不能为NULL
@method:流程中没有使用,只是检查了该阐述不能为NULL
@defaults:搜索源
@others:其它参数
int nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
	    const char *method, const ns_src defaults[], ...)
{
	va_list		 ap;
	int		 i, result;
	const ns_src	*srclist;
	int		 srclistsize;
	nss_method	 cb;
	void		*cb_data;

	//输入参数的非空判断
	/* retval may be NULL */
	/* disp_tab may be NULL */
	assert(database != NULL);
	assert(method != NULL);
	assert(defaults != NULL);
	if (database == NULL || method == NULL || defaults == NULL)
		return (NS_UNAVAIL);

	//计算搜索源中有几个有效值
    srclist = defaults;
    srclistsize = 0;
    while (srclist[srclistsize].name != NULL)
            srclistsize++;

	result = 0;
	//遍历搜索源
	for (i = 0; i < srclistsize; i++) {
    	//该函数会返回查询表中src与搜索源中name字段相同的表项的回调函数,后面使用该回调函数
        //完成实际的查询,这里不知道为什么要设计的这么复杂
		cb = _nsmethod(srclist[i].name, database, method,
		    disp_tab, &cb_data);
		result = 0;
		if (cb != NULL) {
			va_start(ap, defaults);
            //调用查询函数进行查询
			result = (*cb)(retval, cb_data, ap);
			va_end(ap);
            //如果指定了NS_FORCEALL,表示强制查询搜有的搜索源,所以继续查询
			if (defaults[0].flags & NS_FORCEALL)
				continue;
            //回调返回的结果与指定的标记符合(一般指查询成功),那么跳出
			if (result & srclist[i].flags)
				break;
            //如果是提供的buffer空间不足,直接返回
			/* Stop trying next resolver when there is a memory space fatal error. */
			if ((result & NS_UNAVAIL) != 0 && errno == ENOSPC) {
			  break;
			}
		}
	}
	result &= NS_STATUSMASK;	/* clear private flags in result */

	return (result ? result : NS_NOTFOUND);
}

搜索源与查询表的匹配规则

static nss_method
_nsmethod(const char *source, const char *database __unused, const char *method __unused,
    const ns_dtab disp_tab[], void **cb_data)
{
	int	curdisp;

	if (disp_tab != NULL) {
    	//遍历查询表
		for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++) {
			//寻找搜索源source和查询表项的scr一致的查询表项,然后返回其回调函数以及对应回调函数参数
            if (strcasecmp(source, disp_tab[curdisp].src) == 0) {
				*cb_data = disp_tab[curdisp].cb_data;
				return (disp_tab[curdisp].callback);
			}
		}
	}

	*cb_data = NULL;
	return (NULL);
}

综上所述,实际上ndispatch()要做的事情就是根据指定的搜索源(defaults参数)去匹配查询表(disp_tab参数)中匹配对应的搜索回调函数,这里通过这种机制实现了基于文件和域名系统的查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值