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