2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
19 #include <loc/libloc.h>
20 #include <loc/database.h>
22 #include "locationmodule.h"
28 static PyObject
* Database_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
29 DatabaseObject
* self
= (DatabaseObject
*)type
->tp_alloc(type
, 0);
31 return (PyObject
*)self
;
34 static void Database_dealloc(DatabaseObject
* self
) {
36 loc_database_unref(self
->db
);
41 Py_TYPE(self
)->tp_free((PyObject
* )self
);
44 static int Database_init(DatabaseObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
45 const char* path
= NULL
;
47 if (!PyArg_ParseTuple(args
, "s", &path
))
50 self
->path
= strdup(path
);
52 // Open the file for reading
53 FILE* f
= fopen(self
->path
, "r");
55 PyErr_SetFromErrno(PyExc_IOError
);
60 int r
= loc_database_new(loc_ctx
, &self
->db
, f
);
63 // Return on any errors
70 static PyObject
* Database_repr(DatabaseObject
* self
) {
71 return PyUnicode_FromFormat("<Database %s>", self
->path
);
74 static PyObject
* Database_verify(DatabaseObject
* self
, PyObject
* args
) {
75 PyObject
* public_key
= NULL
;
79 if (!PyArg_ParseTuple(args
, "O", &public_key
))
83 int fd
= PyObject_AsFileDescriptor(public_key
);
87 // Re-open file descriptor
90 PyErr_SetFromErrno(PyExc_IOError
);
94 int r
= loc_database_verify(self
->db
, f
);
102 static PyObject
* Database_get_description(DatabaseObject
* self
) {
103 const char* description
= loc_database_get_description(self
->db
);
105 return PyUnicode_FromString(description
);
108 static PyObject
* Database_get_vendor(DatabaseObject
* self
) {
109 const char* vendor
= loc_database_get_vendor(self
->db
);
111 return PyUnicode_FromString(vendor
);
114 static PyObject
* Database_get_license(DatabaseObject
* self
) {
115 const char* license
= loc_database_get_license(self
->db
);
117 return PyUnicode_FromString(license
);
120 static PyObject
* Database_get_created_at(DatabaseObject
* self
) {
121 time_t created_at
= loc_database_created_at(self
->db
);
123 return PyLong_FromLong(created_at
);
126 static PyObject
* Database_get_as(DatabaseObject
* self
, PyObject
* args
) {
127 struct loc_as
* as
= NULL
;
130 if (!PyArg_ParseTuple(args
, "i", &number
))
133 // Try to retrieve the AS
134 int r
= loc_database_get_as(self
->db
, &as
, number
);
138 PyObject
* obj
= new_as(&ASType
, as
);
152 static PyObject
* Database_get_country(DatabaseObject
* self
, PyObject
* args
) {
153 const char* country_code
= NULL
;
155 if (!PyArg_ParseTuple(args
, "s", &country_code
))
158 struct loc_country
* country
;
159 int r
= loc_database_get_country(self
->db
, &country
, country_code
);
164 PyObject
* obj
= new_country(&CountryType
, country
);
165 loc_country_unref(country
);
170 static PyObject
* Database_lookup(DatabaseObject
* self
, PyObject
* args
) {
171 struct loc_network
* network
= NULL
;
172 const char* address
= NULL
;
174 if (!PyArg_ParseTuple(args
, "s", &address
))
177 // Try to retrieve a matching network
178 int r
= loc_database_lookup_from_string(self
->db
, address
, &network
);
182 PyObject
* obj
= new_network(&NetworkType
, network
);
183 loc_network_unref(network
);
192 } else if (r
== -EINVAL
) {
193 PyErr_Format(PyExc_ValueError
, "Invalid IP address: %s", address
);
201 static PyObject
* new_database_enumerator(PyTypeObject
* type
, struct loc_database_enumerator
* enumerator
) {
202 DatabaseEnumeratorObject
* self
= (DatabaseEnumeratorObject
*)type
->tp_alloc(type
, 0);
204 self
->enumerator
= loc_database_enumerator_ref(enumerator
);
207 return (PyObject
*)self
;
210 static PyObject
* Database_iterate_all(DatabaseObject
* self
, enum loc_database_enumerator_mode what
, int flags
) {
211 struct loc_database_enumerator
* enumerator
;
213 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, what
, flags
);
215 PyErr_SetFromErrno(PyExc_SystemError
);
219 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
220 loc_database_enumerator_unref(enumerator
);
225 static PyObject
* Database_ases(DatabaseObject
* self
) {
226 return Database_iterate_all(self
, LOC_DB_ENUMERATE_ASES
, 0);
229 static PyObject
* Database_search_as(DatabaseObject
* self
, PyObject
* args
) {
230 const char* string
= NULL
;
232 if (!PyArg_ParseTuple(args
, "s", &string
))
235 struct loc_database_enumerator
* enumerator
;
237 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, LOC_DB_ENUMERATE_ASES
, 0);
239 PyErr_SetFromErrno(PyExc_SystemError
);
243 // Search string we are searching for
244 loc_database_enumerator_set_string(enumerator
, string
);
246 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
247 loc_database_enumerator_unref(enumerator
);
252 static PyObject
* Database_networks(DatabaseObject
* self
) {
253 return Database_iterate_all(self
, LOC_DB_ENUMERATE_NETWORKS
, 0);
256 static PyObject
* Database_networks_flattened(DatabaseObject
*self
) {
257 return Database_iterate_all(self
, LOC_DB_ENUMERATE_NETWORKS
, LOC_DB_ENUMERATOR_FLAGS_FLATTEN
);
260 static PyObject
* Database_search_networks(DatabaseObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
261 char* kwlist
[] = { "country_codes", "asn", "flags", "family", "flatten", NULL
};
262 PyObject
* country_codes
= NULL
;
263 unsigned int asn
= 0;
268 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|O!iiip", kwlist
,
269 &PyList_Type
, &country_codes
, &asn
, &flags
, &family
, &flatten
))
272 struct loc_database_enumerator
* enumerator
;
273 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, LOC_DB_ENUMERATE_NETWORKS
,
274 (flatten
) ? LOC_DB_ENUMERATOR_FLAGS_FLATTEN
: 0);
276 PyErr_SetFromErrno(PyExc_SystemError
);
280 // Set country code we are searching for
282 struct loc_country_list
* countries
;
283 r
= loc_country_list_new(loc_ctx
, &countries
);
285 PyErr_SetString(PyExc_SystemError
, "Could not create country list");
289 for (unsigned int i
= 0; i
< PyList_Size(country_codes
); i
++) {
290 PyObject
* item
= PyList_GetItem(country_codes
, i
);
292 if (!PyUnicode_Check(item
)) {
293 PyErr_SetString(PyExc_TypeError
, "Country codes must be strings");
294 loc_country_list_unref(countries
);
298 const char* country_code
= PyUnicode_AsUTF8(item
);
300 struct loc_country
* country
;
301 r
= loc_country_new(loc_ctx
, &country
, country_code
);
304 PyErr_Format(PyExc_ValueError
, "Invalid country code: %s", country_code
);
306 PyErr_SetString(PyExc_SystemError
, "Could not create country");
309 loc_country_list_unref(countries
);
313 // Append it to the list
314 r
= loc_country_list_append(countries
, country
);
316 PyErr_SetString(PyExc_SystemError
, "Could not append country to the list");
318 loc_country_list_unref(countries
);
319 loc_country_unref(country
);
323 loc_country_unref(country
);
326 loc_database_enumerator_set_countries(enumerator
, countries
);
328 Py_DECREF(country_codes
);
329 loc_country_list_unref(countries
);
332 // Set the ASN we are searching for
334 r
= loc_database_enumerator_set_asn(enumerator
, asn
);
337 PyErr_SetFromErrno(PyExc_SystemError
);
342 // Set the flags we are searching for
344 r
= loc_database_enumerator_set_flag(enumerator
, flags
);
347 PyErr_SetFromErrno(PyExc_SystemError
);
352 // Set the family we are searching for
354 r
= loc_database_enumerator_set_family(enumerator
, family
);
357 PyErr_SetFromErrno(PyExc_SystemError
);
362 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
363 loc_database_enumerator_unref(enumerator
);
368 static PyObject
* Database_countries(DatabaseObject
* self
) {
369 return Database_iterate_all(self
, LOC_DB_ENUMERATE_COUNTRIES
, 0);
372 static struct PyMethodDef Database_methods
[] = {
375 (PyCFunction
)Database_get_as
,
381 (PyCFunction
)Database_get_country
,
387 (PyCFunction
)Database_lookup
,
393 (PyCFunction
)Database_search_as
,
399 (PyCFunction
)Database_search_networks
,
400 METH_VARARGS
|METH_KEYWORDS
,
405 (PyCFunction
)Database_verify
,
412 static struct PyGetSetDef Database_getsetters
[] = {
415 (getter
)Database_ases
,
422 (getter
)Database_countries
,
429 (getter
)Database_get_created_at
,
436 (getter
)Database_get_description
,
443 (getter
)Database_get_license
,
450 (getter
)Database_networks
,
456 "networks_flattened",
457 (getter
)Database_networks_flattened
,
464 (getter
)Database_get_vendor
,
472 PyTypeObject DatabaseType
= {
473 PyVarObject_HEAD_INIT(NULL
, 0)
474 .tp_name
= "location.Database",
475 .tp_basicsize
= sizeof(DatabaseObject
),
476 .tp_flags
= Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
,
477 .tp_new
= Database_new
,
478 .tp_dealloc
= (destructor
)Database_dealloc
,
479 .tp_init
= (initproc
)Database_init
,
480 .tp_doc
= "Database object",
481 .tp_methods
= Database_methods
,
482 .tp_getset
= Database_getsetters
,
483 .tp_repr
= (reprfunc
)Database_repr
,
486 static PyObject
* DatabaseEnumerator_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
487 DatabaseEnumeratorObject
* self
= (DatabaseEnumeratorObject
*)type
->tp_alloc(type
, 0);
489 return (PyObject
*)self
;
492 static void DatabaseEnumerator_dealloc(DatabaseEnumeratorObject
* self
) {
493 loc_database_enumerator_unref(self
->enumerator
);
495 Py_TYPE(self
)->tp_free((PyObject
* )self
);
498 static PyObject
* DatabaseEnumerator_next(DatabaseEnumeratorObject
* self
) {
499 struct loc_network
* network
= NULL
;
501 // Enumerate all networks
502 int r
= loc_database_enumerator_next_network(self
->enumerator
, &network
);
504 PyErr_SetFromErrno(PyExc_ValueError
);
508 // A network was found
510 PyObject
* obj
= new_network(&NetworkType
, network
);
511 loc_network_unref(network
);
516 // Enumerate all ASes
517 struct loc_as
* as
= NULL
;
519 r
= loc_database_enumerator_next_as(self
->enumerator
, &as
);
521 PyErr_SetFromErrno(PyExc_ValueError
);
526 PyObject
* obj
= new_as(&ASType
, as
);
532 // Enumerate all countries
533 struct loc_country
* country
= NULL
;
535 r
= loc_database_enumerator_next_country(self
->enumerator
, &country
);
537 PyErr_SetFromErrno(PyExc_ValueError
);
542 PyObject
* obj
= new_country(&CountryType
, country
);
543 loc_country_unref(country
);
548 // Nothing found, that means the end
549 PyErr_SetNone(PyExc_StopIteration
);
553 PyTypeObject DatabaseEnumeratorType
= {
554 PyVarObject_HEAD_INIT(NULL
, 0)
555 .tp_name
= "location.DatabaseEnumerator",
556 .tp_basicsize
= sizeof(DatabaseEnumeratorObject
),
557 .tp_flags
= Py_TPFLAGS_DEFAULT
,
558 .tp_alloc
= PyType_GenericAlloc
,
559 .tp_new
= DatabaseEnumerator_new
,
560 .tp_dealloc
= (destructor
)DatabaseEnumerator_dealloc
,
561 .tp_iter
= PyObject_SelfIter
,
562 .tp_iternext
= (iternextfunc
)DatabaseEnumerator_next
,