当前位置: 首页 > 工具软件 > dns.c > 使用案例 >

LINUX C语言 DNS

鲁展
2023-12-01

LINUX C语言 DNS

本文使用的glibc版本是2.19

资源下载地址

1.GNU LIB C 手册[http://ftp.gnu.org/old-gnu/Manuals/glibc-2.2.3/pdf/libc.pdf]

其实这算是LINUX下C语言的库函数手册,大部分函数的简单说明都能在里面查到。另外,如果你的环境是在liunux下,会有更简单的办法,就是man命令请看后面的内容。另外,这个版本的libc其实是旧版本的,2.2版本。但是现在常用的已经是比这个版本高了(本文使用的已经是2.19了)。提供这个手册的其中一个原因也是为了让大家注意一下自己的libc版本,以免跟我一样被版本问题坑一下。查询版本方法(shell命令):

ldd --version

2.GNU LIB C 源文件[http://ftp.gnu.org/gnu/libc/glibc-2.19.tar.xz]
注意:http://ftp.gnu.org里存的基本都是和GNU相关的东西,没事翻一番,或许有意外收获

数据结构

1.struct hostent

这个结构类型并不是在libc里面有定义的,因此没法通过源代码找到这个函数的结构。但是也是有办法查到的,比如百度一下(= =),不过我赌五毛钱这么干的人会被坑一下。
我建议可以通过gdb编译的时候带上-g参数,然后在调试程序的时候打印类型

(gdb)ptype struct hostent

结果如下:

struct hostent {
    char *h_name;
    char **h_aliases;
    int h_addrtype;
    int h_length;
    char **h_addr_list;char 
}

host_name:该地址最终的名字

例如ping百度的时候,最终会指向www.a.shifen.com

h_aliases 地址的预备名称的指针,一般为空
h_addrtype 地址类型,一般是是AF_INET。
h_length – 地址的长度,AF_INET时是4,单位应该是字节
h_addr_list -主机网络地址指针。存的就是我们要的IP地址。

现存的资料可能会提到一个成员char *h_addr 。但是根据我使用gdb打印的结果来看,这个成员已经不存在了。使用这个成员也会导致编译错误。

函数介绍

1.gethostbyname()

以下是可以在libc手册里查到的关于该函数的说明

Function
struct hostent * gethostbyname (const char *name)
The gethostbyname function returns information about the host named name. If the lookup fails, it returns a null pointer.

其实也可以在linux通过man命令查询到一些介绍,同时也可以查到使用该函数需要引入的头文件

man gethostbyname

在这里贴上源代码:

struct hostent *
gethostbyname(name)
    const char *name;
{
    struct hostent *hp;

    if (__res_maybe_init (&_res, 0) == -1) {
        __set_h_errno (NETDB_INTERNAL);
        return (NULL);
    }
    if (_res.options & RES_USE_INET6) {
        hp = gethostbyname2(name, AF_INET6);
        if (hp)
            return (hp);
    }
    return (gethostbyname2(name, AF_INET));
}

可以看到,主体实现其实还在另外一个函数gethostbyname2里。但是这个函数比较长,这里就不贴出来了,后面简单介绍一下就算了。有兴趣的可以下载源码查看[^footnote]

2.gethostbyname2()

struct hostent * gethostbyname2 (const char *name, int af)
The gethostbyname2 function is like gethostbyname, but allows the caller to specify the desired address family (e.g. AF_INET or AF_INET6) of the result.

函数第二个参数是协议类型,可以是AF_INET(IPv4)或者AF_INET6(IPv6)类型

程序代码

首先,上一段有问题的代码。对,你没看错,就是有问题的代码

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h>
int main(void)
{
    struct hostent *hostinfo;
    char *hostname = "www.csdn.com"
    hostinfo = gethostbyname (hostname); 
    if (hostinfo == NULL){
        fprintf (stderr, "Unknown host %s.\n", hostname);
        exit(EXIT_FAILURE); 
    } 
    printf("HostName:%s\n", hostinfo->h_name);
    printf("IPAddress:%s",inet_ntoa(*((struct in_addr*)h->h_addr)));
}

注意最后一行代码
printf(“IPAddress:%s”,inet_ntoa(((struct in_addr)h->h_addr)));
在前面已经提过了,h_addr这个成员在新版本里已经被删除掉了。因此这里不能再使用这个成员了。其实可以使用另外一个成员h_addr_list。这是一个二维指针,其实IP地址就依次存在于

hostinfo->h_addr_list[0][0]
hostinfo->h_addr_list[0][1]
hostinfo->h_addr_list[0][2]
hostinfo->h_addr_list[0][3] 

例如例子中,查询的是”www.csdn.com“的IP地址,如果是使用

ping www.csdn.com

返回的值可能是:114.112.73.194
那么对应存的值是

hostinfo->h_addr_list[0][0]//值为114
hostinfo->h_addr_list[0][1]//值为112
hostinfo->h_addr_list[0][2]//值为73
hostinfo->h_addr_list[0][3]//值为194,有符号打印则结果为负数

本来是想用inet_ntoa函数转换的,但是这个函数好像也经过了修改,gcc编译的时候会警报提示说” format ‘%s’ expects argument of type ‘char ’, but argument 2 has type ‘int’“。但是在libc的源码中看到的inet_ntoa函数返回值又确实是char 类型的。我尝试直接将结果当成一个整数打印出来,但是也并没有看出点什么。有明白的朋友希望告知。

 类似资料: