This file is indexed.

/usr/lib/python3/dist-packages/maxminddb/reader.py is in python3-maxminddb 1.3.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
"""
maxminddb.reader
~~~~~~~~~~~~~~~~

This module contains the pure Python database reader and related classes.

"""
from __future__ import unicode_literals

try:
    import mmap
except ImportError:
    # pylint: disable=invalid-name
    mmap = None

import struct

from maxminddb.compat import byte_from_int, compat_ip_address
from maxminddb.const import MODE_AUTO, MODE_MMAP, MODE_FILE, MODE_MEMORY
from maxminddb.decoder import Decoder
from maxminddb.errors import InvalidDatabaseError
from maxminddb.file import FileBuffer


class Reader(object):
    """
    Instances of this class provide a reader for the MaxMind DB format. IP
    addresses can be looked up using the ``get`` method.
    """

    _DATA_SECTION_SEPARATOR_SIZE = 16
    _METADATA_START_MARKER = b"\xAB\xCD\xEFMaxMind.com"

    _ipv4_start = None

    def __init__(self, database, mode=MODE_AUTO):
        """Reader for the MaxMind DB file format

        Arguments:
        database -- A path to a valid MaxMind DB file such as a GeoIP2
                    database file.
        mode -- mode to open the database with. Valid mode are:
            * MODE_MMAP - read from memory map.
            * MODE_FILE - read database as standard file.
            * MODE_MEMORY - load database into memory.
            * MODE_AUTO - tries MODE_MMAP and then MODE_FILE. Default.
        """
        # pylint: disable=redefined-variable-type
        if (mode == MODE_AUTO and mmap) or mode == MODE_MMAP:
            with open(database, 'rb') as db_file:
                self._buffer = mmap.mmap(
                    db_file.fileno(), 0, access=mmap.ACCESS_READ)
                self._buffer_size = self._buffer.size()
        elif mode in (MODE_AUTO, MODE_FILE):
            self._buffer = FileBuffer(database)
            self._buffer_size = self._buffer.size()
        elif mode == MODE_MEMORY:
            with open(database, 'rb') as db_file:
                self._buffer = db_file.read()
                self._buffer_size = len(self._buffer)
        else:
            raise ValueError(
                'Unsupported open mode ({0}). Only MODE_AUTO, '
                ' MODE_FILE, and MODE_MEMORY are support by the pure Python '
                'Reader'.format(mode))

        metadata_start = self._buffer.rfind(
            self._METADATA_START_MARKER, max(0,
                                             self._buffer_size - 128 * 1024))

        if metadata_start == -1:
            self.close()
            raise InvalidDatabaseError('Error opening database file ({0}). '
                                       'Is this a valid MaxMind DB file?'
                                       ''.format(database))

        metadata_start += len(self._METADATA_START_MARKER)
        metadata_decoder = Decoder(self._buffer, metadata_start)
        (metadata, _) = metadata_decoder.decode(metadata_start)
        self._metadata = Metadata(**metadata)  # pylint: disable=bad-option-value

        self._decoder = Decoder(self._buffer, self._metadata.search_tree_size +
                                self._DATA_SECTION_SEPARATOR_SIZE)
        self.closed = False

    def metadata(self):
        """Return the metadata associated with the MaxMind DB file"""
        return self._metadata

    def get(self, ip_address):
        """Return the record for the ip_address in the MaxMind DB


        Arguments:
        ip_address -- an IP address in the standard string notation
        """

        address = compat_ip_address(ip_address)

        if address.version == 6 and self._metadata.ip_version == 4:
            raise ValueError(
                'Error looking up {0}. You attempted to look up '
                'an IPv6 address in an IPv4-only database.'.format(ip_address))
        pointer = self._find_address_in_tree(address)

        return self._resolve_data_pointer(pointer) if pointer else None

    def _find_address_in_tree(self, ip_address):
        packed = bytearray(ip_address.packed)

        bit_count = len(packed) * 8
        node = self._start_node(bit_count)

        for i in range(bit_count):
            if node >= self._metadata.node_count:
                break
            bit = 1 & (packed[i >> 3] >> 7 - (i % 8))
            node = self._read_node(node, bit)
        if node == self._metadata.node_count:
            # Record is empty
            return 0
        elif node > self._metadata.node_count:
            return node

        raise InvalidDatabaseError('Invalid node in search tree')

    def _start_node(self, length):
        if self._metadata.ip_version != 6 or length == 128:
            return 0

        # We are looking up an IPv4 address in an IPv6 tree. Skip over the
        # first 96 nodes.
        if self._ipv4_start:
            return self._ipv4_start

        node = 0
        for _ in range(96):
            if node >= self._metadata.node_count:
                break
            node = self._read_node(node, 0)
        self._ipv4_start = node
        return node

    def _read_node(self, node_number, index):
        base_offset = node_number * self._metadata.node_byte_size

        record_size = self._metadata.record_size
        if record_size == 24:
            offset = base_offset + index * 3
            node_bytes = b'\x00' + self._buffer[offset:offset + 3]
        elif record_size == 28:
            (middle, ) = struct.unpack(
                b'!B', self._buffer[base_offset + 3:base_offset + 4])
            if index:
                middle &= 0x0F
            else:
                middle = (0xF0 & middle) >> 4
            offset = base_offset + index * 4
            node_bytes = byte_from_int(middle) + self._buffer[offset:offset +
                                                              3]
        elif record_size == 32:
            offset = base_offset + index * 4
            node_bytes = self._buffer[offset:offset + 4]
        else:
            raise InvalidDatabaseError('Unknown record size: {0}'.format(
                record_size))
        return struct.unpack(b'!I', node_bytes)[0]

    def _resolve_data_pointer(self, pointer):
        resolved = pointer - self._metadata.node_count + \
            self._metadata.search_tree_size

        if resolved > self._buffer_size:
            raise InvalidDatabaseError(
                "The MaxMind DB file's search tree is corrupt")

        (data, _) = self._decoder.decode(resolved)
        return data

    def close(self):
        """Closes the MaxMind DB file and returns the resources to the system"""
        # pylint: disable=unidiomatic-typecheck
        if type(self._buffer) not in (str, bytes):
            self._buffer.close()
        self.closed = True

    def __exit__(self, *args):
        self.close()

    def __enter__(self):
        if self.closed:
            raise ValueError('Attempt to reopen a closed MaxMind DB')
        return self


class Metadata(object):
    """Metadata for the MaxMind DB reader"""

    # pylint: disable=too-many-instance-attributes
    def __init__(self, **kwargs):
        """Creates new Metadata object. kwargs are key/value pairs from spec"""
        # Although I could just update __dict__, that is less obvious and it
        # doesn't work well with static analysis tools and some IDEs
        self.node_count = kwargs['node_count']
        self.record_size = kwargs['record_size']
        self.ip_version = kwargs['ip_version']
        self.database_type = kwargs['database_type']
        self.languages = kwargs['languages']
        self.binary_format_major_version = kwargs[
            'binary_format_major_version']
        self.binary_format_minor_version = kwargs[
            'binary_format_minor_version']
        self.build_epoch = kwargs['build_epoch']
        self.description = kwargs['description']

    @property
    def node_byte_size(self):
        """The size of a node in bytes"""
        return self.record_size // 4

    @property
    def search_tree_size(self):
        """The size of the search tree"""
        return self.node_count * self.node_byte_size

    def __repr__(self):
        args = ', '.join('%s=%r' % x for x in self.__dict__.items())
        return '{module}.{class_name}({data})'.format(
            module=self.__module__,
            class_name=self.__class__.__name__,
            data=args)