]> git.ipfire.org Git - location/libloc.git/blob - src/python/network.c
474b6de279969cbf875daf6157d12b0253bd16e8
[location/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/libloc.h>
23 #include <libloc/network.h>
24 #include <libloc/network-list.h>
25
26 #include "locationmodule.h"
27 #include "network.h"
28
29 static 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
47 PyObject* 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
56 static 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
62 static 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
69 static 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
85 static PyObject* Network_repr(NetworkObject* self) {
86 const char* network = loc_network_str(self->network);
87
88 return PyUnicode_FromFormat("<location.Network %s>", network);
89 }
90
91 static PyObject* Network_str(NetworkObject* self) {
92 const char* network = loc_network_str(self->network);
93
94 return PyUnicode_FromString(network);
95 }
96
97 static 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
103 static 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)
109 PyErr_Format(PyExc_ValueError,
110 "Invalid country code: %s", country_code);
111
112 return -1;
113 }
114
115 return 0;
116 }
117
118 static 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
127 static 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
131 if (asn <= 0) {
132 PyErr_Format(PyExc_ValueError, "Invalid ASN %ld", asn);
133 return -1;
134 }
135
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
144 int r = loc_network_set_asn(self->network, asn);
145 if (r)
146 return -1;
147
148 return 0;
149 }
150
151 static 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
163 static 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
179 static 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
194 static 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
200 if (loc_network_is_subnet(other->network, self->network))
201 Py_RETURN_TRUE;
202
203 Py_RETURN_FALSE;
204 }
205
206 static PyObject* Network_get_family(NetworkObject* self) {
207 int family = loc_network_address_family(self->network);
208
209 return PyLong_FromLong(family);
210 }
211
212 static PyObject* Network_get_first_address(NetworkObject* self) {
213 const char* address = loc_network_format_first_address(self->network);
214
215 return PyUnicode_FromString(address);
216 }
217
218 static 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
232 static 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
238 static PyObject* Network_get_last_address(NetworkObject* self) {
239 const char* address = loc_network_format_last_address(self->network);
240
241 return PyUnicode_FromString(address);
242 }
243
244 static 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
250 static struct PyMethodDef Network_methods[] = {
251 {
252 "exclude",
253 (PyCFunction)Network_exclude,
254 METH_VARARGS,
255 NULL,
256 },
257 {
258 "has_flag",
259 (PyCFunction)Network_has_flag,
260 METH_VARARGS,
261 NULL,
262 },
263 {
264 "is_subnet_of",
265 (PyCFunction)Network_is_subnet_of,
266 METH_VARARGS,
267 NULL,
268 },
269 {
270 "set_flag",
271 (PyCFunction)Network_set_flag,
272 METH_VARARGS,
273 NULL,
274 },
275 { NULL },
276 };
277
278 static struct PyGetSetDef Network_getsetters[] = {
279 {
280 "asn",
281 (getter)Network_get_asn,
282 (setter)Network_set_asn,
283 NULL,
284 NULL,
285 },
286 {
287 "country_code",
288 (getter)Network_get_country_code,
289 (setter)Network_set_country_code,
290 NULL,
291 NULL,
292 },
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 },
307 {
308 "_first_address",
309 (getter)Network_get__first_address,
310 NULL,
311 NULL,
312 NULL,
313 },
314 {
315 "last_address",
316 (getter)Network_get_last_address,
317 NULL,
318 NULL,
319 NULL,
320 },
321 {
322 "_last_address",
323 (getter)Network_get__last_address,
324 NULL,
325 NULL,
326 NULL,
327 },
328 { NULL },
329 };
330
331 PyTypeObject NetworkType = {
332 PyVarObject_HEAD_INIT(NULL, 0)
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",
340 .tp_methods = Network_methods,
341 .tp_getset = Network_getsetters,
342 .tp_repr = (reprfunc)Network_repr,
343 .tp_str = (reprfunc)Network_str,
344 };