]> git.ipfire.org Git - people/ms/libloc.git/blame - src/python/network.c
importer: Drop EDROP as it has been merged into DROP
[people/ms/libloc.git] / src / python / network.c
CommitLineData
39967361
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
19#include <errno.h>
7c78416c 20#include <limits.h>
39967361 21
25f300f7 22#include <libloc/compat.h>
c12a1385
MT
23#include <libloc/libloc.h>
24#include <libloc/network.h>
25#include <libloc/network-list.h>
39967361
MT
26
27#include "locationmodule.h"
28#include "network.h"
29
037c65d3
MT
30static PyObject* PyList_FromNetworkList(struct loc_network_list* networks) {
31 PyObject* list = PyList_New(0);
32 if (!networks)
33 return list;
34
35 while (!loc_network_list_empty(networks)) {
36 struct loc_network* network = loc_network_list_pop(networks);
37
38 PyObject* n = new_network(&NetworkType, network);
39 PyList_Append(list, n);
40
41 loc_network_unref(network);
42 Py_DECREF(n);
43 }
44
45 return list;
46}
47
31edab76
MT
48PyObject* new_network(PyTypeObject* type, struct loc_network* network) {
49 NetworkObject* self = (NetworkObject*)type->tp_alloc(type, 0);
50 if (self) {
51 self->network = loc_network_ref(network);
52 }
53
54 return (PyObject*)self;
55}
56
39967361
MT
57static PyObject* Network_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
58 NetworkObject* self = (NetworkObject*)type->tp_alloc(type, 0);
59
60 return (PyObject*)self;
61}
62
63static void Network_dealloc(NetworkObject* self) {
64 if (self->network)
65 loc_network_unref(self->network);
66
67 Py_TYPE(self)->tp_free((PyObject* )self);
68}
69
70static int Network_init(NetworkObject* self, PyObject* args, PyObject* kwargs) {
71 const char* network = NULL;
72
73 if (!PyArg_ParseTuple(args, "s", &network))
74 return -1;
75
76 // Load the Network
77 int r = loc_network_new_from_string(loc_ctx, &self->network, network);
78 if (r) {
79 PyErr_Format(PyExc_ValueError, "Invalid network: %s", network);
80 return -1;
81 }
82
83 return 0;
84}
85
86static PyObject* Network_repr(NetworkObject* self) {
0a0a289a 87 const char* network = loc_network_str(self->network);
39967361 88
0a0a289a 89 return PyUnicode_FromFormat("<location.Network %s>", network);
39967361
MT
90}
91
5118a4b8 92static PyObject* Network_str(NetworkObject* self) {
0a0a289a 93 const char* network = loc_network_str(self->network);
5118a4b8 94
0a0a289a 95 return PyUnicode_FromString(network);
5118a4b8
MT
96}
97
39967361
MT
98static PyObject* Network_get_country_code(NetworkObject* self) {
99 const char* country_code = loc_network_get_country_code(self->network);
100
101 return PyUnicode_FromString(country_code);
102}
103
104static int Network_set_country_code(NetworkObject* self, PyObject* value) {
105 const char* country_code = PyUnicode_AsUTF8(value);
106
107 int r = loc_network_set_country_code(self->network, country_code);
108 if (r) {
109 if (r == -EINVAL)
35f5acdc
MT
110 PyErr_Format(PyExc_ValueError,
111 "Invalid country code: %s", country_code);
39967361
MT
112
113 return -1;
114 }
115
116 return 0;
117}
118
71ff3e69
MT
119static PyObject* Network_get_asn(NetworkObject* self) {
120 uint32_t asn = loc_network_get_asn(self->network);
121
122 if (asn)
123 return PyLong_FromLong(asn);
124
125 Py_RETURN_NONE;
126}
127
128static int Network_set_asn(NetworkObject* self, PyObject* value) {
129 long int asn = PyLong_AsLong(value);
130
131 // Check if the ASN is within the valid range
7c78416c 132 if (asn <= 0) {
71ff3e69
MT
133 PyErr_Format(PyExc_ValueError, "Invalid ASN %ld", asn);
134 return -1;
135 }
136
7c78416c
MT
137#if (__WORDSIZE > 32)
138 // Check whether the input was longer than 32 bit
139 if (asn > UINT32_MAX) {
140 PyErr_Format(PyExc_ValueError, "Invalid ASN %ld", asn);
141 return -1;
142 }
143#endif
144
71ff3e69
MT
145 int r = loc_network_set_asn(self->network, asn);
146 if (r)
147 return -1;
148
149 return 0;
150}
151
24ca7992
MT
152static PyObject* Network_has_flag(NetworkObject* self, PyObject* args) {
153 enum loc_network_flags flag = 0;
154
155 if (!PyArg_ParseTuple(args, "i", &flag))
156 return NULL;
157
158 if (loc_network_has_flag(self->network, flag))
159 Py_RETURN_TRUE;
160
161 Py_RETURN_FALSE;
162}
163
164static PyObject* Network_set_flag(NetworkObject* self, PyObject* args) {
165 enum loc_network_flags flag = 0;
166
167 if (!PyArg_ParseTuple(args, "i", &flag))
168 return NULL;
169
170 int r = loc_network_set_flag(self->network, flag);
171
172 if (r) {
173 // What exception to throw here?
174 return NULL;
175 }
176
177 Py_RETURN_NONE;
178}
179
037c65d3
MT
180static PyObject* Network_exclude(NetworkObject* self, PyObject* args) {
181 NetworkObject* other = NULL;
182
183 if (!PyArg_ParseTuple(args, "O!", &NetworkType, &other))
184 return NULL;
185
186 struct loc_network_list* list = loc_network_exclude(self->network, other->network);
187
188 // Convert to Python objects
189 PyObject* obj = PyList_FromNetworkList(list);
190 loc_network_list_unref(list);
191
192 return obj;
193}
194
43554dc4
MT
195static PyObject* Network_is_subnet_of(NetworkObject* self, PyObject* args) {
196 NetworkObject* other = NULL;
197
198 if (!PyArg_ParseTuple(args, "O!", &NetworkType, &other))
199 return NULL;
200
d6a5092f 201 if (loc_network_is_subnet(other->network, self->network))
43554dc4
MT
202 Py_RETURN_TRUE;
203
204 Py_RETURN_FALSE;
205}
206
2b9338ea
MT
207static PyObject* Network_get_family(NetworkObject* self) {
208 int family = loc_network_address_family(self->network);
209
210 return PyLong_FromLong(family);
211}
212
213static PyObject* Network_get_first_address(NetworkObject* self) {
0a0a289a 214 const char* address = loc_network_format_first_address(self->network);
2b9338ea 215
0a0a289a 216 return PyUnicode_FromString(address);
2b9338ea
MT
217}
218
a1a00053
MT
219static PyObject* PyBytes_FromAddress(const struct in6_addr* address6) {
220 struct in_addr address4;
221
222 // Convert IPv4 addresses to struct in_addr
223 if (IN6_IS_ADDR_V4MAPPED(address6)) {
224 address4.s_addr = address6->s6_addr32[3];
225
226 return PyBytes_FromStringAndSize((const char*)&address4, sizeof(address4));
227 }
228
229 // Return IPv6 addresses as they are
230 return PyBytes_FromStringAndSize((const char*)address6, sizeof(*address6));
231}
232
233static PyObject* Network_get__first_address(NetworkObject* self) {
234 const struct in6_addr* address = loc_network_get_first_address(self->network);
235
236 return PyBytes_FromAddress(address);
237}
238
2b9338ea 239static PyObject* Network_get_last_address(NetworkObject* self) {
0a0a289a 240 const char* address = loc_network_format_last_address(self->network);
2b9338ea 241
0a0a289a 242 return PyUnicode_FromString(address);
2b9338ea
MT
243}
244
a1a00053
MT
245static PyObject* Network_get__last_address(NetworkObject* self) {
246 const struct in6_addr* address = loc_network_get_last_address(self->network);
247
248 return PyBytes_FromAddress(address);
249}
250
ff172164
MT
251static PyObject* Network_richcompare(NetworkObject* self, PyObject* other, int op) {
252 int r;
253
254 // Check for type
255 if (!PyObject_IsInstance(other, (PyObject *)&NetworkType))
256 Py_RETURN_NOTIMPLEMENTED;
257
258 NetworkObject* o = (NetworkObject*)other;
259
260 r = loc_network_cmp(self->network, o->network);
261
262 switch (op) {
263 case Py_EQ:
264 if (r == 0)
265 Py_RETURN_TRUE;
266
267 Py_RETURN_FALSE;
268
269 case Py_LT:
270 if (r < 0)
271 Py_RETURN_TRUE;
272
273 Py_RETURN_FALSE;
274
275 default:
276 break;
277 }
278
279 Py_RETURN_NOTIMPLEMENTED;
280}
281
8da88dda
MT
282static PyObject* Network_reverse_pointer(NetworkObject* self, PyObject* args, PyObject* kwargs) {
283 char* kwlist[] = { "suffix", NULL };
284 const char* suffix = NULL;
285 char* rp = NULL;
286
287 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|z", kwlist, &suffix))
288 return NULL;
289
290 rp = loc_network_reverse_pointer(self->network, suffix);
291 if (!rp) {
292 switch (errno) {
293 case ENOTSUP:
294 Py_RETURN_NONE;
295
296 default:
297 PyErr_SetFromErrno(PyExc_OSError);
298 return NULL;
299 }
300 }
301
302 PyObject* ret = PyUnicode_FromString(rp);
303 free(rp);
304
305 return ret;
306}
307
24ca7992 308static struct PyMethodDef Network_methods[] = {
037c65d3
MT
309 {
310 "exclude",
311 (PyCFunction)Network_exclude,
312 METH_VARARGS,
313 NULL,
314 },
24ca7992
MT
315 {
316 "has_flag",
317 (PyCFunction)Network_has_flag,
318 METH_VARARGS,
319 NULL,
320 },
43554dc4
MT
321 {
322 "is_subnet_of",
323 (PyCFunction)Network_is_subnet_of,
324 METH_VARARGS,
325 NULL,
326 },
8da88dda
MT
327 {
328 "reverse_pointer",
329 (PyCFunction)Network_reverse_pointer,
330 METH_VARARGS|METH_KEYWORDS,
331 NULL,
332 },
24ca7992
MT
333 {
334 "set_flag",
335 (PyCFunction)Network_set_flag,
336 METH_VARARGS,
337 NULL,
338 },
339 { NULL },
340};
341
39967361 342static struct PyGetSetDef Network_getsetters[] = {
71ff3e69
MT
343 {
344 "asn",
345 (getter)Network_get_asn,
346 (setter)Network_set_asn,
347 NULL,
348 NULL,
349 },
39967361
MT
350 {
351 "country_code",
352 (getter)Network_get_country_code,
353 (setter)Network_set_country_code,
354 NULL,
355 NULL,
356 },
2b9338ea
MT
357 {
358 "family",
359 (getter)Network_get_family,
360 NULL,
361 NULL,
362 NULL,
363 },
364 {
365 "first_address",
366 (getter)Network_get_first_address,
367 NULL,
368 NULL,
369 NULL,
370 },
a1a00053
MT
371 {
372 "_first_address",
373 (getter)Network_get__first_address,
374 NULL,
375 NULL,
376 NULL,
377 },
2b9338ea
MT
378 {
379 "last_address",
380 (getter)Network_get_last_address,
381 NULL,
382 NULL,
383 NULL,
384 },
a1a00053
MT
385 {
386 "_last_address",
387 (getter)Network_get__last_address,
388 NULL,
389 NULL,
390 NULL,
391 },
39967361
MT
392 { NULL },
393};
394
395PyTypeObject NetworkType = {
396 PyVarObject_HEAD_INIT(NULL, 0)
d42e1dcd
MT
397 .tp_name = "location.Network",
398 .tp_basicsize = sizeof(NetworkObject),
399 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
400 .tp_new = Network_new,
401 .tp_dealloc = (destructor)Network_dealloc,
402 .tp_init = (initproc)Network_init,
403 .tp_doc = "Network object",
24ca7992 404 .tp_methods = Network_methods,
d42e1dcd
MT
405 .tp_getset = Network_getsetters,
406 .tp_repr = (reprfunc)Network_repr,
407 .tp_str = (reprfunc)Network_str,
ff172164 408 .tp_richcompare = (richcmpfunc)Network_richcompare,
39967361 409};