Skip to content

Commit 76dc816

Browse files
committed
Add get_with_prefix_len to C extension
1 parent 2687c23 commit 76dc816

File tree

1 file changed

+42
-11
lines changed

1 file changed

+42
-11
lines changed

extension/maxminddb.c

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ typedef struct {
3131
PyObject *record_size;
3232
} Metadata_obj;
3333

34+
static int get_record(PyObject *self, PyObject *args, PyObject **record);
3435
static bool format_sockaddr(struct sockaddr *addr, char *dst);
3536
static PyObject *from_entry_data_list(MMDB_entry_data_list_s **entry_data_list);
3637
static PyObject *from_map(MMDB_entry_data_list_s **entry_data_list);
@@ -111,24 +112,43 @@ static int Reader_init(PyObject *self, PyObject *args, PyObject *kwds)
111112

112113
static PyObject *Reader_get(PyObject *self, PyObject *args)
113114
{
114-
MMDB_s *mmdb = ((Reader_obj *)self)->mmdb;
115+
PyObject *record = NULL;
116+
if (get_record(self, args, &record) == -1) {
117+
return NULL;
118+
}
119+
return record;
120+
}
115121

122+
static PyObject *Reader_get_with_prefix_len(PyObject *self, PyObject *args)
123+
{
124+
PyObject *record = NULL;
125+
int prefix_len = get_record(self, args, &record);
126+
if (prefix_len == -1) {
127+
return NULL;
128+
}
129+
130+
return PyTuple_Pack(2, record, PyLong_FromLong(prefix_len));
131+
}
132+
133+
static int get_record(PyObject *self, PyObject *args, PyObject **record)
134+
{
135+
MMDB_s *mmdb = ((Reader_obj *)self)->mmdb;
116136
if (NULL == mmdb) {
117137
PyErr_SetString(PyExc_ValueError,
118138
"Attempt to read from a closed MaxMind DB.");
119-
return NULL;
139+
return -1;
120140
}
121141

122142
struct sockaddr_storage ip_address_ss = { 0 };
123143
struct sockaddr *ip_address = (struct sockaddr *)&ip_address_ss;
124144
if (!PyArg_ParseTuple(args, "O&", ip_converter, &ip_address_ss)) {
125-
return NULL;
145+
return -1;
126146
}
127147

128148
if (!ip_address->sa_family) {
129149
PyErr_SetString(PyExc_ValueError,
130150
"Error parsing argument");
131-
return NULL;
151+
return -1;
132152
}
133153

134154
int mmdb_error = MMDB_SUCCESS;
@@ -147,11 +167,19 @@ static PyObject *Reader_get(PyObject *self, PyObject *args)
147167
PyErr_Format(exception, "Error looking up %s. %s",
148168
ipstr, MMDB_strerror(mmdb_error));
149169
}
150-
return NULL;
170+
return -1;
171+
}
172+
173+
int prefix_len = result.netmask;
174+
if (ip_address->sa_family == AF_INET && mmdb->metadata.ip_version == 6) {
175+
// We return the prefix length given the IPv4 address. If there is
176+
// no IPv4 subtree, we return a prefix length of 0.
177+
prefix_len = prefix_len >= 96 ? prefix_len - 96 : 0;
151178
}
152179

153180
if (!result.found_entry) {
154-
Py_RETURN_NONE;
181+
*record = Py_None;
182+
return prefix_len;
155183
}
156184

157185
MMDB_entry_data_list_s *entry_data_list = NULL;
@@ -164,13 +192,14 @@ static PyObject *Reader_get(PyObject *self, PyObject *args)
164192
ipstr, MMDB_strerror(status));
165193
}
166194
MMDB_free_entry_data_list(entry_data_list);
167-
return NULL;
195+
return -1;
168196
}
169197

170198
MMDB_entry_data_list_s *original_entry_data_list = entry_data_list;
171-
PyObject *py_obj = from_entry_data_list(&entry_data_list);
199+
*record = from_entry_data_list(&entry_data_list);
172200
MMDB_free_entry_data_list(original_entry_data_list);
173-
return py_obj;
201+
202+
return prefix_len;
174203
}
175204

176205
static int ip_converter(PyObject *obj, struct sockaddr_storage *ip_address)
@@ -589,9 +618,11 @@ static PyObject *from_uint128(const MMDB_entry_data_list_s *entry_data_list)
589618

590619
static PyMethodDef Reader_methods[] = {
591620
{ "get", Reader_get, METH_VARARGS,
592-
"Get record for IP address" },
621+
"Return the record for the ip_address in the MaxMind DB" },
622+
{ "get_with_prefix_len", Reader_get_with_prefix_len, METH_VARARGS,
623+
"Return a tuple with the record and the associated prefix length" },
593624
{ "metadata", Reader_metadata, METH_NOARGS,
594-
"Returns metadata object for database" },
625+
"Return metadata object for database" },
595626
{ "close", Reader_close, METH_NOARGS, "Closes database"},
596627
{ "__exit__", Reader__exit__, METH_VARARGS, "Called when exiting a with-context. Calls close"},
597628
{ "__enter__", Reader__enter__, METH_NOARGS, "Called when entering a with-context."},

0 commit comments

Comments
 (0)