1 /* vim: set expandtab ts=4 sw=4: */
2 /*
3 * You may redistribute this program and/or modify it under the terms of
4 * the GNU General Public License as published by the Free Software Foundation,
5 * either version 3 of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <https://www.gnu.org/licenses/>.
14 */
15 #include "admin/Admin.h"
16 #include "benc/String.h"
17 #include "benc/Dict.h"
18 #include "benc/List.h"
19 #include "benc/Int.h"
20 #include "crypto/AddressCalc.h"
21 #include "crypto/Key.h"
22 #ifdef HAS_ETH_INTERFACE
23 #include "interface/ETHInterface.h"
24 #endif
25 #include "net/InterfaceController.h"
26 #include "net/InterfaceController_admin.h"
27 #include "util/AddrTools.h"
28
29 struct Context
30 {
31 struct Allocator* alloc;
32 struct InterfaceController* ic;
33 struct Admin* admin;
34 Identity
35 };
36
37 // typical peer record is around 140 benc chars, so can't have very many in 1023
38 #define ENTRIES_PER_PAGE 6
39
adminInterfaces(Dict * args,void * vcontext,String * txid,struct Allocator * alloc)40 static void adminInterfaces(Dict* args,
41 void* vcontext,
42 String* txid,
43 struct Allocator* alloc)
44 {
45 struct Context* context = Identity_check((struct Context*)vcontext);
46
47 int64_t* page = Dict_getIntC(args, "page");
48 int i = (page) ? *page * ENTRIES_PER_PAGE : 0;
49
50 int count = InterfaceController_ifaceCount(context->ic);
51 //int count = InterfaceController_getIface(context->ic, alloc, &stats);
52
53 List* list = List_new(alloc);
54 for (int counter = 0; i < count && counter++ < ENTRIES_PER_PAGE; i++) {
55 struct InterfaceController_Iface* iface = InterfaceController_getIface(context->ic, i);
56 Dict* d = Dict_new(alloc);
57 Dict_putIntC(d, "ifNum", iface->ifNum, alloc);
58 Dict_putStringC(d, "name", iface->name, alloc);
59 char* bs = InterfaceController_beaconStateString(iface->beaconState);
60 Dict_putStringCC(d, "beaconState", bs, alloc);
61 List_addDict(list, d, alloc);
62 }
63
64 Dict* resp = Dict_new(alloc);
65 Dict_putListC(resp, "ifaces", list, alloc);
66 Dict_putIntC(resp, "total", count, alloc);
67 if (i < count) { Dict_putIntC(resp, "more", 1, alloc); }
68 Admin_sendMessage(resp, txid, context->admin);
69 }
70
adminPeerStats(Dict * args,void * vcontext,String * txid,struct Allocator * alloc)71 static void adminPeerStats(Dict* args, void* vcontext, String* txid, struct Allocator* alloc)
72 {
73 struct Context* context = Identity_check((struct Context*)vcontext);
74 struct InterfaceController_PeerStats* stats = NULL;
75
76 int64_t* page = Dict_getIntC(args, "page");
77 int i = (page) ? *page * ENTRIES_PER_PAGE : 0;
78
79 int count = InterfaceController_getPeerStats(context->ic, alloc, &stats);
80
81 List* list = List_new(alloc);
82 for (int counter=0; i < count && counter++ < ENTRIES_PER_PAGE; i++) {
83 Dict* d = Dict_new(alloc);
84 Dict_putIntC(d, "bytesIn", stats[i].bytesIn, alloc);
85 Dict_putIntC(d, "bytesOut", stats[i].bytesOut, alloc);
86
87 Dict_putIntC(d, "recvKbps", stats[i].recvKbps, alloc);
88 Dict_putIntC(d, "sendKbps", stats[i].sendKbps, alloc);
89
90 Dict_putStringC(d, "addr", Address_toStringKey(&stats[i].addr, alloc), alloc);
91
92 String* lladdrString;
93 #ifdef HAS_ETH_INTERFACE
94 if (ETHInterface_Sockaddr_SIZE == stats[i].lladdr->addrLen) {
95 struct ETHInterface_Sockaddr* eth = (struct ETHInterface_Sockaddr*) stats[i].lladdr;
96 uint8_t printedMac[18];
97 AddrTools_printMac(printedMac, eth->mac);
98 lladdrString = String_new(printedMac, alloc);
99 } else {
100 lladdrString = String_new(Sockaddr_print(stats[i].lladdr, alloc), alloc);
101 }
102 #else
103 lladdrString = String_new(Sockaddr_print(stats[i].lladdr, alloc), alloc);
104 #endif
105 Dict_putStringC(d, "lladdr", lladdrString, alloc);
106
107 String* stateString = String_new(InterfaceController_stateString(stats[i].state), alloc);
108 Dict_putStringC(d, "state", stateString, alloc);
109
110 Dict_putIntC(d, "last", stats[i].timeOfLastMessage, alloc);
111
112 Dict_putIntC(d, "isIncoming", stats[i].isIncomingConnection, alloc);
113 Dict_putIntC(d, "duplicates", stats[i].duplicates, alloc);
114 Dict_putIntC(d, "lostPackets", stats[i].lostPackets, alloc);
115 Dict_putIntC(d, "receivedOutOfRange", stats[i].receivedOutOfRange, alloc);
116
117 Dict_putIntC(d, "ifNum", stats[i].ifNum, alloc);
118
119 if (stats[i].user) {
120 Dict_putStringC(d, "user", stats[i].user, alloc);
121 }
122
123 Dict_putIntC(d, "receivedPackets", stats[i].receivedPackets, alloc);
124
125 List_addDict(list, d, alloc);
126 }
127
128 Dict* resp = Dict_new(alloc);
129 Dict_putListC(resp, "peers", list, alloc);
130 Dict_putIntC(resp, "total", count, alloc);
131
132 if (i < count) {
133 Dict_putIntC(resp, "more", 1, alloc);
134 }
135
136 Admin_sendMessage(resp, txid, context->admin);
137 }
138
adminDisconnectPeer(Dict * args,void * vcontext,String * txid,struct Allocator * requestAlloc)139 static void adminDisconnectPeer(Dict* args,
140 void* vcontext,
141 String* txid,
142 struct Allocator* requestAlloc)
143 {
144 struct Context* context = Identity_check((struct Context*)vcontext);
145 String* pubkeyString = Dict_getStringC(args, "pubkey");
146
147 // parse the key
148 uint8_t pubkey[32];
149 uint8_t addr[16];
150 int error = Key_parse(pubkeyString, pubkey, addr);
151
152 char* errorMsg = NULL;
153 if (error) {
154 errorMsg = "bad key";
155 } else {
156 // try to remove the peer if the key is valid
157 error = InterfaceController_disconnectPeer(context->ic,pubkey);
158 if (error) {
159 errorMsg = "no peer found for that key";
160 }
161 }
162
163 Dict* response = Dict_new(requestAlloc);
164 Dict_putIntC(response, "success", error ? 0 : 1, requestAlloc);
165 if (error) {
166 Dict_putStringCC(response, "error", errorMsg, requestAlloc);
167 }
168
169 Admin_sendMessage(response, txid, context->admin);
170 }
171
adminResetPeering(Dict * args,void * vcontext,String * txid,struct Allocator * requestAlloc)172 static void adminResetPeering(Dict* args,
173 void* vcontext,
174 String* txid,
175 struct Allocator* requestAlloc)
176 {
177 struct Context* context = Identity_check((struct Context*)vcontext);
178 String* pubkeyString = Dict_getStringC(args, "pubkey");
179
180 int error = 0;
181 char* errorMsg = NULL;
182
183 if (pubkeyString) {
184 // parse the key
185 uint8_t pubkey[32];
186 uint8_t addr[16];
187 error = Key_parse(pubkeyString, pubkey, addr);
188
189 if (error) {
190 errorMsg = "bad key";
191 } else {
192 InterfaceController_resetPeering(context->ic, pubkey);
193 }
194 } else {
195 // reset all
196 InterfaceController_resetPeering(context->ic, NULL);
197 }
198
199 Dict* response = Dict_new(requestAlloc);
200 Dict_putIntC(response, "success", error ? 0 : 1, requestAlloc);
201 if (error) {
202 Dict_putStringCC(response, "error", errorMsg, requestAlloc);
203 }
204
205 Admin_sendMessage(response, txid, context->admin);
206 }
207
timestampPackets(Dict * args,void * vcontext,String * txid,struct Allocator * requestAlloc)208 static void timestampPackets(Dict* args,
209 void* vcontext,
210 String* txid,
211 struct Allocator* requestAlloc)
212 {
213 struct Context* context = Identity_check((struct Context*)vcontext);
214 int64_t* enable = Dict_getIntC(args, "enable");
215 Dict* response = Dict_new(requestAlloc);
216 Dict_putStringCC(response, "error", "none", requestAlloc);
217 if (!enable) {
218 Dict_putIntC(response, "enabled", context->ic->timestampPackets, requestAlloc);
219 } else {
220 context->ic->timestampPackets = *enable;
221 }
222 Admin_sendMessage(response, txid, context->admin);
223 }
224
225 /*
226 static resetSession(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
227 {
228 struct Context* context = Identity_check((struct Context*)vcontext);
229 String* pubkeyString = Dict_getStringC(args, "pubkey");
230
231 // parse the key
232 uint8_t pubkey[32];
233 uint8_t addr[16];
234 int error = Key_parse(pubkeyString, pubkey, addr);
235
236 char* errorMsg = NULL;
237 if (error) {
238 errorMsg = "bad key";
239 } else {
240 // try to remove the peer if the key is valid
241 error = InterfaceController_disconnectPeer(context->ic,pubkey);
242 if (error) {
243 errorMsg = "no peer found for that key";
244 }
245 }
246
247 Dict* response = Dict_new(requestAlloc);
248 Dict_putIntC(response, "success", error ? 0 : 1, requestAlloc);
249 if (error) {
250 Dict_putStringCC(response, "error", errorMsg, requestAlloc);
251 }
252
253 Admin_sendMessage(response, txid, context->admin);
254 }*/
255
InterfaceController_admin_register(struct InterfaceController * ic,struct Admin * admin,struct Allocator * allocator)256 void InterfaceController_admin_register(struct InterfaceController* ic,
257 struct Admin* admin,
258 struct Allocator* allocator)
259 {
260 struct Allocator* alloc = Allocator_child(allocator);
261 struct Context* ctx = Allocator_clone(alloc, (&(struct Context) {
262 .alloc = alloc,
263 .ic = ic,
264 .admin = admin
265 }));
266 Identity_set(ctx);
267
268 Admin_registerFunction("InterfaceController_interfaces", adminInterfaces, ctx, true,
269 ((struct Admin_FunctionArg[]) {
270 { .name = "page", .required = 0, .type = "Int" }
271 }), admin);
272
273 Admin_registerFunction("InterfaceController_peerStats", adminPeerStats, ctx, false,
274 ((struct Admin_FunctionArg[]) {
275 { .name = "page", .required = 0, .type = "Int" }
276 }), admin);
277
278 Admin_registerFunction("InterfaceController_resetPeering", adminResetPeering, ctx, true,
279 ((struct Admin_FunctionArg[]) {
280 { .name = "pubkey", .required = 0, .type = "String" }
281 }), admin);
282
283 Admin_registerFunction("InterfaceController_disconnectPeer", adminDisconnectPeer, ctx, true,
284 ((struct Admin_FunctionArg[]) {
285 { .name = "pubkey", .required = 1, .type = "String" }
286 }), admin);
287
288 Admin_registerFunction("InterfaceController_timestampPackets", timestampPackets, ctx, true,
289 ((struct Admin_FunctionArg[]) {
290 { .name = "enable", .required = 0, .type = "Int" }
291 }), admin);
292
293 }
294