3 # Wireshark - Network traffic analyzer
4 # By Gerald Combs <gerald@wireshark.org>
5 # Copyright 1998 Gerald Combs
7 # SPDX-License-Identifier: GPL-2.0-or-later
8 '''Update the IANA IP registry file.
10 Make-iana-ip creates a file containing information about IPv4/IPv6 allocation blocks.
19 import urllib
.request
, urllib
.error
, urllib
.parse
21 def exit_msg(msg
=None, status
=1):
23 sys
.stderr
.write(msg
+ '\n\n')
24 sys
.stderr
.write(__doc__
+ '\n')
29 Returns a tuple containing the body and response dict. The body is a
30 str in Python 3 and bytes in Python 2 in order to be compatible with
35 url_path
= os
.path
.join(sys
.argv
[1], url
[1])
36 url_fd
= open(url_path
)
40 url_path
= '/'.join(url
)
42 req_headers
= { 'User-Agent': 'Wireshark iana-ip' }
44 req
= urllib
.request
.Request(url_path
, headers
=req_headers
)
45 response
= urllib
.request
.urlopen(req
)
46 body
= response
.read().decode('UTF-8', 'replace')
48 exit_msg('Error opening ' + url_path
)
52 class IPv4SpecialBlock(ipaddress
.IPv4Network
):
54 def ip_get_subnet_mask(bits
):
57 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
58 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
59 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
60 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
61 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
62 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
63 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
64 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff)
66 ValueError("Expected bit mask less or equal to 32")
70 addr
= self
.network_address
72 line
= '{{ .ipv4 = {{ {:#x}, {:#010x} }} }}'.format(addr
, self
.ip_get_subnet_mask(mask
))
75 class IPv6SpecialBlock(ipaddress
.IPv6Network
):
77 def addr_c_array(byte_array
):
78 if len(byte_array
) != 16:
79 raise ValueError("Expected byte array of length 16")
80 c_array
= ", ".join(f
"0x{byte:02x}" for byte
in byte_array
)
81 return f
"{{ {c_array} }}"
84 addr
= self
.network_address
.packed
86 line
= '{{ .ipv6 = {{ {}, {} }} }}'.format(self
.addr_c_array(addr
), mask
)
89 class IPRegistry(list):
91 def true_or_false(val
):
99 def append(self
, row
):
100 ip
, name
, _
, _
, termin_date
, source
, destination
, forward
, glob
, reserved
= row
101 if termin_date
[0].isdigit():
102 # skip allocations that have expired
104 name
= re
.sub(r
'\[.*\]', '', name
)
105 name
= '"' + name
.replace('"', '\\"') + '"'
106 source
= self
.true_or_false(source
)
107 destination
= self
.true_or_false(destination
)
108 forward
= self
.true_or_false(forward
)
109 glob
= self
.true_or_false(glob
)
110 reserved
= self
.true_or_false(reserved
)
111 super().append([ip
, name
, source
, destination
, forward
, glob
, reserved
])
113 class IPv4Registry(IPRegistry
):
115 def ipv4_addr_and_mask(s
):
116 ip
= IPv4SpecialBlock(s
)
119 def append(self
, row
):
120 # some lines contain multiple (comma separated) blocks
121 ip_list
= row
[0].split(',')
123 # remove annotations like "1.1.1.1 [2]"
124 ip_str
= s
.split()[0]
125 row
= [self
.ipv4_addr_and_mask(ip_str
)] + row
[1:]
130 fill_data
= '_U_ static const struct ws_iana_ip_special_block __ipv4_special_block[] = {\n'
132 line
= ' {{ 4, {}, {}, {}, {}, {}, {}, {} }},\n'.format(*row
)
137 class IPv6Registry(IPRegistry
):
139 def ipv6_addr_and_mask(s
):
140 ip_str
= s
.split()[0]
141 ip
= IPv6SpecialBlock(ip_str
)
144 def append(self
, row
):
145 # remove annotations like "1.1.1.1 [2]"
146 ip_str
= row
[0].split()[0]
147 row
= [self
.ipv6_addr_and_mask(ip_str
)] + row
[1:]
152 fill_data
= '// GCC bug?\n'
153 fill_data
+= 'DIAG_OFF(missing-braces)\n'
154 fill_data
+= '_U_ static const struct ws_iana_ip_special_block __ipv6_special_block[] = {\n'
158 {}, {}, {}, {}, {}, {} }},\n'''.format(*row
)
161 fill_data
+= 'DIAG_ON(missing-braces)\n'
165 'IPv4': { 'url': ["https://www.iana.org/assignments/iana-ipv4-special-registry", "iana-ipv4-special-registry-1.csv"], 'min_entries': 2 },
166 'IPv6': { 'url': ["https://www.iana.org/assignments/iana-ipv6-special-registry", "iana-ipv6-special-registry-1.csv"], 'min_entries': 2 },
169 def dump_registry(db
, reg
):
170 db_url
= IANA_URLS
[db
]['url']
171 print('Loading {} data from {}'.format(db
, db_url
))
172 body
= open_url(db_url
)
173 iana_csv
= csv
.reader(body
.splitlines())
177 for iana_row
in iana_csv
:
178 # Address Block,Name,RFC,Allocation Date,Termination Date,Source,Destination,Forwardable,Globally Reachable,Reserved-by-Protocol
179 # ::1/128,Loopback Address,[RFC4291],2006-02,N/A,False,False,False,False,True
182 if len(reg
) < IANA_URLS
[db
]['min_entries']:
183 exit_msg("Too few {} entries. Got {}, wanted {}".format(db
, len(reg
), IANA_URLS
[db
]['min_entries']))
188 iana_path
= os
.path
.join(os
.path
.dirname(__file__
), '..', 'epan', 'iana-ip-data.c')
192 * This file was generated by running ./tools/make-iana-ip.py.
194 * SPDX-License-Identifier: GPL-2.0-or-later
201 iana_data
+= dump_registry('IPv4', IPv4Registry())
203 iana_data
+= dump_registry('IPv6', IPv6Registry())
206 with io
.open(iana_path
, 'w', encoding
='UTF-8') as iana_f
:
207 iana_f
.write(iana_data
)
209 exit_msg("Couldn't open \"{}\" file for writing".format(iana_path
))
211 if __name__
== '__main__':