]>
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> | |
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 |
28 | static 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 |
46 | PyObject* 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 |
55 | static 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 | ||
61 | static 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 | ||
68 | static 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 | ||
84 | static 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 |
93 | static 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 |
102 | static 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 | ||
108 | static 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 |
123 | static 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 | ||
132 | static 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 |
148 | static 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 | ||
160 | static 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 |
176 | static 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 |
191 | static 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 | ||
d6a5092f | 197 | if (loc_network_is_subnet(other->network, self->network)) |
43554dc4 MT |
198 | Py_RETURN_TRUE; |
199 | ||
200 | Py_RETURN_FALSE; | |
201 | } | |
202 | ||
2b9338ea MT |
203 | static PyObject* Network_get_family(NetworkObject* self) { |
204 | int family = loc_network_address_family(self->network); | |
205 | ||
206 | return PyLong_FromLong(family); | |
207 | } | |
208 | ||
209 | static 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 |
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 | ||
2b9338ea MT |
238 | static 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 |
247 | static 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 | 253 | static 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 | 281 | static 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 | ||
334 | PyTypeObject 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 | }; |