]>
Commit | Line | Data |
---|---|---|
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 |
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 | ||
31edab76 MT |
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 | ||
39967361 MT |
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 | 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 |
94 | static 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 |
103 | static 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 | ||
109 | static 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 |
124 | static 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 | ||
133 | static 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 |
157 | static 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 | ||
169 | static 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 |
185 | static 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 |
200 | static 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 |
212 | static PyObject* Network_get_family(NetworkObject* self) { |
213 | int family = loc_network_address_family(self->network); | |
214 | ||
215 | return PyLong_FromLong(family); | |
216 | } | |
217 | ||
218 | static 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 |
227 | static 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 | ||
241 | static 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 |
247 | static 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 |
256 | static 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 | 262 | static 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 | 290 | static 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 | ||
343 | PyTypeObject 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 | }; |