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 <libloc/libloc.h>
20 #include <libloc/as.h>
21 #include <libloc/as-list.h>
22 #include <libloc/database.h>
24 #include "locationmodule.h"
30 static PyObject
* Database_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
31 DatabaseObject
* self
= (DatabaseObject
*)type
->tp_alloc(type
, 0);
33 return (PyObject
*)self
;
36 static void Database_dealloc(DatabaseObject
* self
) {
38 loc_database_unref(self
->db
);
43 Py_TYPE(self
)->tp_free((PyObject
* )self
);
46 static int Database_init(DatabaseObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
47 const char* path
= NULL
;
51 if (!PyArg_ParseTuple(args
, "s", &path
))
55 self
->path
= strdup(path
);
59 // Open the file for reading
60 f
= fopen(self
->path
, "r");
65 int r
= loc_database_new(loc_ctx
, &self
->db
, f
);
76 PyErr_SetFromErrno(PyExc_OSError
);
80 static PyObject
* Database_repr(DatabaseObject
* self
) {
81 return PyUnicode_FromFormat("<Database %s>", self
->path
);
84 static PyObject
* Database_verify(DatabaseObject
* self
, PyObject
* args
) {
85 PyObject
* public_key
= NULL
;
89 if (!PyArg_ParseTuple(args
, "O", &public_key
))
93 int fd
= PyObject_AsFileDescriptor(public_key
);
97 // Re-open file descriptor
100 PyErr_SetFromErrno(PyExc_IOError
);
104 int r
= loc_database_verify(self
->db
, f
);
112 static PyObject
* Database_get_description(DatabaseObject
* self
) {
113 const char* description
= loc_database_get_description(self
->db
);
117 return PyUnicode_FromString(description
);
120 static PyObject
* Database_get_vendor(DatabaseObject
* self
) {
121 const char* vendor
= loc_database_get_vendor(self
->db
);
125 return PyUnicode_FromString(vendor
);
128 static PyObject
* Database_get_license(DatabaseObject
* self
) {
129 const char* license
= loc_database_get_license(self
->db
);
133 return PyUnicode_FromString(license
);
136 static PyObject
* Database_get_created_at(DatabaseObject
* self
) {
137 time_t created_at
= loc_database_created_at(self
->db
);
139 return PyLong_FromLong(created_at
);
142 static PyObject
* Database_get_as(DatabaseObject
* self
, PyObject
* args
) {
143 struct loc_as
* as
= NULL
;
146 if (!PyArg_ParseTuple(args
, "i", &number
))
149 // Try to retrieve the AS
150 int r
= loc_database_get_as(self
->db
, &as
, number
);
154 PyObject
* obj
= new_as(&ASType
, as
);
168 static PyObject
* Database_get_country(DatabaseObject
* self
, PyObject
* args
) {
169 struct loc_country
* country
= NULL
;
170 const char* country_code
= NULL
;
172 if (!PyArg_ParseTuple(args
, "s", &country_code
))
176 int r
= loc_database_get_country(self
->db
, &country
, country_code
);
180 PyErr_SetString(PyExc_ValueError
, "Invalid country code");
184 PyErr_SetFromErrno(PyExc_OSError
);
195 PyObject
* obj
= new_country(&CountryType
, country
);
196 loc_country_unref(country
);
201 static PyObject
* Database_lookup(DatabaseObject
* self
, PyObject
* args
) {
202 struct loc_network
* network
= NULL
;
203 const char* address
= NULL
;
206 if (!PyArg_ParseTuple(args
, "s", &address
))
209 // Try to retrieve a matching network
210 r
= loc_database_lookup_from_string(self
->db
, address
, &network
);
215 PyErr_Format(PyExc_ValueError
, "Invalid IP address: %s", address
);
219 PyErr_SetFromErrno(PyExc_OSError
);
231 PyObject
* obj
= new_network(&NetworkType
, network
);
232 loc_network_unref(network
);
237 static PyObject
* new_database_enumerator(PyTypeObject
* type
, struct loc_database_enumerator
* enumerator
) {
238 DatabaseEnumeratorObject
* self
= (DatabaseEnumeratorObject
*)type
->tp_alloc(type
, 0);
240 self
->enumerator
= loc_database_enumerator_ref(enumerator
);
243 return (PyObject
*)self
;
246 static PyObject
* Database_iterate_all(DatabaseObject
* self
,
247 enum loc_database_enumerator_mode what
, int family
, int flags
) {
248 struct loc_database_enumerator
* enumerator
;
250 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, what
, flags
);
252 PyErr_SetFromErrno(PyExc_SystemError
);
258 loc_database_enumerator_set_family(enumerator
, family
);
260 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
261 loc_database_enumerator_unref(enumerator
);
266 static PyObject
* Database_ases(DatabaseObject
* self
) {
267 return Database_iterate_all(self
, LOC_DB_ENUMERATE_ASES
, AF_UNSPEC
, 0);
270 static PyObject
* Database_search_as(DatabaseObject
* self
, PyObject
* args
) {
271 const char* string
= NULL
;
273 if (!PyArg_ParseTuple(args
, "s", &string
))
276 struct loc_database_enumerator
* enumerator
;
278 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, LOC_DB_ENUMERATE_ASES
, 0);
280 PyErr_SetFromErrno(PyExc_SystemError
);
284 // Search string we are searching for
285 loc_database_enumerator_set_string(enumerator
, string
);
287 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
288 loc_database_enumerator_unref(enumerator
);
293 static PyObject
* Database_networks(DatabaseObject
* self
) {
294 return Database_iterate_all(self
, LOC_DB_ENUMERATE_NETWORKS
, AF_UNSPEC
, 0);
297 static PyObject
* Database_networks_flattened(DatabaseObject
*self
) {
298 return Database_iterate_all(self
, LOC_DB_ENUMERATE_NETWORKS
, AF_UNSPEC
,
299 LOC_DB_ENUMERATOR_FLAGS_FLATTEN
);
302 static PyObject
* Database_search_networks(DatabaseObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
303 const char* kwlist
[] = { "country_codes", "asns", "flags", "family", "flatten", NULL
};
304 PyObject
* country_codes
= NULL
;
305 PyObject
* asn_list
= NULL
;
310 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|O!O!iip", (char**)kwlist
,
311 &PyList_Type
, &country_codes
, &PyList_Type
, &asn_list
, &flags
, &family
, &flatten
))
314 struct loc_database_enumerator
* enumerator
;
315 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, LOC_DB_ENUMERATE_NETWORKS
,
316 (flatten
) ? LOC_DB_ENUMERATOR_FLAGS_FLATTEN
: 0);
318 PyErr_SetFromErrno(PyExc_SystemError
);
322 // Set country code we are searching for
324 struct loc_country_list
* countries
;
325 r
= loc_country_list_new(loc_ctx
, &countries
);
327 PyErr_SetString(PyExc_SystemError
, "Could not create country list");
331 for (int i
= 0; i
< PyList_Size(country_codes
); i
++) {
332 PyObject
* item
= PyList_GetItem(country_codes
, i
);
334 if (!PyUnicode_Check(item
)) {
335 PyErr_SetString(PyExc_TypeError
, "Country codes must be strings");
336 loc_country_list_unref(countries
);
340 const char* country_code
= PyUnicode_AsUTF8(item
);
342 struct loc_country
* country
;
343 r
= loc_country_new(loc_ctx
, &country
, country_code
);
346 PyErr_Format(PyExc_ValueError
, "Invalid country code: %s", country_code
);
348 PyErr_SetString(PyExc_SystemError
, "Could not create country");
351 loc_country_list_unref(countries
);
355 // Append it to the list
356 r
= loc_country_list_append(countries
, country
);
358 PyErr_SetString(PyExc_SystemError
, "Could not append country to the list");
360 loc_country_list_unref(countries
);
361 loc_country_unref(country
);
365 loc_country_unref(country
);
368 r
= loc_database_enumerator_set_countries(enumerator
, countries
);
370 PyErr_SetFromErrno(PyExc_SystemError
);
372 loc_country_list_unref(countries
);
376 loc_country_list_unref(countries
);
379 // Set the ASN we are searching for
381 struct loc_as_list
* asns
;
382 r
= loc_as_list_new(loc_ctx
, &asns
);
384 PyErr_SetFromErrno(PyExc_OSError
);
388 for (int i
= 0; i
< PyList_Size(asn_list
); i
++) {
389 PyObject
* item
= PyList_GetItem(asn_list
, i
);
391 if (!PyLong_Check(item
)) {
392 PyErr_SetString(PyExc_TypeError
, "ASNs must be numbers");
394 loc_as_list_unref(asns
);
398 unsigned long number
= PyLong_AsLong(item
);
401 r
= loc_as_new(loc_ctx
, &as
, number
);
403 PyErr_SetFromErrno(PyExc_OSError
);
405 loc_as_list_unref(asns
);
410 r
= loc_as_list_append(asns
, as
);
412 PyErr_SetFromErrno(PyExc_OSError
);
414 loc_as_list_unref(asns
);
422 r
= loc_database_enumerator_set_asns(enumerator
, asns
);
424 PyErr_SetFromErrno(PyExc_OSError
);
426 loc_as_list_unref(asns
);
430 loc_as_list_unref(asns
);
433 // Set the flags we are searching for
435 r
= loc_database_enumerator_set_flag(enumerator
, flags
);
438 PyErr_SetFromErrno(PyExc_OSError
);
443 // Set the family we are searching for
445 r
= loc_database_enumerator_set_family(enumerator
, family
);
448 PyErr_SetFromErrno(PyExc_OSError
);
453 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
454 loc_database_enumerator_unref(enumerator
);
459 static PyObject
* Database_countries(DatabaseObject
* self
) {
460 return Database_iterate_all(self
, LOC_DB_ENUMERATE_COUNTRIES
, AF_UNSPEC
, 0);
463 static PyObject
* Database_list_bogons(DatabaseObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
464 const char* kwlist
[] = { "family", NULL
};
465 int family
= AF_UNSPEC
;
468 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|i", (char**)kwlist
, &family
))
471 return Database_iterate_all(self
, LOC_DB_ENUMERATE_BOGONS
, family
, 0);
474 static struct PyMethodDef Database_methods
[] = {
477 (PyCFunction
)Database_get_as
,
483 (PyCFunction
)Database_get_country
,
489 (PyCFunction
)Database_list_bogons
,
490 METH_VARARGS
|METH_KEYWORDS
,
495 (PyCFunction
)Database_lookup
,
501 (PyCFunction
)Database_search_as
,
507 (PyCFunction
)Database_search_networks
,
508 METH_VARARGS
|METH_KEYWORDS
,
513 (PyCFunction
)Database_verify
,
520 static struct PyGetSetDef Database_getsetters
[] = {
523 (getter
)Database_ases
,
530 (getter
)Database_countries
,
537 (getter
)Database_get_created_at
,
544 (getter
)Database_get_description
,
551 (getter
)Database_get_license
,
558 (getter
)Database_networks
,
564 "networks_flattened",
565 (getter
)Database_networks_flattened
,
572 (getter
)Database_get_vendor
,
580 PyTypeObject DatabaseType
= {
581 PyVarObject_HEAD_INIT(NULL
, 0)
582 .tp_name
= "location.Database",
583 .tp_basicsize
= sizeof(DatabaseObject
),
584 .tp_flags
= Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
,
585 .tp_new
= Database_new
,
586 .tp_dealloc
= (destructor
)Database_dealloc
,
587 .tp_init
= (initproc
)Database_init
,
588 .tp_doc
= "Database object",
589 .tp_methods
= Database_methods
,
590 .tp_getset
= Database_getsetters
,
591 .tp_repr
= (reprfunc
)Database_repr
,
594 static PyObject
* DatabaseEnumerator_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
595 DatabaseEnumeratorObject
* self
= (DatabaseEnumeratorObject
*)type
->tp_alloc(type
, 0);
597 return (PyObject
*)self
;
600 static void DatabaseEnumerator_dealloc(DatabaseEnumeratorObject
* self
) {
601 loc_database_enumerator_unref(self
->enumerator
);
603 Py_TYPE(self
)->tp_free((PyObject
* )self
);
606 static PyObject
* DatabaseEnumerator_next(DatabaseEnumeratorObject
* self
) {
607 struct loc_network
* network
= NULL
;
609 // Enumerate all networks
610 int r
= loc_database_enumerator_next_network(self
->enumerator
, &network
);
612 PyErr_SetFromErrno(PyExc_ValueError
);
616 // A network was found
618 PyObject
* obj
= new_network(&NetworkType
, network
);
619 loc_network_unref(network
);
624 // Enumerate all ASes
625 struct loc_as
* as
= NULL
;
627 r
= loc_database_enumerator_next_as(self
->enumerator
, &as
);
629 PyErr_SetFromErrno(PyExc_ValueError
);
634 PyObject
* obj
= new_as(&ASType
, as
);
640 // Enumerate all countries
641 struct loc_country
* country
= NULL
;
643 r
= loc_database_enumerator_next_country(self
->enumerator
, &country
);
645 PyErr_SetFromErrno(PyExc_ValueError
);
650 PyObject
* obj
= new_country(&CountryType
, country
);
651 loc_country_unref(country
);
656 // Nothing found, that means the end
657 PyErr_SetNone(PyExc_StopIteration
);
661 PyTypeObject DatabaseEnumeratorType
= {
662 PyVarObject_HEAD_INIT(NULL
, 0)
663 .tp_name
= "location.DatabaseEnumerator",
664 .tp_basicsize
= sizeof(DatabaseEnumeratorObject
),
665 .tp_flags
= Py_TPFLAGS_DEFAULT
,
666 .tp_alloc
= PyType_GenericAlloc
,
667 .tp_new
= DatabaseEnumerator_new
,
668 .tp_dealloc
= (destructor
)DatabaseEnumerator_dealloc
,
669 .tp_iter
= PyObject_SelfIter
,
670 .tp_iternext
= (iternextfunc
)DatabaseEnumerator_next
,