2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
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.
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.
22 #include <libloc/compat.h>
23 #include <libloc/libloc.h>
24 #include <libloc/network.h>
25 #include <libloc/network-list.h>
27 #include "locationmodule.h"
30 static PyObject
* PyList_FromNetworkList(struct loc_network_list
* networks
) {
31 PyObject
* list
= PyList_New(0);
35 while (!loc_network_list_empty(networks
)) {
36 struct loc_network
* network
= loc_network_list_pop(networks
);
38 PyObject
* n
= new_network(&NetworkType
, network
);
39 PyList_Append(list
, n
);
41 loc_network_unref(network
);
48 PyObject
* new_network(PyTypeObject
* type
, struct loc_network
* network
) {
49 NetworkObject
* self
= (NetworkObject
*)type
->tp_alloc(type
, 0);
51 self
->network
= loc_network_ref(network
);
54 return (PyObject
*)self
;
57 static PyObject
* Network_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
58 NetworkObject
* self
= (NetworkObject
*)type
->tp_alloc(type
, 0);
60 return (PyObject
*)self
;
63 static void Network_dealloc(NetworkObject
* self
) {
65 loc_network_unref(self
->network
);
67 Py_TYPE(self
)->tp_free((PyObject
* )self
);
70 static int Network_init(NetworkObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
71 const char* network
= NULL
;
73 if (!PyArg_ParseTuple(args
, "s", &network
))
77 int r
= loc_network_new_from_string(loc_ctx
, &self
->network
, network
);
79 PyErr_Format(PyExc_ValueError
, "Invalid network: %s", network
);
86 static PyObject
* Network_repr(NetworkObject
* self
) {
87 const char* network
= loc_network_str(self
->network
);
89 return PyUnicode_FromFormat("<location.Network %s>", network
);
92 static PyObject
* Network_str(NetworkObject
* self
) {
93 const char* network
= loc_network_str(self
->network
);
95 return PyUnicode_FromString(network
);
98 static PyObject
* Network_get_country_code(NetworkObject
* self
) {
99 const char* country_code
= loc_network_get_country_code(self
->network
);
101 return PyUnicode_FromString(country_code
);
104 static int Network_set_country_code(NetworkObject
* self
, PyObject
* value
) {
105 const char* country_code
= PyUnicode_AsUTF8(value
);
107 int r
= loc_network_set_country_code(self
->network
, country_code
);
110 PyErr_Format(PyExc_ValueError
,
111 "Invalid country code: %s", country_code
);
119 static PyObject
* Network_get_asn(NetworkObject
* self
) {
120 uint32_t asn
= loc_network_get_asn(self
->network
);
123 return PyLong_FromLong(asn
);
128 static int Network_set_asn(NetworkObject
* self
, PyObject
* value
) {
129 long int asn
= PyLong_AsLong(value
);
131 // Check if the ASN is within the valid range
133 PyErr_Format(PyExc_ValueError
, "Invalid ASN %ld", asn
);
137 #if (__WORDSIZE > 32)
138 // Check whether the input was longer than 32 bit
139 if (asn
> UINT32_MAX
) {
140 PyErr_Format(PyExc_ValueError
, "Invalid ASN %ld", asn
);
145 int r
= loc_network_set_asn(self
->network
, asn
);
152 static PyObject
* Network_has_flag(NetworkObject
* self
, PyObject
* args
) {
153 enum loc_network_flags flag
= 0;
155 if (!PyArg_ParseTuple(args
, "i", &flag
))
158 if (loc_network_has_flag(self
->network
, flag
))
164 static PyObject
* Network_set_flag(NetworkObject
* self
, PyObject
* args
) {
165 enum loc_network_flags flag
= 0;
167 if (!PyArg_ParseTuple(args
, "i", &flag
))
170 int r
= loc_network_set_flag(self
->network
, flag
);
173 // What exception to throw here?
180 static PyObject
* Network_exclude(NetworkObject
* self
, PyObject
* args
) {
181 NetworkObject
* other
= NULL
;
183 if (!PyArg_ParseTuple(args
, "O!", &NetworkType
, &other
))
186 struct loc_network_list
* list
= loc_network_exclude(self
->network
, other
->network
);
188 // Convert to Python objects
189 PyObject
* obj
= PyList_FromNetworkList(list
);
190 loc_network_list_unref(list
);
195 static PyObject
* Network_is_subnet_of(NetworkObject
* self
, PyObject
* args
) {
196 NetworkObject
* other
= NULL
;
198 if (!PyArg_ParseTuple(args
, "O!", &NetworkType
, &other
))
201 if (loc_network_is_subnet(other
->network
, self
->network
))
207 static PyObject
* Network_get_family(NetworkObject
* self
) {
208 int family
= loc_network_address_family(self
->network
);
210 return PyLong_FromLong(family
);
213 static PyObject
* Network_get_first_address(NetworkObject
* self
) {
214 const char* address
= loc_network_format_first_address(self
->network
);
216 return PyUnicode_FromString(address
);
219 static PyObject
* PyBytes_FromAddress(const struct in6_addr
* address6
) {
220 struct in_addr address4
;
222 // Convert IPv4 addresses to struct in_addr
223 if (IN6_IS_ADDR_V4MAPPED(address6
)) {
224 address4
.s_addr
= address6
->s6_addr32
[3];
226 return PyBytes_FromStringAndSize((const char*)&address4
, sizeof(address4
));
229 // Return IPv6 addresses as they are
230 return PyBytes_FromStringAndSize((const char*)address6
, sizeof(*address6
));
233 static PyObject
* Network_get__first_address(NetworkObject
* self
) {
234 const struct in6_addr
* address
= loc_network_get_first_address(self
->network
);
236 return PyBytes_FromAddress(address
);
239 static PyObject
* Network_get_last_address(NetworkObject
* self
) {
240 const char* address
= loc_network_format_last_address(self
->network
);
242 return PyUnicode_FromString(address
);
245 static PyObject
* Network_get__last_address(NetworkObject
* self
) {
246 const struct in6_addr
* address
= loc_network_get_last_address(self
->network
);
248 return PyBytes_FromAddress(address
);
251 static PyObject
* Network_richcompare(NetworkObject
* self
, PyObject
* other
, int op
) {
255 if (!PyObject_IsInstance(other
, (PyObject
*)&NetworkType
))
256 Py_RETURN_NOTIMPLEMENTED
;
258 NetworkObject
* o
= (NetworkObject
*)other
;
260 r
= loc_network_cmp(self
->network
, o
->network
);
279 Py_RETURN_NOTIMPLEMENTED
;
282 static PyObject
* Network_reverse_pointer(NetworkObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
283 char* kwlist
[] = { "suffix", NULL
};
284 const char* suffix
= NULL
;
287 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|z", kwlist
, &suffix
))
290 rp
= loc_network_reverse_pointer(self
->network
, suffix
);
297 PyErr_SetFromErrno(PyExc_OSError
);
302 PyObject
* ret
= PyUnicode_FromString(rp
);
308 static struct PyMethodDef Network_methods
[] = {
311 (PyCFunction
)Network_exclude
,
317 (PyCFunction
)Network_has_flag
,
323 (PyCFunction
)Network_is_subnet_of
,
329 (PyCFunction
)Network_reverse_pointer
,
330 METH_VARARGS
|METH_KEYWORDS
,
335 (PyCFunction
)Network_set_flag
,
342 static struct PyGetSetDef Network_getsetters
[] = {
345 (getter
)Network_get_asn
,
346 (setter
)Network_set_asn
,
352 (getter
)Network_get_country_code
,
353 (setter
)Network_set_country_code
,
359 (getter
)Network_get_family
,
366 (getter
)Network_get_first_address
,
373 (getter
)Network_get__first_address
,
380 (getter
)Network_get_last_address
,
387 (getter
)Network_get__last_address
,
395 PyTypeObject NetworkType
= {
396 PyVarObject_HEAD_INIT(NULL
, 0)
397 .tp_name
= "location.Network",
398 .tp_basicsize
= sizeof(NetworkObject
),
399 .tp_flags
= Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
,
400 .tp_new
= Network_new
,
401 .tp_dealloc
= (destructor
)Network_dealloc
,
402 .tp_init
= (initproc
)Network_init
,
403 .tp_doc
= "Network object",
404 .tp_methods
= Network_methods
,
405 .tp_getset
= Network_getsetters
,
406 .tp_repr
= (reprfunc
)Network_repr
,
407 .tp_str
= (reprfunc
)Network_str
,
408 .tp_richcompare
= (richcmpfunc
)Network_richcompare
,