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>
21 #include <loc/as-list.h>
22 #include <loc/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
;
49 if (!PyArg_ParseTuple(args
, "s", &path
))
52 self
->path
= strdup(path
);
54 // Open the file for reading
55 FILE* f
= fopen(self
->path
, "r");
57 PyErr_SetFromErrno(PyExc_IOError
);
62 int r
= loc_database_new(loc_ctx
, &self
->db
, f
);
65 // Return on any errors
72 static PyObject
* Database_repr(DatabaseObject
* self
) {
73 return PyUnicode_FromFormat("<Database %s>", self
->path
);
76 static PyObject
* Database_verify(DatabaseObject
* self
, PyObject
* args
) {
77 PyObject
* public_key
= NULL
;
81 if (!PyArg_ParseTuple(args
, "O", &public_key
))
85 int fd
= PyObject_AsFileDescriptor(public_key
);
89 // Re-open file descriptor
92 PyErr_SetFromErrno(PyExc_IOError
);
96 int r
= loc_database_verify(self
->db
, f
);
104 static PyObject
* Database_get_description(DatabaseObject
* self
) {
105 const char* description
= loc_database_get_description(self
->db
);
107 return PyUnicode_FromString(description
);
110 static PyObject
* Database_get_vendor(DatabaseObject
* self
) {
111 const char* vendor
= loc_database_get_vendor(self
->db
);
113 return PyUnicode_FromString(vendor
);
116 static PyObject
* Database_get_license(DatabaseObject
* self
) {
117 const char* license
= loc_database_get_license(self
->db
);
119 return PyUnicode_FromString(license
);
122 static PyObject
* Database_get_created_at(DatabaseObject
* self
) {
123 time_t created_at
= loc_database_created_at(self
->db
);
125 return PyLong_FromLong(created_at
);
128 static PyObject
* Database_get_as(DatabaseObject
* self
, PyObject
* args
) {
129 struct loc_as
* as
= NULL
;
132 if (!PyArg_ParseTuple(args
, "i", &number
))
135 // Try to retrieve the AS
136 int r
= loc_database_get_as(self
->db
, &as
, number
);
140 PyObject
* obj
= new_as(&ASType
, as
);
154 static PyObject
* Database_get_country(DatabaseObject
* self
, PyObject
* args
) {
155 const char* country_code
= NULL
;
157 if (!PyArg_ParseTuple(args
, "s", &country_code
))
160 struct loc_country
* country
;
161 int r
= loc_database_get_country(self
->db
, &country
, country_code
);
166 PyObject
* obj
= new_country(&CountryType
, country
);
167 loc_country_unref(country
);
172 static PyObject
* Database_lookup(DatabaseObject
* self
, PyObject
* args
) {
173 struct loc_network
* network
= NULL
;
174 const char* address
= NULL
;
176 if (!PyArg_ParseTuple(args
, "s", &address
))
179 // Try to retrieve a matching network
180 int r
= loc_database_lookup_from_string(self
->db
, address
, &network
);
184 PyObject
* obj
= new_network(&NetworkType
, network
);
185 loc_network_unref(network
);
194 } else if (r
== -EINVAL
) {
195 PyErr_Format(PyExc_ValueError
, "Invalid IP address: %s", address
);
203 static PyObject
* new_database_enumerator(PyTypeObject
* type
, struct loc_database_enumerator
* enumerator
) {
204 DatabaseEnumeratorObject
* self
= (DatabaseEnumeratorObject
*)type
->tp_alloc(type
, 0);
206 self
->enumerator
= loc_database_enumerator_ref(enumerator
);
209 return (PyObject
*)self
;
212 static PyObject
* Database_iterate_all(DatabaseObject
* self
, enum loc_database_enumerator_mode what
, int flags
) {
213 struct loc_database_enumerator
* enumerator
;
215 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, what
, flags
);
217 PyErr_SetFromErrno(PyExc_SystemError
);
221 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
222 loc_database_enumerator_unref(enumerator
);
227 static PyObject
* Database_ases(DatabaseObject
* self
) {
228 return Database_iterate_all(self
, LOC_DB_ENUMERATE_ASES
, 0);
231 static PyObject
* Database_search_as(DatabaseObject
* self
, PyObject
* args
) {
232 const char* string
= NULL
;
234 if (!PyArg_ParseTuple(args
, "s", &string
))
237 struct loc_database_enumerator
* enumerator
;
239 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, LOC_DB_ENUMERATE_ASES
, 0);
241 PyErr_SetFromErrno(PyExc_SystemError
);
245 // Search string we are searching for
246 loc_database_enumerator_set_string(enumerator
, string
);
248 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
249 loc_database_enumerator_unref(enumerator
);
254 static PyObject
* Database_networks(DatabaseObject
* self
) {
255 return Database_iterate_all(self
, LOC_DB_ENUMERATE_NETWORKS
, 0);
258 static PyObject
* Database_networks_flattened(DatabaseObject
*self
) {
259 return Database_iterate_all(self
, LOC_DB_ENUMERATE_NETWORKS
, LOC_DB_ENUMERATOR_FLAGS_FLATTEN
);
262 static PyObject
* Database_search_networks(DatabaseObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
263 char* kwlist
[] = { "country_codes", "asns", "flags", "family", "flatten", NULL
};
264 PyObject
* country_codes
= NULL
;
265 PyObject
* asn_list
= NULL
;
270 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|O!O!iip", kwlist
,
271 &PyList_Type
, &country_codes
, &PyList_Type
, &asn_list
, &flags
, &family
, &flatten
))
274 struct loc_database_enumerator
* enumerator
;
275 int r
= loc_database_enumerator_new(&enumerator
, self
->db
, LOC_DB_ENUMERATE_NETWORKS
,
276 (flatten
) ? LOC_DB_ENUMERATOR_FLAGS_FLATTEN
: 0);
278 PyErr_SetFromErrno(PyExc_SystemError
);
282 // Set country code we are searching for
284 struct loc_country_list
* countries
;
285 r
= loc_country_list_new(loc_ctx
, &countries
);
287 PyErr_SetString(PyExc_SystemError
, "Could not create country list");
291 for (unsigned int i
= 0; i
< PyList_Size(country_codes
); i
++) {
292 PyObject
* item
= PyList_GetItem(country_codes
, i
);
294 if (!PyUnicode_Check(item
)) {
295 PyErr_SetString(PyExc_TypeError
, "Country codes must be strings");
296 loc_country_list_unref(countries
);
300 const char* country_code
= PyUnicode_AsUTF8(item
);
302 struct loc_country
* country
;
303 r
= loc_country_new(loc_ctx
, &country
, country_code
);
306 PyErr_Format(PyExc_ValueError
, "Invalid country code: %s", country_code
);
308 PyErr_SetString(PyExc_SystemError
, "Could not create country");
311 loc_country_list_unref(countries
);
315 // Append it to the list
316 r
= loc_country_list_append(countries
, country
);
318 PyErr_SetString(PyExc_SystemError
, "Could not append country to the list");
320 loc_country_list_unref(countries
);
321 loc_country_unref(country
);
325 loc_country_unref(country
);
328 loc_database_enumerator_set_countries(enumerator
, countries
);
330 Py_DECREF(country_codes
);
331 loc_country_list_unref(countries
);
334 // Set the ASN we are searching for
336 struct loc_as_list
* asns
;
337 r
= loc_as_list_new(loc_ctx
, &asns
);
339 PyErr_SetString(PyExc_SystemError
, "Could not create AS list");
343 for (unsigned int i
= 0; i
< PyList_Size(asn_list
); i
++) {
344 PyObject
* item
= PyList_GetItem(asn_list
, i
);
346 if (!PyLong_Check(item
)) {
347 PyErr_SetString(PyExc_TypeError
, "ASNs must be numbers");
349 loc_as_list_unref(asns
);
353 unsigned long number
= PyLong_AsLong(item
);
356 r
= loc_as_new(loc_ctx
, &as
, number
);
358 PyErr_SetString(PyExc_SystemError
, "Could not create AS");
360 loc_as_list_unref(asns
);
365 r
= loc_as_list_append(asns
, as
);
367 PyErr_SetString(PyExc_SystemError
, "Could not append AS to the list");
369 loc_as_list_unref(asns
);
377 r
= loc_database_enumerator_set_asns(enumerator
, asns
);
379 PyErr_SetFromErrno(PyExc_SystemError
);
381 loc_as_list_unref(asns
);
385 loc_as_list_unref(asns
);
388 // Set the flags we are searching for
390 r
= loc_database_enumerator_set_flag(enumerator
, flags
);
393 PyErr_SetFromErrno(PyExc_SystemError
);
398 // Set the family we are searching for
400 r
= loc_database_enumerator_set_family(enumerator
, family
);
403 PyErr_SetFromErrno(PyExc_SystemError
);
408 PyObject
* obj
= new_database_enumerator(&DatabaseEnumeratorType
, enumerator
);
409 loc_database_enumerator_unref(enumerator
);
414 static PyObject
* Database_countries(DatabaseObject
* self
) {
415 return Database_iterate_all(self
, LOC_DB_ENUMERATE_COUNTRIES
, 0);
418 static struct PyMethodDef Database_methods
[] = {
421 (PyCFunction
)Database_get_as
,
427 (PyCFunction
)Database_get_country
,
433 (PyCFunction
)Database_lookup
,
439 (PyCFunction
)Database_search_as
,
445 (PyCFunction
)Database_search_networks
,
446 METH_VARARGS
|METH_KEYWORDS
,
451 (PyCFunction
)Database_verify
,
458 static struct PyGetSetDef Database_getsetters
[] = {
461 (getter
)Database_ases
,
468 (getter
)Database_countries
,
475 (getter
)Database_get_created_at
,
482 (getter
)Database_get_description
,
489 (getter
)Database_get_license
,
496 (getter
)Database_networks
,
502 "networks_flattened",
503 (getter
)Database_networks_flattened
,
510 (getter
)Database_get_vendor
,
518 PyTypeObject DatabaseType
= {
519 PyVarObject_HEAD_INIT(NULL
, 0)
520 .tp_name
= "location.Database",
521 .tp_basicsize
= sizeof(DatabaseObject
),
522 .tp_flags
= Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
,
523 .tp_new
= Database_new
,
524 .tp_dealloc
= (destructor
)Database_dealloc
,
525 .tp_init
= (initproc
)Database_init
,
526 .tp_doc
= "Database object",
527 .tp_methods
= Database_methods
,
528 .tp_getset
= Database_getsetters
,
529 .tp_repr
= (reprfunc
)Database_repr
,
532 static PyObject
* DatabaseEnumerator_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
533 DatabaseEnumeratorObject
* self
= (DatabaseEnumeratorObject
*)type
->tp_alloc(type
, 0);
535 return (PyObject
*)self
;
538 static void DatabaseEnumerator_dealloc(DatabaseEnumeratorObject
* self
) {
539 loc_database_enumerator_unref(self
->enumerator
);
541 Py_TYPE(self
)->tp_free((PyObject
* )self
);
544 static PyObject
* DatabaseEnumerator_next(DatabaseEnumeratorObject
* self
) {
545 struct loc_network
* network
= NULL
;
547 // Enumerate all networks
548 int r
= loc_database_enumerator_next_network(self
->enumerator
, &network
);
550 PyErr_SetFromErrno(PyExc_ValueError
);
554 // A network was found
556 PyObject
* obj
= new_network(&NetworkType
, network
);
557 loc_network_unref(network
);
562 // Enumerate all ASes
563 struct loc_as
* as
= NULL
;
565 r
= loc_database_enumerator_next_as(self
->enumerator
, &as
);
567 PyErr_SetFromErrno(PyExc_ValueError
);
572 PyObject
* obj
= new_as(&ASType
, as
);
578 // Enumerate all countries
579 struct loc_country
* country
= NULL
;
581 r
= loc_database_enumerator_next_country(self
->enumerator
, &country
);
583 PyErr_SetFromErrno(PyExc_ValueError
);
588 PyObject
* obj
= new_country(&CountryType
, country
);
589 loc_country_unref(country
);
594 // Nothing found, that means the end
595 PyErr_SetNone(PyExc_StopIteration
);
599 PyTypeObject DatabaseEnumeratorType
= {
600 PyVarObject_HEAD_INIT(NULL
, 0)
601 .tp_name
= "location.DatabaseEnumerator",
602 .tp_basicsize
= sizeof(DatabaseEnumeratorObject
),
603 .tp_flags
= Py_TPFLAGS_DEFAULT
,
604 .tp_alloc
= PyType_GenericAlloc
,
605 .tp_new
= DatabaseEnumerator_new
,
606 .tp_dealloc
= (destructor
)DatabaseEnumerator_dealloc
,
607 .tp_iter
= PyObject_SelfIter
,
608 .tp_iternext
= (iternextfunc
)DatabaseEnumerator_next
,