@@ -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 );
3435static bool format_sockaddr (struct sockaddr * addr , char * dst );
3536static PyObject * from_entry_data_list (MMDB_entry_data_list_s * * entry_data_list );
3637static 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
112113static 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
176205static 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
590619static 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