欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

处理udp请求

程序员文章站 2022-05-12 09:18:56
...

接下来就分析如何处理udp请求了,它主要用到的函数就是client_request

client_request(isc_task_t *task, isc_event_t *event)
{
    ns_client_t *client = event->ev_arg;
    //处理的连接数++
    ns_client_requests++;

    //这里是udp协议过来的
    if (event->ev_type == ISC_SOCKEVENT_RECVDONE) 
    {
        //获取那个recvevent事件
        sevent = (isc_socketevent_t *)event;
        //把buffer转移到新的内容上
        isc_buffer_init(&tbuffer, sevent->region.base, sevent->n);
		isc_buffer_add(&tbuffer, sevent->n);
		buffer = &tbuffer;
        //获取地址
        client->peeraddr = sevent->address;
        //
        client->nrecvs--
    }
    //解析dns报文,获取报文的id和flags
    result = dns_message_peekheader(buffer, &id, &flags);
    {
        id = isc_buffer_getuint16(&buffer);
	    flags = isc_buffer_getuint16(&buffer);
    }
    //解析报文
    result = dns_message_parse(client->message, buffer, 0);
    {
        //获取四个记录
        msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
	    msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
	    msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
	    msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
        //获取要查询的名字
        ret = getquestions(source, msg, &dctx, options);
        {
            //每次查询的的域名个数只能是1,name的ndata里面就存储了要查询的域名以及标点的个数
            for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++)
            {
                dns_name_t *name = isc_mempool_get(msg->namepool);
                isc_buffer_remainingregion(source, &r);
		        isc_buffer_setactive(source, r.length);
		        result = getname(name, source, msg, dctx);
                //获取到type和class
                dns_rdatatype_t rdtype = isc_buffer_getuint16(source);
	            dns_rdataclass_t rdclass = isc_buffer_getuint16(source);
                //申请dns_rdatalist_t的空间
                rdatalist = newrdatalist(msg);
                {
                    dns_msgblock_t *msgblock = msgblock_allocate(msg->mctx,sizeof(dns_rdatalist_t),RDATALIST_COUNT);
                    ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
					dns_rdatalist_t *rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 
					     
                }
                dns_rdataset_t *rdataset = isc_mempool_get(msg->rdspool);
                rdatalist->type = rdtype;
                rdatalist->covers = 0;
		        rdatalist->rdclass = rdclass;
		        rdatalist->ttl = 0;
                dns_rdataset_init(rdataset);
                //这里把rdatalist转变为rdataset
                dns_rdatalist_tordataset(rdatalist, rdataset);
                {
                    rdataset->methods = &methods;
	                rdataset->rdclass = rdatalist->rdclass;
	                rdataset->type = rdatalist->type;
	                rdataset->covers = rdatalist->covers;
	                rdataset->ttl = rdatalist->ttl;
	                rdataset->trust = 0;
	                rdataset->private1 = rdatalist;
	                rdataset->private2 = NULL;
	                rdataset->private3 = NULL;
	                rdataset->privateuint4 = 0;
	                rdataset->private5 = NULL;
                }
                //把rdataset添加到name->list中
                ISC_LIST_APPEND(name->list, rdataset, link);
            } 
            
        }
        //提取其余三个字段,注意如果是question的话,这三个字段一般就是空
        ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
    }
    //处理edns
    //获取目的地址,不同的协议获取的方式是不同的,对于ipv4的通过interface的addr,如果是tcp的query,通过client的tcpsorket
    if ((client->interface->flags & NS_INTERFACEFLAG_ANYADDR) == 0)
        //这是所有ipv4的处理
		isc_netaddr_fromsockaddr(&destaddr, &client->interface->addr);
	else {
         这是ipv6的处理
        isc_netaddr_fromsockaddr(&destaddr,&destsockaddr)
						
    }
    
    //通过client的源Ip匹配可以服务他的view,就是遍历server的viewlist,把找到的那个view复制到client->view
    for (view = ISC_LIST_HEAD(ns_g_server->viewlist);view != NULL;view = ISC_LIST_NEXT(view, link))
    {
        dns_view_attach(view, &client->view);
    }
			
    //获取跟签名相关的部分
    //调整包的大小,这个值是可以设定的
    if (client->udpsize > 512)
    switch (client->message->opcode)
    {
        case dns_opcode_query:
            ns_query_start(client);
    }
    
}
//开始查询资源了
ns_query_start(ns_client_t *client)
{
    //获取到查询信息
    dns_message_t *message = client->message;
    //用对端的地址初始化client的信息
    ns_client_info(client, peerbuf, ISC_SOCKADDR_FORMATSIZE);

    //处理好后路    
    client->next = query_next_callback;
    //设置一些查询的属性

    //获取查询的域名,存入到msg->cursors[section]中
    result = dns_message_firstname(message, DNS_SECTION_QUESTION);
    //将上面的名字存储到client->query.qname
    dns_message_currentname(message, DNS_SECTION_QUESTION,&client->query.qname);
    //域名合法性的检测,这里最终把要查询的域名存储到client->query.origqname->ndata中
    //比如a.some.top会存储为a回车换行sometop(假设zone名是some.top)
    dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
    client->query.origqname = client->query.qname;
    //要判断它的question的个数要大于1
	if (message->counts[DNS_SECTION_QUESTION] > 1)
    {}

    //取出第一个rdataset,检验它的查询type,就是A/AAAA/TXT那些,只有合法才继续往下走
    rdataset = ISC_LIST_HEAD(client->query.qname->list);
    qtype = rdataset->type;
    switch(qtype){}

    //一路设置message的属性
    将client复制到qclient
    ns_client_attach(client, &qclient);
    query_find(qclient, NULL, qtype, &client->q_log);
    
}
//在查找合适的db的时候,最先找的是标准库即zone文件,然后找dlz数据,如果找不到再找cache,当然cache就不是权威的答复了
query_find((ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype, query_log_t* q_log)
{
    if (client->view->checknames &&!dns_rdata_checkowner(client->query.qname,)
    {
        //view需要检测合法性的
    }
    //先找到合适的db
    dns_db_t *db
    dns_zone_t *zone
    result = query_getdb(client, client->query.qname, qtype, options,&zone, &db, &version, &is_zone)
    {
        dns_db_t * tdbp;
        dns_zone_t *zone = NULL;
        //他对应的接口dns_dlzimplementation_t *dlz_imp;每个dlz对应一个dlzdb_t的db,该db可以连接到dns_dlzimplementation_t 的接口,然后他又会有公有的methods
        dns_dlzdb_t *dlzdatabase;
        

        //这个就是域名的标号
        unsigned int namelabels = dns_name_countlabels(name);
        //先看是否有一个合适的zonedb
        result = query_getzonedb(client, name, qtype, options, &zone,dbp, versionp);
		{
            
            //先去红黑树中查找zone对应的信息存储到zone中
            result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,&zone);
		    {
                dns_zone_t *dummy = NULL;
                //去红黑树中寻找该zone
                result = dns_rbt_findname(zt->table, name, rbtoptions, foundname, (void **) (void*)&dummy);
                {
                    dns_rbtnode_t *node = NULL;
                    result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,options, NULL, NULL);
                    {
                        
                    }
				  
                }
				 
            }
            
        }
        //如果没有找到,或者找到的zone的名字比待查找的名字短(比如找到的zone是aa,而我们要查找aa.bb),就去dlz中寻找,注意最终的tdbp就等于封装好的dns_sdlz_db_t 类型的db,里面封装了dlz自己的imp以及自己的数据集合(flexi_dns_instance)
        
        if (zonelabels < namelabels && client->view->dlzdatabase != NULL)
        {
            tresult = dns_dlzfindzone(client->view, name,zonelabels, &tdbp);
		    {
                dns_name_t *zonename;
                for (i = namelabels; i > minlabels && i > 1; i--) 
                {
                    if (i == namelabels)
                    {
                        //把原始的名字存储到zonename上
                        result = dns_name_copy(name, zonename, NULL)
                    }
                    else
                    {
                        dns_name_split(name, i, NULL, zonename);
                        {
                            一次次缩减,比如第一个是akindlychinacachecom,缩减第一次为kindlychinacachecom,如果在dlz中找到kindlychinacachecom,那就意味着找到了
                        }
                        //去dlz中进行zone的寻找,这里调用的是findzone方法
                        dns_dlzdb_t *dlzdatabase = view->dlzdatabase;
		                findzone = dlzdatabase->implementation->methods->findzone;
		                result = (*findzone)(dlzdatabase->implementation->driverarg,dlzdatabase->dbdata, dlzdatabase->mctx,view->rdclass, zonename, dbp);
				        {
                            //这个的方法就是公有方法static dns_dlzmethods_t sdlzmethods
                            dns_sdlzfindzone
                            {
                                //通过它找到对应的dlz模块,就是每个dlz特有的方法
                                dns_sdlzimplementation_t *imp= (dns_sdlzimplementation_t *) driverarg;
                                //确保小写
                                dns_sdlz_tolower(namestr)
                                imp->methods->findzone(imp->driverarg, dbdata, namestr)
                                {
                                    //这个才是真正的findzone方法
                                    flexi_dns_findzone(void *driverarg, void *dbdata, const char *name)
                                    {
                                        zone_lookup(db->lookup_data->zone_table,name)
                                        {
                                            //将name进行hash然后查看table中是否有
                                        }
                                        if (result == ISC_R_SUCCESS)
                                        {
                                            result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,rdclass, dbp);
                                           
                                            {
                                                dns_sdlz_db_t *sdlzdb;
                                                dns_sdlzimplementation_t *imp
                                                imp = (dns_sdlzimplementation_t *) driverarg;
                                                //申请dns_sdlz_db_t 空间,注意这里区别dns_dlz_db_t 
                                                sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
                                                //设置它的一些属性
                                                sdlzdb->dlzimp = imp;
                                                sdlzdb->common.methods = &sdlzdb_methods;
                                                //它的dbdata就是每个dlz管理自己的方法的db,比如F_instance
                                                sdlzdb->dbdata = dbdata
                                                //这样就找到了db,封装了公用的方法,但是它的dlz_imp又指向每个私有的dlz
                                                *dbp = (dns_db_t *) sdlzdb;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        
                        //看nameid里面是否有更合适的
				         就是如果找到nameid中更匹配的,那就直接用nameid的db,而不用zonedb的
                        for (i = namelabels; i > minlabels && i >= 1; i--)
                        {
                            //这里用findnameid的方法看有没有更合适的db,如果有就更新
                            findzone = dlzdatabase->implementation->methods->findnameid;
                            result = (*findzone)(dlzdatabase->implementation-。。。)
                            {
                                //调用公用的方法:dns_sdlzfindnameid
                                dns_sdlzimplementation_t *imp = (dns_sdlzimplementation_t *) driverarg
                                //调用dlz真正的属于自己的方法flexi_dns_findnameid
                                result = imp->methods->findnameid(imp->driverarg, dbdata, namestr, is_full_domain);
                                {
                                    return flexi_dns_lookup_nameid_level(name, db, is_full_domain);
                                    {
                                        //直接查找
                                    }
                                }
                                if (result == ISC_R_SUCCESS)
		                            result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,rdclass, dbp);    
		                            {
                                        //做法同上面的zone是一样的,申请sdlzdb,同时赋值
                                        dns_sdlz_db_t *sdlzdb;
                                        *dbp = (dns_db_t *) sdlzdb;

                                    }
                            }
                        }
                    }
                 }
            }//end dns_dlzfindzone
            //分离上面找到的那个db
            if (*dbp != NULL)
				 dns_db_detach(dbp);
            *dbp = tdbp

            
        }
    	
	    if (result == ISC_R_SUCCESS) 
        {
            *zonep = zone;
            //代表是权威查找出来的
            *is_zonep = ISC_TRUE;
        } 
        else
        {
            result = query_getcachedb(client, name, qtype, dbp, options);
            //是缓存,因此不是权威
            *is_zonep = ISC_FALSE;
        }
	}//end query_db
    //确定它的权威性
    if (is_zone)
		authoritative = ISC_TRUE;
    if (is_zone) 
    {
        if (zone != NULL)
        {
            dns_zone_attach(zone, &client->query.authzone);
        }
        dns_db_attach(db, &client->query.authdb);
        client->query.authdbset = ISC_TRUE;
    }
     
    db_find:
        //下面开始查找数据
   
}

 

相关标签: dns bind