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