如何在python子列表中填写未使用的ip地址?

2024-05-15 20:39:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我创建了一个python脚本,试图让我作为系统管理员的生活轻松许多。 此脚本的目的是将Microsoft DHCP服务器转储文件转换为已排序的CSV文件。在

我将在这里包括代码,并感谢所有种类的改进。在

我的问题

我的脚本创建一个列表列表(每个dhcp保留一个)。例如:

[
  # [DHCP SERVER, IP ADDRESS, MAC ADDRESS, HOSTNAME, DESCRIPTION]
  [server1,172.16.0.120,31872fcefa33,wks120.domain.net,Description of client]
  [server1,172.16.0.125,4791ca3d7279,wks125.domain.net,Description of client]
  [server1,172.16.0.132,6035a71c930c,wks132.domain.net,Description of client]
  ...
]

未使用的ip地址未列出。但是我希望我的脚本自动为所有未使用的IP地址添加子列表,并给它们一个注释“Unregistered”或其他东西。在

我甚至不知道如何开始在谷歌搜索如何完成这项任务,所以任何帮助都将不胜感激:)

脚本

^{pr2}$

注意:我也尝试过使用python socket.inet_ntoa进行IPv4排序,但没有成功地让它正常工作。在

转储文件示例

根据请求,这里是一些转储文件

[Ommited content]

# ======================================================================
#  Start Add ReservedIp to the Scope : 172.16.0.0, Server : server1.domain.net            
# ======================================================================


    Dhcp Server \\server1.domain.net Scope 172.16.0.0 Add reservedip 172.16.0.76 0800278882ae "wks126devlin.domain.net" "Viana (VM)" "BOTH"
    Dhcp Server \\server1.domain.net Scope 172.16.0.0 Add reservedip 172.16.0.118 001e37322202 "WKS18.domain.net" "Kristof (linux)" "BOTH"
    Dhcp Server \\server1.domain.net Scope 172.16.0.0 Add reservedip 172.16.0.132 000d607205a5 "WKS32.domain.net" "Lab PC" "BOTH"
    Dhcp Server \\server1.domain.net Scope 172.16.0.0 Add reservedip 172.16.0.156 338925b532ca "wks56.domain.net" "Test PC" "BOTH"
    Dhcp Server \\server1.domain.net Scope 172.16.0.0 Add reservedip 172.16.0.155 001422a7d474 "WKS55.domain.net" "Liesbeth" "BOTH"
    Dhcp Server \\server1.domain.net Scope 172.16.0.0 Add reservedip 172.16.0.15 0800266cfe31 "xpsystst.domain.net" "Pascal (VM)" "BOTH"

[Ommited content]

Tags: 文件of脚本clientadd列表netserver
3条回答

我首先创建一个包含所有空预订的列表,然后用您开始使用的非空列表覆盖它:

#!/usr/bin/env python

reservations = [
    # [DHCP SERVER, IP ADDRESS, MAC ADDRESS, HOSTNAME, DESCRIPTION]
    ['server1','172.16.0.120','31872fcefa33','wks120.domain.net','Description of client'],
    ['server1','172.16.0.125','4791ca3d7279','wks125.domain.net','Description of client'],
    ['server1','172.16.0.132','6035a71c930c','wks132.domain.net','Description of client'],
]

def reservationlist(reservations, serverpattern, addresspattern, hostpattern,
        start, end):
    result = []
    for i in range(start, end + 1):
        result.append([
            serverpattern % i,
            addresspattern % i,
            '[no mac]',
            hostpattern % i,
            'Unregistered'])

    for reservation in reservations:
        index = int(reservation[1].split('.')[3]) - start
        result[index] = reservation

    return result

print reservationlist(
    reservations,
    'server%d',
    '172.16.0.%d',
    'wks%d.domain.net',
    120,
    132)

最终结果如下:

^{pr2}$

呸!我情不自禁。此版本接受起始值和结束值的IP地址:

#!/usr/bin/env python

reservations = [
    # [DHCP SERVER, IP ADDRESS, MAC ADDRESS, HOSTNAME, DESCRIPTION]
    ['server1','172.16.0.120','31872fcefa33','wks120.domain.net','Description of client'],
    ['server1','172.16.0.125','4791ca3d7279','wks125.domain.net','Description of client'],
    ['server1','172.16.0.132','6035a71c930c','wks132.domain.net','Description of client'],
]

def addr_to_int(address):
    """Convert an IP address to a 32-bit int"""
    a, b, c, d = map(int, address.split('.'))
    return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d

def int_to_addr(value):
    """Convert a 32-bit int into a tuple of its IPv4 byte values"""
    return value >> 24, value >> 16 & 255, value >> 8 & 255, value & 255

def reservationlist(reservations, serverpattern, addresspattern, hostpattern,
        start, end):

    reservationdict = dict((addr_to_int(item[1]), item)
            for item in reservations)
    startint = addr_to_int(start)
    endint = addr_to_int(end)
    for i in range(startint, endint + 1):
        try:
            item = reservationdict[i]
        except KeyError:
            addressbytes = int_to_addr(i)
            item = [
                serverpattern.format(*addressbytes),
                addresspattern.format(*addressbytes),
                '[no mac]',
                hostpattern.format(*addressbytes),
                'Unregistered']
        yield item

for entry in reservationlist(
    reservations,
    'server{3}',
    '172.16.{2}.{3}',
    'wks{3}.domain.net',
    '172.16.0.120',
    '172.16.1.132'):
    print entry

