]> git.ipfire.org Git - location/libloc.git/blame - src/python/network.c
strings: Statically allocate all address/network strings
[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 21
c12a1385
MT
22#include <libloc/libloc.h>
23#include <libloc/network.h>
24#include <libloc/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) {
0a0a289a 86 const char* network = loc_network_str(self->network);
39967361 87
0a0a289a 88 return PyUnicode_FromFormat("<location.Network %s>", network);
39967361
MT
89}
90
5118a4b8 91static PyObject* Network_str(NetworkObject* self) {
0a0a289a 92 const char* network = loc_network_str(self->network);
5118a4b8 93
0a0a289a 94 return PyUnicode_FromString(network);
5118a4b8
MT
95}
96
39967361
MT
97static PyObject* Network_get_country_code(NetworkObject* self) {
98 const char* country_code = loc_network_get_country_code(self->network);
99
100 return PyUnicode_FromString(country_code);
101}
102
103static int Network_set_country_code(NetworkObject* self, PyObject* value) {
104 const char* country_code = PyUnicode_AsUTF8(value);
105
106 int r = loc_network_set_country_code(self->network, country_code);
107 if (r) {
108 if (r == -EINVAL)
35f5acdc
MT
109 PyErr_Format(PyExc_ValueError,
110 "Invalid country code: %s", country_code);
39967361
MT
111
112 return -1;
113 }
114
115 return 0;
116}
117
71ff3e69
MT
118static PyObject* Network_get_asn(NetworkObject* self) {
119 uint32_t asn = loc_network_get_asn(self->network);
120
121 if (asn)
122 return PyLong_FromLong(asn);
123
124 Py_RETURN_NONE;
125}
126
127static int Network_set_asn(NetworkObject* self, PyObject* value) {
128 long int asn = PyLong_AsLong(value);
129
130 // Check if the ASN is within the valid range
7c78416c 131 if (asn <= 0) {
71ff3e69
MT
132 PyErr_Format(PyExc_ValueError, "Invalid ASN %ld", asn);
133 return -1;
134 }
135
7c78416c
MT
136#if (__WORDSIZE > 32)
137 // Check whether the input was longer than 32 bit
138 if (asn > UINT32_MAX) {
139 PyErr_Format(PyExc_ValueError, "Invalid ASN %ld", asn);
140 return -1;
141 }
142#endif
143
71ff3e69
MT
144 int r = loc_network_set_asn(self->network, asn);
145 if (r)
146 return -1;
147
148 return 0;
149}
150
24ca7992
MT
151static PyObject* Network_has_flag(NetworkObject* self, PyObject* args) {
152 enum loc_network_flags flag = 0;
153
154 if (!PyArg_ParseTuple(args, "i", &flag))
155 return NULL;
156
157 if (loc_network_has_flag(self->network, flag))
158 Py_RETURN_TRUE;
159
160 Py_RETURN_FALSE;
161}
162
163static PyObject* Network_set_flag(NetworkObject* self, PyObject* args) {
164 enum loc_network_flags flag = 0;
165
166 if (!PyArg_ParseTuple(args, "i", &flag))
167 return NULL;
168
169 int r = loc_network_set_flag(self->network, flag);
170
171 if (r) {
172 // What exception to throw here?
173 return NULL;
174 }
175
176 Py_RETURN_NONE;
177}
178
037c65d3
MT
179static PyObject* Network_exclude(NetworkObject* self, PyObject* args) {
180 NetworkObject* other = NULL;
181
182 if (!PyArg_ParseTuple(args, "O!", &NetworkType, &other))
183 return NULL;
184
185 struct loc_network_list* list = loc_network_exclude(self->network, other->network);
186
187 // Convert to Python objects
188 PyObject* obj = PyList_FromNetworkList(list);
189 loc_network_list_unref(list);
190
191 return obj;
192}
193
43554dc4
MT
194static PyObject* Network_is_subnet_of(NetworkObject* self, PyObject* args) {
195 NetworkObject* other = NULL;
196
197 if (!PyArg_ParseTuple(args, "O!", &NetworkType, &other))
198 return NULL;
199
d6a5092f 200 if (loc_network_is_subnet(other->network, self->network))
43554dc4
MT
201 Py_RETURN_TRUE;
202
203 Py_RETURN_FALSE;
204}
205
2b9338ea
MT
206static PyObject* Network_get_family(NetworkObject* self) {
207 int family = loc_network_address_family(self->network);
208
209 return PyLong_FromLong(family);
210}
211
212static PyObject* Network_get_first_address(NetworkObject* self) {
0a0a289a 213 const char* address = loc_network_format_first_address(self->network);
2b9338ea 214
0a0a289a 215 return PyUnicode_FromString(address);
2b9338ea
MT
216}
217
a1a00053
MT
218static PyObject* PyBytes_FromAddress(const struct in6_addr* address6) {
219 struct in_addr address4;
220
221 // Convert IPv4 addresses to struct in_addr
222 if (IN6_IS_ADDR_V4MAPPED(address6)) {
223 address4.s_addr = address6->s6_addr32[3];
224
225 return PyBytes_FromStringAndSize((const char*)&address4, sizeof(address4));
226 }
227
228 // Return IPv6 addresses as they are
229 return PyBytes_FromStringAndSize((const char*)address6, sizeof(*address6));
230}
231
232static PyObject* Network_get__first_address(NetworkObject* self) {
233 const struct in6_addr* address = loc_network_get_first_address(self->network);
234
235 return PyBytes_FromAddress(address);
236}
237
2b9338ea 238static PyObject* Network_get_last_address(NetworkObject* self) {
0a0a289a 239 const char* address = loc_network_format_last_address(self->network);
2b9338ea 240
0a0a289a 241 return PyUnicode_FromString(address);
2b9338ea
MT
242}
243
a1a00053
MT
244static PyObject* Network_get__last_address(NetworkObject* self) {
245 const struct in6_addr* address = loc_network_get_last_address(self->network);
246
247 return PyBytes_FromAddress(address);
248}
249
24ca7992 250static struct PyMethodDef Network_methods[] = {
037c65d3
MT
251 {
252 "exclude",
253 (PyCFunction)Network_exclude,
254 METH_VARARGS,
255 NULL,
256 },
24ca7992
MT
257 {
258 "has_flag",
259 (PyCFunction)Network_has_flag,
260 METH_VARARGS,
261 NULL,
262 },
43554dc4
MT
263 {
264 "is_subnet_of",
265 (PyCFunction)Network_is_subnet_of,
266 METH_VARARGS,
267 NULL,
268 },
24ca7992
MT
269 {
270 "set_flag",
271 (PyCFunction)Network_set_flag,
272 METH_VARARGS,
273 NULL,
274 },
275 { NULL },
276};
277
39967361 278static struct PyGetSetDef Network_getsetters[] = {
71ff3e69
MT
279 {
280 "asn",
281 (getter)Network_get_asn,
282 (setter)Network_set_asn,
283 NULL,
284 NULL,
285 },
39967361
MT
286 {
287 "country_code",
288 (getter)Network_get_country_code,
289 (setter)Network_set_country_code,
290 NULL,
291 NULL,
292 },
2b9338ea
MT
293 {
294 "family",
295 (getter)Network_get_family,
296 NULL,
297 NULL,
298 NULL,
299 },
300 {
301 "first_address",
302 (getter)Network_get_first_address,
303 NULL,
304 NULL,
305 NULL,
306 },
a1a00053
MT
307 {
308 "_first_address",
309 (getter)Network_get__first_address,
310 NULL,
311 NULL,
312 NULL,
313 },
2b9338ea
MT
314 {
315 "last_address",
316 (getter)Network_get_last_address,
317 NULL,
318 NULL,
319 NULL,
320 },
a1a00053
MT
321 {
322 "_last_address",
323 (getter)Network_get__last_address,
324 NULL,
325 NULL,
326 NULL,
327 },
39967361
MT
328 { NULL },
329};
330
331PyTypeObject NetworkType = {
332 PyVarObject_HEAD_INIT(NULL, 0)
d42e1dcd
MT
333 .tp_name = "location.Network",
334 .tp_basicsize = sizeof(NetworkObject),
335 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
336 .tp_new = Network_new,
337 .tp_dealloc = (destructor)Network_dealloc,
338 .tp_init = (initproc)Network_init,
339 .tp_doc = "Network object",
24ca7992 340 .tp_methods = Network_methods,
d42e1dcd
MT
341 .tp_getset = Network_getsetters,
342 .tp_repr = (reprfunc)Network_repr,
343 .tp_str = (reprfunc)Network_str,
39967361 344};