5

使用C语言获取DNS nameserver并进行域名解析

 2 years ago
source link: https://www.lujun9972.win/blog/2019/05/05/%E4%BD%BF%E7%94%A8c%E8%AF%AD%E8%A8%80%E8%8E%B7%E5%8F%96dns-nameserver%E5%B9%B6%E8%BF%9B%E8%A1%8C%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90/index.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用C语言获取DNS nameserver并进行域名解析

#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>

int main()
{
  res_init();
  int i = 0;
  for (i = 0;i< _res.nscount;i++) /* _res.nscount为找到的域名服务器的数量 */
    {
      struct sockaddr_in addr = _res.nsaddr_list[i]; /* 域名服务器的地址  */
    }
  int class = C_IN;
  int type = T_A;
  unsigned char answer[512]="";
  int n =res_query("www.baidu.com", class, type, answer, sizeof(answer)); /* answer中为域名解析的结果 */
  res_close();
  for(int i=0; i<n; i++){
    printf("%02x", answer[i]);
  }
}
4d20818000010003000000000377777705626169647503636f6d0000010001c00c0005000100000258000f0377777701610673686966656ec016c02b000100010000025800040ed7b126c02b000100010000025800040ed7b127

这种方法由于使用到了静态全局变量 _res,因此并不是线程安全的。为此glib提供了线程安全的对应函数 res_ninit, res_nquery, res_nclose:

#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>