此版本使用yield关键字将reservationlist()转换为生成器。它不是一次保存RAM中的所有值,而是一次只发出一个值,直到循环结束。对于循环的每一次传递,它都会尝试从保留列表中获取实际值(使用dict快速访问)。如果不能,则使用string.format方法用IPv4地址字节填充字符串模板。在

地址操作的速记

int_to_addr函数采用32位IP地址,如:

AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD

并返回4个字节,范围为0-255,如:

AAAAAAAA, BBBBBBBB, CCCCCCCC, DDDDDDDD

在该函数中,>>表示“将值向右旋转多个位”,“amp;255”表示“只返回最后8位(128+64+32+16+8+4+2+1)”。在

如果我们在上面输入了“AAAA…DDDD”号码:

  • value >> 24=>;AAAAAAAA
  • value >> 16=>;aaaaaaaa bbbbbb。该值&255=>;BBBBBBBB
  • value >> 8=>;aaaaaaaa-bbbbbb-cccccccc。该值&255=>CCCCCC
  • value & 255=>;DDDDDDDD

这或多或少是将32位IPv4地址转换为4字节列表的标准方法。当你把这些值和一个点连在一起时,你会得到正常的“a.B.C.D”地址格式。在

和纽比完蛋了

import numpy as np

reservations = [
    # [DHCP SERVER, IP ADDRESS, MAC ADDRESS, HOSTNAME, DESCRIPTION]
    ['server1','172.16.0.120','31872fcefa33','wks120.domain.net',
    'Description of client'],
    ['server1','172.16.0.125','4791ca3d7279','wks125.domain.net',
    'Description of client'],
    ['server1','172.16.0.132','6035a71c930c','wks132.domain.net',
    'Description of client'],
]
occupied_ip = []
for i in reservations:
    occupied_ip.append(int(i[1][-3:]))
occupied_ip = np.array(occupied_ip)

iplist = np.arange(256)
idx = np.in1d(iplist,occupied_ip)    #Where are the two arrays equual?
idx = np.logical_not(idx)            #Where are they NOT equal
freeip = iplist[idx]

unreserved = []
for i in range(len(freeip)):
    unreserved.append(["server1", "172.16.0."+str(freeip[i]), "Unassigned MAC",
    "unknown domain"])
    print unreserved[i]

生产

^{pr2}$

以下是一个计划:

  1. int中转换所有IP。也就是说,IP[0]*(256**3) + IP[1]*(256**2) + IP[2]*256 + IP[3]表示IPv4。在
  2. 把你得到的所有IP存储在一个dict中,IP作为密钥
  3. 迭代子网的所有IP(作为int,使用range()表示),并对每个IP使用get()dict。如果get()返回None,则打印默认消息和当前IP。否则,打印返回的列表。在

所以,我们计划的第一步:

def ip_tuple2int(ip_tuple):
     return sum(ip_part * 256**(len(ip_tuple) - no) for no, ip_part in enumerate(ip_tuple, start=1))

我们需要一个函数来打印这些。假设我们使用:

^{pr2}$

第二步:

d = {}
for rec in records:
    d[ip_tuple2int(ip2tuple(rec[1]))] = rec

第三步,我们需要网络掩码。我们假设它存储在nmask中,如下:nmask = ip_tuple2int(ip2tuple("255.255.254.0"))(是的,这个掩码是不寻常的,因为它最好能解决更一般的问题。在

min_ip = d.keys()[0] & nmask
max_ip = min_ip | nmask ^ 2**int(math.ceil(math.log(nmask, 2))) - 1
    # the right-hand of the '|' is just the bitwise inversion of nmask
    # because ~nmask gives a negative number in python

for ip_int in range(min_ip, max_ip + 1):
    row = d.get(ip_int)
    if row:
        print row
    else:
        print [None, ip_int2str(ip_int), None, None, None]

一。在

所以,这就结束了解决方案。这里提供的代码同时支持IPv4和IPv6:它已经在两种情况下的一些输入上进行了测试,如下所示ip2tuple()

def ip2tuple(ip_str):
    try:
        ip_bin = socket.inet_pton(socket.AF_INET, ip_str)
    except socket.error:
        ip_bin = socket.inet_pton(socket.AF_INET6, ip_str)

    return [ord(c) for c in ip_bin]

如果你还想接受IPv6,你的问题中的代码还需要修改。在

最后,此代码还支持任何网络掩码,只要地址类型的最高有效位已设置。在

编辑:关于两个复杂行的更多信息:min_ip和max_ip

所以,我们

min_ip = d.keys()[0] & nmask
max_ip = min_ip | nmask ^ 2**int(math.ceil(math.log(nmask, 2))) - 1

计算我们范围内的最小和最大ip。让我们把它们拆开!在

min_ip = d.keys()[0] & nmask

我们在这里取一个任意的ip d.keys()[0],它与网络掩码一起使用:我们保留ip中不变的位,并将构成变量部分的位归零。在

max_ip = min_ip | nmask ^ 2**int(math.ceil(math.log(nmask, 2))) - 1

为了计算最大ip,我们取存储在min_ip中的子网ip的常量部分,并“添加”(二进制或)ip的可变部分,所有位都设置为1。 这是通过计算一个与nmask 2**int(math.ceil(math.log(nmask, 2))) - 1大小相同的二进制行和使用nmask的XOR来实现的,这样nmask中设置为1的所有位都变为0,网络掩码的所有低位0都变为1。在

为什么要这样做?因为即使不太清楚,它也会自动适应地址类型。它甚至可以支持4096位地址,甚至更多!在

相关问题 更多 >