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