]>
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 | 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 |
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) { | |
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 | 91 | static 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 |
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) | |
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 |
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 | |
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 |
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 | ||
037c65d3 MT |
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 | ||
43554dc4 MT |
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 | ||
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 |
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) { | |
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 |
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 | 238 | static 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 |
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 | ||
24ca7992 | 250 | static 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 | 278 | static 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 | ||
331 | PyTypeObject 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 | }; |