ip 子网

bit byte

1byte = 8bit

ipv4

32 bit二进制

ip地址 := {<网络号>,<主机号>}

点分十进制

每8bit => 十进制数字

IP段

  • A类IP段  0.0.0.0 到127.255.255.255
  • B类IP段 128.0.0.0 到191.255.255.255
  • C类IP段 192.0.0.0 到223.255.255.255

默认分配的子网掩码每段只有255或0

  • A类的默认子网掩码 255.0.0.0     一个子网最多可以容纳 \(2^{24}-2\) 1677万多台电脑
  • B类的默认子网掩码 255.255.0.0    一个子网最多可以容纳6万台电脑
  • C类的默认子网掩码 255.255.255.0   一个子网最多可以容纳254台电脑

子网掩码 & IP地址=网络标识 网络标识一样,那么属于同一网段

私有网段

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

ip/num CIDR

/num 是子网掩码表示方法 表示1的个数

1
192.168.0.0/24 => 11000000.10101000.00000000.00000000/24

ip有13位 num 取值范围[13,32] 总个数 2**(32-num) 前缀越短,包含地址数越多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
net = 12
network = ip_range(f'192.168.0.0/{net}')
ip2bin = lambda ip: '.'.join([bin(int(x) + 256)[3:] for x in ip.split('.')])
print(ip2bin('192.168.0.0'))

>>> 11000000.10101000.00000000.00000000

e = list(network)
print(str(min(e)), str(max(e)))

>>> 192.168.0.0 192.175.255.255

n = 2**(32-net)
l = len(e)
assert n == l

路由

通过目标主机连接的网络号来转发分组 通过路由表跳到下一个地方

子网

报文结构

ipv6

128 bit 在

IPv6单个段落内可重复压缩,比如上述可压缩为2001:0:0:0:11:0:0:10/64;若多个段落连续为0,可压缩 ,但只能压缩一次,比如上述可进一步压缩为2001::11:0:0:10/64,或者2001:0:0:0:11::10/64,通常为前者

程序里面通常与端口结合写法[::]:port

  • ::1 => 127.0.0.1
  • :: => 0.0.0.0

只要你想访问IPv6互联网,就必须要在终端上配置IPv6地址

用到的一些协议也有不同 icmp6 DHCPv6 等

生成方式

被这玩意坑过

ip util

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def test_is_ip_interface():
    assert is_ip_interface('127.0.0.1') is True
    assert is_ip_interface('127.0.0.0/24') is True
    assert is_ip_interface('test') is False


def test_ip_range():
    network = ip_range('192.168.0.0/28')
    assert str(network) == '192.168.0.0/28'
    assert str(min(network)) == '192.168.0.0'
    assert str(max(network)) == '192.168.0.15'
    assert min(network) < ip('192.168.0.4') < max(network)

    network = ip_range('192.168.0.0/98')
    assert network is None

    assert ipaddress.ip_address('10.118.0.18') in ip_range('10.118.0.0/22')


def test_ipv6():
    f = ip('1050:0:0:0:5:600:300c:326b')
    b = f.packed
    assert str(ip(b)) == '1050::5:600:300c:326b'

    f = ip_range('2001:0:0:CD30::/123')
    c = ip('2001:0:0:CD30::10')
    assert c in f
    a, b = str(min(f)), str(max(f))
    assert a == '2001:0:0:cd30::'
    assert b == '2001:0:0:cd30::1f'

    assert min(f).packed < c.packed < max(f).packed

当网段主机数很大的时候要获取网段第一个地址和最后地址通过min max会很慢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def get_first_last_ip(iprange: typing.Union[str, ipaddress.IPv4Network, ipaddress.IPv6Network]) -> typing.Tuple[
        typing.Union[None, ipaddress.IPv4Address, ipaddress.IPv6Address],
        typing.Union[None, ipaddress.IPv4Address, ipaddress.IPv6Address]]:
    """
    获取网段第一个和最后一个ip
    :param iprange:
    :return:
    """
    if isinstance(iprange, str):
        net = ip_range(iprange)
        if net is None:
            return None, None
    else:
        net = iprange
    try:
        mask = ip(net.with_netmask.split('/')[0])
        host_mask = net.hostmask
        last_ip = int(mask) | int(host_mask)
        return mask, ip(last_ip)
    except Exception:
        return None, None
1
2
3
4
5
6
7
8
9
10
11
12
13

// 通过To4 判断ipvx
IP := "10.119.1.107"
fmt.Println([]byte(net.ParseIP(IP)))    // [0 0 0 0 0 0 0 0 0 0 255 255 10 119 1 107]
fmt.Println([]byte(net.ParseIP(IP).To4())) // [10 119 1 107]
fmt.Println([]byte(net.ParseIP(IP).To16())) // [0 0 0 0 0 0 0 0 0 0 255 255 10 119 1 107]

IP = "2001:4860:4860::8888"
fmt.Println([]byte(net.ParseIP(IP)))        // [32 1 72 96 72 96 0 0 0 0 0 0 0 0 136 136]
fmt.Println([]byte(net.ParseIP(IP).To4()))  // []
fmt.Println([]byte(net.ParseIP(IP).To16())) // [32 1 72 96 72 96 0 0 0 0 0 0 0 0 136 136]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// GetFirstAndLastIP4 获取 IPv4 段里第一个和最后一个 IP
func GetFirstAndLastIP4(iprange string) (firstIPInt, lastIPInt uint32, err error) {
	ip, ipNet, err := net.ParseCIDR(iprange)
	if err != nil {
		log.Warnf("invalid iprange: %s", iprange)
		return
	}

	firstIP := ip.Mask(ipNet.Mask)
	firstIPInt = IP2Int(firstIP)
	ipNetMaskInt := binary.BigEndian.Uint32(ipNet.Mask)
	lastIPInt = firstIPInt | ^ipNetMaskInt
	return
}

// GetFirstAndLastIP6 获取 IPv6 段里第一个和最后一个 IP
func GetFirstAndLastIP6(iprange string) (firstIP6, lastIP6 []byte, err error) {
	ip, ipNet, err := net.ParseCIDR(iprange)
	if err != nil {
		log.Warnf("invalid iprange: %s", iprange)
		return
	}

	firstIP6 = []byte(ip.Mask(ipNet.Mask))
	lastIP6 = make([]byte, net.IPv6len)
	for i, b := range firstIP6 {
		m := ipNet.Mask[i]
		lastIP6[i] = b | ^m
	}
	return
}