]> git.ipfire.org Git - location/libloc.git/blame - 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
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
MT
21
22#include <loc/libloc.h>
23#include <loc/network.h>
e0b9ff5f 24#include <loc/network-list.h>
39967361
MT
25
26#include "locationmodule.h"
27#include "network.h"
28
037c65d3
MT
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
31edab76
MT
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
39967361
MT
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
5118a4b8
MT
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
39967361
MT
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)
35f5acdc
MT
115 PyErr_Format(PyExc_ValueError,
116 "Invalid country code: %s", country_code);
39967361
MT
117
118 return -1;
119 }
120
121 return 0;
122}
123
71ff3e69
MT
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
7c78416c 137 if (asn <= 0) {
71ff3e69
MT
138 PyErr_Format(PyExc_ValueError, "Invalid ASN %ld", asn);
139 return -1;
140 }
141
7c78416c
MT
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
71ff3e69
MT
150 int r = loc_network_set_asn(self->network, asn);
151 if (r)
152 return -1;
153
154 return 0;
155}
156
24ca7992
MT
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
037c65d3
MT
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
43554dc4
MT
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
d6a5092f 206 if (loc_network_is_subnet(other->network, self->network))
43554dc4
MT
207 Py_RETURN_TRUE;
208
209 Py_RETURN_FALSE;
210}
211
2b9338ea
MT
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
a1a00053
MT
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
2b9338ea
MT
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
a1a00053
MT
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
24ca7992 262static struct PyMethodDef Network_methods[] = {
037c65d3
MT
263 {
264 "exclude",
265 (PyCFunction)Network_exclude,
266 METH_VARARGS,
267 NULL,
268 },
24ca7992
MT
269 {
270 "has_flag",
271 (PyCFunction)Network_has_flag,
272 METH_VARARGS,
273 NULL,
274 },
43554dc4
MT
275 {
276 "is_subnet_of",
277 (PyCFunction)Network_is_subnet_of,
278 METH_VARARGS,
279 NULL,
280 },
24ca7992
MT
281 {
282 "set_flag",
283 (PyCFunction)Network_set_flag,
284 METH_VARARGS,
285 NULL,
286 },
287 { NULL },
288};
289
39967361 290static struct PyGetSetDef Network_getsetters[] = {
71ff3e69
MT
291 {
292 "asn",
293 (getter)Network_get_asn,
294 (setter)Network_set_asn,
295 NULL,
296 NULL,
297 },
39967361
MT
298 {
299 "country_code",
300 (getter)Network_get_country_code,
301 (setter)Network_set_country_code,
302 NULL,
303 NULL,
304 },
2b9338ea
MT
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 },
a1a00053
MT
319 {
320 "_first_address",
321 (getter)Network_get__first_address,
322 NULL,
323 NULL,
324 NULL,
325 },
2b9338ea
MT
326 {
327 "last_address",
328 (getter)Network_get_last_address,
329 NULL,
330 NULL,
331 NULL,
332 },
a1a00053
MT
333 {
334 "_last_address",
335 (getter)Network_get__last_address,
336 NULL,
337 NULL,
338 NULL,
339 },
39967361
MT
340 { NULL },
341};
342
343PyTypeObject NetworkType = {
344 PyVarObject_HEAD_INIT(NULL, 0)
d42e1dcd
MT
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",
24ca7992 352 .tp_methods = Network_methods,
d42e1dcd
MT
353 .tp_getset = Network_getsetters,
354 .tp_repr = (reprfunc)Network_repr,
355 .tp_str = (reprfunc)Network_str,
39967361 356};