]> git.ipfire.org Git - location/libloc.git/blame - src/lua/network.c
lua: Add function that returns subnets of a network
[location/libloc.git] / src / lua / network.c
CommitLineData
e914e3ca
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2024 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 <errno.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <lua.h>
22#include <lauxlib.h>
23
24#include <libloc/network.h>
25
26#include "location.h"
031bae06 27#include "compat.h"
e914e3ca
MT
28#include "network.h"
29
30typedef struct network {
31 struct loc_network* network;
32} Network;
33
34static Network* luaL_checknetwork(lua_State* L, int i) {
35 void* userdata = luaL_checkudata(L, i, "location.Network");
36
37 // Throw an error if the argument doesn't match
38 luaL_argcheck(L, userdata, i, "Network expected");
39
40 return (Network*)userdata;
41}
42
9fac2ef2 43int create_network(lua_State* L, struct loc_network* network) {
e914e3ca
MT
44 // Allocate a new object
45 Network* self = (Network*)lua_newuserdata(L, sizeof(*self));
46
47 // Set metatable
48 luaL_setmetatable(L, "location.Network");
49
50 // Store network
51 self->network = loc_network_ref(network);
52
53 return 1;
54}
55
56static int Network_new(lua_State* L) {
57 struct loc_network* network = NULL;
58 const char* n = NULL;
59 int r;
60
61 // Fetch the network
62 n = luaL_checkstring(L, 1);
63
64 // Parse the string
65 r = loc_network_new_from_string(ctx, &network, n);
66 if (r)
67 return luaL_error(L, "Could not create network %s: %s\n", n, strerror(errno));
68
69 // Return the network
70 r = create_network(L, network);
71 loc_network_unref(network);
72
73 return r;
74}
75
75448a02 76static int Network_gc(lua_State* L) {
6b296c60 77 Network* self = luaL_checknetwork(L, 1);
e914e3ca 78
6b296c60
MT
79 // Free the network
80 if (self->network) {
e914e3ca 81 loc_network_unref(self->network);
6b296c60
MT
82 self->network = NULL;
83 }
84
85 return 0;
86}
e914e3ca 87
e914e3ca
MT
88static int Network_tostring(lua_State* L) {
89 Network* self = luaL_checknetwork(L, 1);
90
91 // Push string representation of the network
92 lua_pushstring(L, loc_network_str(self->network));
93
94 return 1;
95}
96
97// ASN
98
99static int Network_get_asn(lua_State* L) {
b49c59d2 100 Network* self = luaL_checknetwork(L, 1);
e914e3ca
MT
101
102 uint32_t asn = loc_network_get_asn(self->network);
103
104 // Push ASN
105 if (asn)
106 lua_pushnumber(L, asn);
107 else
108 lua_pushnil(L);
109
110 return 1;
111}
112
113// Family
114
115static int Network_get_family(lua_State* L) {
b49c59d2 116 Network* self = luaL_checknetwork(L, 1);
e914e3ca
MT
117
118 // Push family
119 lua_pushnumber(L, loc_network_address_family(self->network));
120
121 return 1;
122}
123
124// Country Code
125
126static int Network_get_country_code(lua_State* L) {
b49c59d2 127 Network* self = luaL_checknetwork(L, 1);
e914e3ca
MT
128
129 const char* country_code = loc_network_get_country_code(self->network);
130
131 // Push country code
132 if (country_code && *country_code)
133 lua_pushstring(L, country_code);
134 else
135 lua_pushnil(L);
136
137 return 1;
138}
139
af7f7210
MT
140// Has Flag?
141
142static int Network_has_flag(lua_State* L) {
143 Network* self = luaL_checknetwork(L, 1);
144
145 // Fetch flag
146 int flag = luaL_checknumber(L, 2);
147
148 // Push result
149 lua_pushboolean(L, loc_network_has_flag(self->network, flag));
150
151 return 1;
152}
153
a457e5e5
MT
154// Subnets
155
156static int Network_subnets(lua_State* L) {
157 struct loc_network* subnet1 = NULL;
158 struct loc_network* subnet2 = NULL;
159 int r;
160
161 Network* self = luaL_checknetwork(L, 1);
162
163 // Make subnets
164 r = loc_network_subnets(self->network, &subnet1, &subnet2);
165 if (r)
166 return luaL_error(L, "Could not create subnets of %s: %s\n",
167 loc_network_str(self->network), strerror(errno));
168
169 // Create a new table
170 lua_createtable(L, 2, 0);
171
172 // Create the networks & push them onto the table
173 create_network(L, subnet1);
174 loc_network_unref(subnet1);
175 lua_rawseti(L, -2, 1);
176
177 create_network(L, subnet2);
178 loc_network_unref(subnet2);
179 lua_rawseti(L, -2, 2);
180
181 return 1;
182}
183
8da88dda
MT
184// Reverse Pointer
185
186static int Network_reverse_pointer(lua_State* L) {
187 char* rp = NULL;
188
189 Network* self = luaL_checknetwork(L, 1);
190
191 // Fetch the suffix
192 const char* suffix = luaL_optstring(L, 2, NULL);
193
194 // Make the reverse pointer
195 rp = loc_network_reverse_pointer(self->network, suffix);
196 if (!rp) {
197 switch (errno) {
198 case ENOTSUP:
199 lua_pushnil(L);
200 return 1;
201
202 default:
203 return luaL_error(L, "Could not create reverse pointer: %s\n", strerror(errno));
204 }
205 }
206
207 // Return the response
208 lua_pushstring(L, rp);
209 free(rp);
210
211 return 1;
212}
213
e914e3ca
MT
214static const struct luaL_Reg Network_functions[] = {
215 { "new", Network_new },
216 { "get_asn", Network_get_asn },
e914e3ca 217 { "get_country_code", Network_get_country_code },
af7f7210
MT
218 { "get_family", Network_get_family },
219 { "has_flag", Network_has_flag },
8da88dda 220 { "reverse_pointer", Network_reverse_pointer },
a457e5e5 221 { "subnets", Network_subnets },
e914e3ca
MT
222 { "__gc", Network_gc },
223 { "__tostring", Network_tostring },
224 { NULL, NULL },
225};
226
227int register_network(lua_State* L) {
228 return register_class(L, "location.Network", Network_functions);
229}