]> git.ipfire.org Git - people/ms/libloc.git/blob - src/python/network.c
importer: Drop EDROP as it has been merged into DROP
[people/ms/libloc.git] / src / python / network.c
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>
20 #include <limits.h>
21
22 #include <libloc/compat.h>
23 #include <libloc/libloc.h>
24 #include <libloc/network.h>
25 #include <libloc/network-list.h>
26
27 #include "locationmodule.h"
28 #include "network.h"
29
30 static 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
48 PyObject* 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
57 static 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
63 static 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
70 static 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
86 static PyObject* Network_repr(NetworkObject* self) {
87 const char* network = loc_network_str(self->network);
88
89 return PyUnicode_FromFormat("<location.Network %s>", network);
90 }
91
92 static PyObject* Network_str(NetworkObject* self) {
93 const char* network = loc_network_str(self->network);
94
95 return PyUnicode_FromString(network);
96 }
97
98 static 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
104 static 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)
110 PyErr_Format(PyExc_ValueError,
111 "Invalid country code: %s", country_code);
112
113 return -1;
114 }
115
116 return 0;
117 }
118
119 static 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
128 static 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
132 if (asn <= 0) {
133 PyErr_Format(PyExc_ValueError, "Invalid ASN %ld", asn);
134 return -1;
135 }
136
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
145 int r = loc_network_set_asn(self->network, asn);
146 if (r)
147 return -1;
148
149 return 0;
150 }
151
152 static 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
164 static 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
180 static 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
195 static 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
201 if (loc_network_is_subnet(other->network, self->network))
202 Py_RETURN_TRUE;
203
204 Py_RETURN_FALSE;
205 }
206
207 static PyObject* Network_get_family(NetworkObject* self) {
208 int family = loc_network_address_family(self->network);
209
210 return PyLong_FromLong(family);
211 }
212
213 static PyObject* Network_get_first_address(NetworkObject* self) {
214 const char* address = loc_network_format_first_address(self->network);
215
216 return PyUnicode_FromString(address);
217 }
218
219 static 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
233 static 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
239 static PyObject* Network_get_last_address(NetworkObject* self) {
240 const char* address = loc_network_format_last_address(self->network);
241
242 return PyUnicode_FromString(address);
243 }
244
245 static 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
251 static 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
282 static 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
308 static struct PyMethodDef Network_methods[] = {
309 {
310 "exclude",
311 (PyCFunction)Network_exclude,
312 METH_VARARGS,
313 NULL,
314 },
315 {
316 "has_flag",
317 (PyCFunction)Network_has_flag,
318 METH_VARARGS,
319 NULL,
320 },
321 {
322 "is_subnet_of",
323 (PyCFunction)Network_is_subnet_of,
324 METH_VARARGS,
325 NULL,
326 },
327 {
328 "reverse_pointer",
329 (PyCFunction)Network_reverse_pointer,
330 METH_VARARGS|METH_KEYWORDS,
331 NULL,
332 },
333 {
334 "set_flag",
335 (PyCFunction)Network_set_flag,
336 METH_VARARGS,
337 NULL,
338 },
339 { NULL },
340 };
341
342 static struct PyGetSetDef Network_getsetters[] = {
343 {
344 "asn",
345 (getter)Network_get_asn,
346 (setter)Network_set_asn,
347 NULL,
348 NULL,
349 },
350 {
351 "country_code",
352 (getter)Network_get_country_code,
353 (setter)Network_set_country_code,
354 NULL,
355 NULL,
356 },
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 },
371 {
372 "_first_address",
373 (getter)Network_get__first_address,
374 NULL,
375 NULL,
376 NULL,
377 },
378 {
379 "last_address",
380 (getter)Network_get_last_address,
381 NULL,
382 NULL,
383 NULL,
384 },
385 {
386 "_last_address",
387 (getter)Network_get__last_address,
388 NULL,
389 NULL,
390 NULL,
391 },
392 { NULL },
393 };
394
395 PyTypeObject NetworkType = {
396 PyVarObject_HEAD_INIT(NULL, 0)
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",
404 .tp_methods = Network_methods,
405 .tp_getset = Network_getsetters,
406 .tp_repr = (reprfunc)Network_repr,
407 .tp_str = (reprfunc)Network_str,
408 .tp_richcompare = (richcmpfunc)Network_richcompare,
409 };