iOS网络编程(二)IP、DNS相关

由于要实现一个VPN首先要开手机中开启一个服务,而 iOS 基于 linux 那么很明显,我们需要了解 Linux 下的相关函数,从而更好地创建服务,而 Linux 底层是基于 C 和 C++,而 iOS 中无论是 swift 还是 Objective-C 都可以完美的兼容 C,所以了解 C 的相关函数,对于我们开发是有很大的帮助的

网络编程——DNS基本知识

  1. 常见 DNS 资源
    | 代码 | 号码 | 描述 | 介绍 |
    | :————- | :————- | :————- | :————- |
    | A | 1 | IP 地址记录 | 传回一个 32 比特的 IPv4 地址,最常用于映射主机名称到 IP地址,但也用于DNSBL(RFC 1101)等。|
    | AAAA | 28 | IPv6 IP 地址记录 | 传回一个 128 比特的 IPv6 地址,最常用于映射主机名称到 IP 地址。|
    | CNAME | 5 | 规范名称记录 | 一个主机名字的别名:网域名称系统将会继续尝试查找新的名字。|

    如果想要更加形象的了解相关的内容,比如说一个人叫做老王,那么CName就是王XX(老王的真名),A就是他所住的地址,AAAA就是他所住地址用英文表示。
    你在 linux 下面可以使用 dig 命令来对对应的主机进行请求。
    比如说

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ dig www.google.com -t a
    ; <<>> DiG 9.8.3-P1 <<>> www.google.com -t a
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45402
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    ;; QUESTION SECTION:
    ;www.google.com. IN A
    ;; ANSWER SECTION:
    www.google.com. 1257 IN A 93.46.8.89
    ;; Query time: 11 msec
    ;; SERVER: 192.168.1.1#53(192.168.1.1)
    ;; WHEN: Fri Jan 27 00:26:45 2017
    ;; MSG SIZE rcvd: 48

    这样可以获得谷歌的IPv4情况下的地址是 93.46.8.89

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ dig www.google.com -t aaaa
    ; <<>> DiG 9.8.3-P1 <<>> www.google.com -t aaaa
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51370
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    ;; QUESTION SECTION:
    ;www.google.com. IN AAAA
    ;; ANSWER SECTION:
    www.google.com. 2350 IN AAAA 200:2:5d2e:859::
    ;; Query time: 8 msec
    ;; SERVER: 192.168.1.1#53(192.168.1.1)
    ;; WHEN: Fri Jan 27 00:26:37 2017
    ;; MSG SIZE rcvd: 60

    这样可以获得谷歌的IPv6情况下的地址是 200:2:5d2e:859::

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ dig www.baidu.com -t cname
    ; <<>> DiG 9.8.3-P1 <<>> www.baidu.com -t cname
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64206
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    ;; QUESTION SECTION:
    ;www.baidu.com. IN CNAME
    ;; ANSWER SECTION:
    www.baidu.com. 481 IN CNAME www.a.shifen.com.
    ;; Query time: 7 msec
    ;; SERVER: 192.168.1.1#53(192.168.1.1)
    ;; WHEN: Fri Jan 27 00:25:01 2017
    ;; MSG SIZE rcvd: 58

    这样可以获得百度的CNAME的地址是 www.a.shifen.com.,也就是说所有你请求 www.baidu.com 最终都会转移到 www.a.shifen.com 上面。

    当某一个参数没有配置的情况下,他会根据已经配置的优先级,返回对应的内容。比如说

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $ dig www.baidu.com -t aaaa
    ; <<>> DiG 9.8.3-P1 <<>> www.baidu.com -t aaaa
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21726
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0
    ;; QUESTION SECTION:
    ;www.baidu.com. IN AAAA
    ;; ANSWER SECTION:
    www.baidu.com. 492 IN CNAME www.a.shifen.com.
    ;; AUTHORITY SECTION:
    a.shifen.com. 94 IN SOA ns1.a.shifen.com. baidu_dns_master.baidu.com. 1701250009 5 5 86400 3600

    如果你想要快速获得a和cname,你可以直接通过 ping 来进行获取,从而获得对应的内容,例子如下

    1
    2
    3
    4
    5
    6
    $ ping www.baidu.com
    PING www.a.shifen.com (115.239.211.112): 56 data bytes
    64 bytes from 115.239.211.112: icmp_seq=0 ttl=55 time=11.128 ms
    --- www.a.shifen.com ping statistics ---
    1 packets transmitted, 1 packets received, 0.0% packet loss
    round-trip min/avg/max/stddev = 11.128/11.128/11.128/0.000 ms
  2. 常用结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public struct hostent {
    public var h_name: UnsafeMutablePointer<Int8>! /* 主机规范名字 */
    public var h_aliases: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>! /* 主机别名 */
    public var h_addrtype: Int32 /* AF_INET/AF_INET6 */
    public var h_length: Int32 /* 4/16 */
    public var h_addr_list: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>! /* 服务器地址链表 */
    public init()
    public init(h_name: UnsafeMutablePointer<Int8>!, h_aliases: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!, h_addrtype: Int32, h_length: Int32, h_addr_list: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!)
    }
1
2
3
4
5
public struct in_addr {
public var s_addr: in_addr_t //用来表示一个32位的IPv4地址,即用字节类型来记录ip地址,例如192.168.3.144记为0x9003a8c0,顺序为IP地址的逆序,即c0为192,a8为168,03为3,90为144
public init()
public init(s_addr: in_addr_t)
}

网络编程——DNS常见函数

  1. public func gethostbyname(_: UnsafePointer<Int8>!) -> UnsafeMutablePointer<hostent>!:如果没有设置RES_USE_INET6则查找A的记录,如果找到则返回 hostent ,否则返回错误,如果设置了,那么先查找 AAAA ,如果没有找到再查找 A 的记录
  2. public func gethostbyname2(_: UnsafePointer<Int8>!, _: Int32) -> UnsafeMutablePointer<hostent>!:功能同上,不过第二个参数是增加查找情况,如果传入值是AF_INET那么查找的是为A的记录,如果没有则返回空,如果找到了,查看有没有设置RES_USE_INET6,如果没有设置,那么就返回 IPv4 的地址,若设置了则返回 IPv4 地址到 IPv6 地址的映射。如果设置为AF_INET6,那么查找为AAAA的记录,如果找到了就返回,否则返回空字符串。(RES_USE_INET6必须在调用这几个函数前进行设置)

网络变成——IP常见函数

  1. public func inet_ntop(_: Int32, _: UnsafeRawPointer!, _: UnsafeMutablePointer<Int8>!, _: socklen_t) -> UnsafePointer<Int8>!:IP地址的点分二进制->点分十进制的转化。
  2. public func inet_pton(_: Int32, _: UnsafePointer<Int8>!, _: UnsafeMutableRawPointer!) -> Int32:IP地址的点分十进制->点分二进制的转化。

参考资料: