]> git.ipfire.org Git - people/ms/libloc.git/blame - src/python/database.c
database: Add scaffolding for checking signatures
[people/ms/libloc.git] / src / python / database.c
CommitLineData
9cdf6c53
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
5
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.
10
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.
15*/
16
17#include <Python.h>
18
9fc7f001
MT
19#include <loc/libloc.h>
20#include <loc/database.h>
21
1da9cd39 22#include "locationmodule.h"
86ca7ef7 23#include "as.h"
7c922e9c 24#include "country.h"
9cdf6c53 25#include "database.h"
31edab76 26#include "network.h"
9cdf6c53
MT
27
28static PyObject* Database_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
9cdf6c53 29 DatabaseObject* self = (DatabaseObject*)type->tp_alloc(type, 0);
9cdf6c53
MT
30
31 return (PyObject*)self;
32}
33
34static void Database_dealloc(DatabaseObject* self) {
35 if (self->db)
36 loc_database_unref(self->db);
37
6fd96715
MT
38 if (self->path)
39 free(self->path);
40
9cdf6c53
MT
41 Py_TYPE(self)->tp_free((PyObject* )self);
42}
43
44static int Database_init(DatabaseObject* self, PyObject* args, PyObject* kwargs) {
45 const char* path = NULL;
46
47 if (!PyArg_ParseTuple(args, "s", &path))
48 return -1;
49
6fd96715
MT
50 self->path = strdup(path);
51
9cdf6c53 52 // Open the file for reading
6fd96715 53 FILE* f = fopen(self->path, "r");
774eea26
MT
54 if (!f) {
55 PyErr_SetFromErrno(PyExc_IOError);
9cdf6c53 56 return -1;
774eea26 57 }
9cdf6c53
MT
58
59 // Load the database
38e07ee0 60 int r = loc_database_new(loc_ctx, &self->db, f);
9cdf6c53
MT
61 fclose(f);
62
63 // Return on any errors
64 if (r)
65 return -1;
66
67 return 0;
68}
69
6fd96715
MT
70static PyObject* Database_repr(DatabaseObject* self) {
71 return PyUnicode_FromFormat("<Database %s>", self->path);
72}
73
b1720435
MT
74static PyObject* Database_verify(DatabaseObject* self) {
75 int r = loc_database_verify(self->db);
76
77 if (r == 0)
78 Py_RETURN_TRUE;
79
80 Py_RETURN_FALSE;
81}
82
d99b0256
MT
83static PyObject* Database_get_description(DatabaseObject* self) {
84 const char* description = loc_database_get_description(self->db);
85
86 return PyUnicode_FromString(description);
87}
88
89static PyObject* Database_get_vendor(DatabaseObject* self) {
90 const char* vendor = loc_database_get_vendor(self->db);
91
92 return PyUnicode_FromString(vendor);
93}
94
4bf49d00
MT
95static PyObject* Database_get_license(DatabaseObject* self) {
96 const char* license = loc_database_get_license(self->db);
97
98 return PyUnicode_FromString(license);
99}
100
53524b2d
MT
101static PyObject* Database_get_created_at(DatabaseObject* self) {
102 time_t created_at = loc_database_created_at(self->db);
103
104 return PyLong_FromLong(created_at);
105}
106
86ca7ef7
MT
107static PyObject* Database_get_as(DatabaseObject* self, PyObject* args) {
108 struct loc_as* as = NULL;
109 uint32_t number = 0;
110
111 if (!PyArg_ParseTuple(args, "i", &number))
112 return NULL;
113
114 // Try to retrieve the AS
115 int r = loc_database_get_as(self->db, &as, number);
86ca7ef7 116
4a0a0f7e
MT
117 // We got an AS
118 if (r == 0) {
86ca7ef7
MT
119 PyObject* obj = new_as(&ASType, as);
120 loc_as_unref(as);
121
122 return obj;
86ca7ef7
MT
123
124 // Nothing found
4a0a0f7e
MT
125 } else if (r == 1) {
126 Py_RETURN_NONE;
127 }
128
129 // Unexpected error
130 return NULL;
86ca7ef7
MT
131}
132
7c922e9c
MT
133static PyObject* Database_get_country(DatabaseObject* self, PyObject* args) {
134 const char* country_code = NULL;
135
136 if (!PyArg_ParseTuple(args, "s", &country_code))
137 return NULL;
138
139 struct loc_country* country;
140 int r = loc_database_get_country(self->db, &country, country_code);
141 if (r) {
142 Py_RETURN_NONE;
143 }
144
145 PyObject* obj = new_country(&CountryType, country);
146 loc_country_unref(country);
147
148 return obj;
149}
150
31edab76
MT
151static PyObject* Database_lookup(DatabaseObject* self, PyObject* args) {
152 struct loc_network* network = NULL;
153 const char* address = NULL;
154
155 if (!PyArg_ParseTuple(args, "s", &address))
156 return NULL;
157
158 // Try to retrieve a matching network
159 int r = loc_database_lookup_from_string(self->db, address, &network);
160
161 // We got a network
162 if (r == 0) {
163 PyObject* obj = new_network(&NetworkType, network);
164 loc_network_unref(network);
165
166 return obj;
167
168 // Nothing found
169 } else if (r == 1) {
170 Py_RETURN_NONE;
927e82f2
MT
171
172 // Invalid input
173 } else if (r == -EINVAL) {
174 PyErr_Format(PyExc_ValueError, "Invalid IP address: %s", address);
175 return NULL;
31edab76
MT
176 }
177
178 // Unexpected error
179 return NULL;
180}
181
afb426df
MT
182static PyObject* new_database_enumerator(PyTypeObject* type, struct loc_database_enumerator* enumerator) {
183 DatabaseEnumeratorObject* self = (DatabaseEnumeratorObject*)type->tp_alloc(type, 0);
184 if (self) {
185 self->enumerator = loc_database_enumerator_ref(enumerator);
186 }
187
188 return (PyObject*)self;
189}
190
191static PyObject* Database_search_as(DatabaseObject* self, PyObject* args) {
192 const char* string = NULL;
193
194 if (!PyArg_ParseTuple(args, "s", &string))
195 return NULL;
196
197 struct loc_database_enumerator* enumerator;
198
ccc7ab4e 199 int r = loc_database_enumerator_new(&enumerator, self->db, LOC_DB_ENUMERATE_ASES);
afb426df
MT
200 if (r) {
201 PyErr_SetFromErrno(PyExc_SystemError);
202 return NULL;
203 }
204
205 // Search string we are searching for
206 loc_database_enumerator_set_string(enumerator, string);
207
208 PyObject* obj = new_database_enumerator(&DatabaseEnumeratorType, enumerator);
209 loc_database_enumerator_unref(enumerator);
210
211 return obj;
212}
213
ccc7ab4e 214static PyObject* Database_search_networks(DatabaseObject* self, PyObject* args, PyObject* kwargs) {
bbdb2e0a 215 char* kwlist[] = { "country_code", "asn", "flags", NULL };
ccc7ab4e
MT
216 const char* country_code = NULL;
217 unsigned int asn = 0;
bbdb2e0a 218 int flags = 0;
ccc7ab4e 219
bbdb2e0a 220 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sii", kwlist, &country_code, &asn, &flags))
ccc7ab4e
MT
221 return NULL;
222
223 struct loc_database_enumerator* enumerator;
224 int r = loc_database_enumerator_new(&enumerator, self->db, LOC_DB_ENUMERATE_NETWORKS);
225 if (r) {
226 PyErr_SetFromErrno(PyExc_SystemError);
227 return NULL;
228 }
229
230 // Set country code we are searching for
231 if (country_code) {
232 r = loc_database_enumerator_set_country_code(enumerator, country_code);
233
234 if (r) {
235 PyErr_SetFromErrno(PyExc_SystemError);
236 return NULL;
237 }
238 }
239
240 // Set the ASN we are searching for
241 if (asn) {
242 r = loc_database_enumerator_set_asn(enumerator, asn);
243
244 if (r) {
245 PyErr_SetFromErrno(PyExc_SystemError);
246 return NULL;
247 }
248 }
249
bbdb2e0a
MT
250 // Set the flags we are searching for
251 if (flags) {
252 r = loc_database_enumerator_set_flag(enumerator, flags);
253
254 if (r) {
255 PyErr_SetFromErrno(PyExc_SystemError);
256 return NULL;
257 }
258 }
259
ccc7ab4e
MT
260 PyObject* obj = new_database_enumerator(&DatabaseEnumeratorType, enumerator);
261 loc_database_enumerator_unref(enumerator);
262
263 return obj;
264}
265
9cdf6c53 266static struct PyMethodDef Database_methods[] = {
86ca7ef7
MT
267 {
268 "get_as",
269 (PyCFunction)Database_get_as,
270 METH_VARARGS,
271 NULL,
272 },
7c922e9c
MT
273 {
274 "get_country",
275 (PyCFunction)Database_get_country,
276 METH_VARARGS,
277 NULL,
278 },
31edab76
MT
279 {
280 "lookup",
281 (PyCFunction)Database_lookup,
282 METH_VARARGS,
283 NULL,
284 },
afb426df
MT
285 {
286 "search_as",
287 (PyCFunction)Database_search_as,
288 METH_VARARGS,
289 NULL,
290 },
ccc7ab4e
MT
291 {
292 "search_networks",
293 (PyCFunction)Database_search_networks,
294 METH_VARARGS|METH_KEYWORDS,
295 NULL,
296 },
b1720435
MT
297 {
298 "verify",
299 (PyCFunction)Database_verify,
300 METH_NOARGS,
301 NULL,
302 },
9cdf6c53
MT
303 { NULL },
304};
305
d99b0256 306static struct PyGetSetDef Database_getsetters[] = {
53524b2d
MT
307 {
308 "created_at",
309 (getter)Database_get_created_at,
310 NULL,
311 NULL,
312 NULL,
313 },
d99b0256
MT
314 {
315 "description",
316 (getter)Database_get_description,
317 NULL,
318 NULL,
319 NULL,
320 },
4bf49d00
MT
321 {
322 "license",
323 (getter)Database_get_license,
324 NULL,
325 NULL,
326 NULL,
327 },
d99b0256
MT
328 {
329 "vendor",
330 (getter)Database_get_vendor,
331 NULL,
332 NULL,
53524b2d 333 NULL,
d99b0256
MT
334 },
335 { NULL },
336};
337
9cdf6c53
MT
338PyTypeObject DatabaseType = {
339 PyVarObject_HEAD_INIT(NULL, 0)
d42e1dcd
MT
340 .tp_name = "location.Database",
341 .tp_basicsize = sizeof(DatabaseObject),
342 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
343 .tp_new = Database_new,
344 .tp_dealloc = (destructor)Database_dealloc,
345 .tp_init = (initproc)Database_init,
346 .tp_doc = "Database object",
347 .tp_methods = Database_methods,
348 .tp_getset = Database_getsetters,
349 .tp_repr = (reprfunc)Database_repr,
9cdf6c53 350};
afb426df
MT
351
352static PyObject* DatabaseEnumerator_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
353 DatabaseEnumeratorObject* self = (DatabaseEnumeratorObject*)type->tp_alloc(type, 0);
354
355 return (PyObject*)self;
356}
357
358static void DatabaseEnumerator_dealloc(DatabaseEnumeratorObject* self) {
359 loc_database_enumerator_unref(self->enumerator);
360
361 Py_TYPE(self)->tp_free((PyObject* )self);
362}
363
364static PyObject* DatabaseEnumerator_next(DatabaseEnumeratorObject* self) {
15f79e2d
MT
365 struct loc_network* network = NULL;
366
ccc7ab4e 367 // Enumerate all networks
15f79e2d
MT
368 int r = loc_database_enumerator_next_network(self->enumerator, &network);
369 if (r) {
20bb6d0c 370 PyErr_SetFromErrno(PyExc_ValueError);
15f79e2d
MT
371 return NULL;
372 }
373
374 // A network was found
ccc7ab4e
MT
375 if (network) {
376 PyObject* obj = new_network(&NetworkType, network);
377 loc_network_unref(network);
378
379 return obj;
380 }
381
382 // Enumerate all ASes
15f79e2d
MT
383 struct loc_as* as = NULL;
384
385 r = loc_database_enumerator_next_as(self->enumerator, &as);
386 if (r) {
20bb6d0c 387 PyErr_SetFromErrno(PyExc_ValueError);
15f79e2d
MT
388 return NULL;
389 }
390
afb426df
MT
391 if (as) {
392 PyObject* obj = new_as(&ASType, as);
393 loc_as_unref(as);
394
395 return obj;
396 }
397
398 // Nothing found, that means the end
399 PyErr_SetNone(PyExc_StopIteration);
400 return NULL;
401}
402
403PyTypeObject DatabaseEnumeratorType = {
404 PyVarObject_HEAD_INIT(NULL, 0)
d42e1dcd
MT
405 .tp_name = "location.DatabaseEnumerator",
406 .tp_basicsize = sizeof(DatabaseEnumeratorObject),
407 .tp_flags = Py_TPFLAGS_DEFAULT,
408 .tp_alloc = PyType_GenericAlloc,
409 .tp_new = DatabaseEnumerator_new,
410 .tp_dealloc = (destructor)DatabaseEnumerator_dealloc,
411 .tp_iter = PyObject_SelfIter,
412 .tp_iternext = (iternextfunc)DatabaseEnumerator_next,
afb426df 413};