int main()
{
  res_state res = malloc(sizeof(*res));
  res_ninit(res);
  int i = 0;
  for (i = 0;i< res->nscount;i++) /* res->nscount存储了域名服务器的个数 */
    {
      struct sockaddr_in addr = res->nsaddr_list[i]; /* 域名服务器的地址 */
    }
  int class = C_IN;
  int type = T_A;
  unsigned char answer[256]="";
  int n =res_nquery(res, "www.baidu.com", class, type, answer, sizeof(answer));  /* answer中为域名解析的结果 */
  res_nclose(res);
  for(int i=0; i<n; i++){
    printf("%02x", answer[i]);
  }
}
9965818000010003000000000377777705626169647503636f6d0000010001c00c0005000100000258000f0377777701610673686966656ec016c02b000100010000025800040ed7b127c02b000100010000025800040ed7b126

  • answer 中的结果是二进制格式的,不能直接解读。我们可以用python的 dnslib 库来帮忙解读

    import dnslib
    import binascii
    data=binascii.a2b_hex(answer)
    return dnslib.DNSRecord.parse(data)
    
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26777
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
    ;; QUESTION SECTION:
    ;www.baidu.com.                 IN      A
    ;; ANSWER SECTION:
    www.baidu.com.          653     IN      CNAME   www.a.shifen.com.
    www.a.shifen.com.       600     IN      A       14.215.177.38
    www.a.shifen.com.       600     IN      A       14.215.177.39
    
    
  • res_state 的定义在 resolv/bits/types/res_state.h

    /* res_state: the global state used by the resolver stub.  */
    #define MAXNS                   3       /* max # name servers we'll track */
    #define MAXDFLSRCH              3       /* # default domain levels to try */
    #define MAXDNSRCH               6       /* max # domains in search path */
    #define MAXRESOLVSORT           10      /* number of net to sort on */
    
    struct __res_state {
      int   retrans;                /* retransmition time interval */
      int   retry;                  /* number of times to retransmit */
      unsigned long options;                /* option flags - see below. */
      int   nscount;                /* number of name servers */
      struct sockaddr_in
        nsaddr_list[MAXNS]; /* address of name server */
      unsigned short id;            /* current message id */
      /* 2 byte hole here.  */
      char  *dnsrch[MAXDNSRCH+1];   /* components of domain to search */
      char  defdname[256];          /* default domain (deprecated) */
      unsigned long pfcode;         /* RES_PRF_ flags - see below. */
      unsigned ndots:4;             /* threshold for initial abs. query */
      unsigned nsort:4;             /* number of elements in sort_list[] */
      unsigned ipv6_unavail:1;      /* connecting to IPv6 server failed */
      unsigned unused:23;
      struct {
        struct in_addr      addr;
        uint32_t    mask;
      } sort_list[MAXRESOLVSORT];
      /* 4 byte hole here on 64-bit architectures.  */
      void * __glibc_unused_qhook;
      void * __glibc_unused_rhook;
      int   res_h_errno;            /* last one set for this context */
      int   _vcsock;                /* PRIVATE: for res_send VC i/o */
      unsigned int _flags;          /* PRIVATE: see below */
      /* 4 byte hole here on 64-bit architectures.  */
      union {
        char        pad[52];        /* On an i386 this means 512b total. */
        struct {
          uint16_t          nscount;
          uint16_t          nsmap[MAXNS];
          int                       nssocks[MAXNS];
          uint16_t          nscount6;
          uint16_t          nsinit;
          struct sockaddr_in6       *nsaddrs[MAXNS];
    #ifdef _LIBC
          unsigned long long int __glibc_extension_index
            __attribute__((packed));
    #else
          unsigned int              __glibc_reserved[2];
    #endif
        } _ext;
      } _u;
    };
    
    typedef struct __res_state *res_state;
    
  • classtype 的定义在 resolv/arpa/nameser.h

    /*%
     * Values for class field
     */
    typedef enum __ns_class {
                             ns_c_invalid = 0,      /*%< Cookie. */
                             ns_c_in = 1,           /*%< Internet. */
                             ns_c_2 = 2,            /*%< unallocated/unsupported. */
                             ns_c_chaos = 3,                /*%< MIT Chaos-net. */
                             ns_c_hs = 4,           /*%< MIT Hesiod. */
                             /* Query class values which do not appear in resource records */
                             ns_c_none = 254,       /*%< for prereq. sections in update requests */
                             ns_c_any = 255,                /*%< Wildcard match. */
                             ns_c_max = 65536
    } ns_class;
    
    typedef enum __ns_type
      {
       ns_t_invalid = 0,
    
       ns_t_a = 1,
       ns_t_ns = 2,
       ns_t_md = 3,
       ns_t_mf = 4,
       ns_t_cname = 5,
       ns_t_soa = 6,
       ns_t_mb = 7,
       ns_t_mg = 8,
       ns_t_mr = 9,
       ns_t_null = 10,
       ns_t_wks = 11,
       ns_t_ptr = 12,
       ns_t_hinfo = 13,
       ns_t_minfo = 14,
       ns_t_mx = 15,
       ns_t_txt = 16,
       ns_t_rp = 17,
       ns_t_afsdb = 18,
       ns_t_x25 = 19,
       ns_t_isdn = 20,
       ns_t_rt = 21,
       ns_t_nsap = 22,
       ns_t_nsap_ptr = 23,
       ns_t_sig = 24,
       ns_t_key = 25,
       ns_t_px = 26,
       ns_t_gpos = 27,
       ns_t_aaaa = 28,
       ns_t_loc = 29,
       ns_t_nxt = 30,
       ns_t_eid = 31,
       ns_t_nimloc = 32,
       ns_t_srv = 33,
       ns_t_atma = 34,
       ns_t_naptr = 35,
       ns_t_kx = 36,
       ns_t_cert = 37,
       ns_t_a6 = 38,
       ns_t_dname = 39,
       ns_t_sink = 40,
       ns_t_opt = 41,
       ns_t_apl = 42,
       ns_t_ds = 43,
       ns_t_sshfp = 44,
       ns_t_ipseckey = 45,
       ns_t_rrsig = 46,
       ns_t_nsec = 47,
       ns_t_dnskey = 48,
       ns_t_dhcid = 49,
       ns_t_nsec3 = 50,
       ns_t_nsec3param = 51,
       ns_t_tlsa = 52,
       ns_t_smimea = 53,
       ns_t_hip = 55,
       ns_t_ninfo = 56,
       ns_t_rkey = 57,
       ns_t_talink = 58,
       ns_t_cds = 59,
       ns_t_cdnskey = 60,
       ns_t_openpgpkey = 61,
       ns_t_csync = 62,
       ns_t_spf = 99,
       ns_t_uinfo = 100,
       ns_t_uid = 101,
       ns_t_gid = 102,
       ns_t_unspec = 103,
       ns_t_nid = 104,
       ns_t_l32 = 105,
       ns_t_l64 = 106,
       ns_t_lp = 107,
       ns_t_eui48 = 108,
       ns_t_eui64 = 109,
       ns_t_tkey = 249,
       ns_t_tsig = 250,
       ns_t_ixfr = 251,
       ns_t_axfr = 252,
       ns_t_mailb = 253,
       ns_t_maila = 254,
       ns_t_any = 255,
       ns_t_uri = 256,
       ns_t_caa = 257,
       ns_t_avc = 258,
       ns_t_ta = 32768,
       ns_t_dlv = 32769,
    
       ns_t_max = 65536
      } ns_type;
    

其他函数说明可以参见 man resolver.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK