Skip to content

Commit a26136a

Browse files
author
Tigusoft
committed
Fix v4 long outgoing references blocking cjdroute
v3 change: v3 we now abort if there is a broken peer. (we leave the try-catch block in separate function, otherwise gcc complains about clobbered variables) Too long text of reference in outgoing peers (in connectTo) is handled correctly: We send to cjdroute (via UDP packet) only the needed data, skipping the fields that are not used. Also, if anyway the reference is still too large (e.g. had very long password), it will be skipped with an error logged. v4 change: add login field
1 parent a38e58b commit a26136a

3 files changed

Lines changed: 77 additions & 1 deletion

File tree

benc/serialization/standard/BencMessageWriter.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "benc/Dict.h"
1919
#include "benc/List.h"
2020
#include "exception/Except.h"
21+
#include "exception/Jmp.h"
2122
#include "wire/Message.h"
2223
#include "util/Base10.h"
2324

@@ -66,6 +67,25 @@ static void writeDict(Dict* d, struct Message* msg, struct Except* eh)
6667
Message_push8(msg, 'd', eh);
6768
}
6869

70+
/**
71+
* Tries to send a message same as in writeDic() but in case of some problems
72+
* where it would throw, it instead returns non-zero value to indicate error:
73+
* return 1 - there was an error
74+
* return 0 - no error was detected, but still no guarantee if message was sent,
75+
* some errors like message not fitting UDP-admin-packet size are NOT detected
76+
* (therefore you should detect them in caller function)
77+
*/
78+
int BencMessageWriter_writeDictTry(Dict* d, struct Message* msg, struct Except* eh)
79+
{
80+
struct Jmp jmp;
81+
Jmp_try(jmp) {
82+
writeDict(d, msg, &jmp.handler);
83+
return 0;
84+
} Jmp_catch {
85+
return 1;
86+
}
87+
}
88+
6989
static void writeGeneric(Object* obj, struct Message* msg, struct Except* eh)
7090
{
7191
switch (obj->type) {

benc/serialization/standard/BencMessageWriter.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,11 @@ Linker_require("benc/serialization/standard/BencMessageWriter.c")
2323

2424
void BencMessageWriter_write(Dict* toWrite, struct Message* msg, struct Except* eh);
2525

26+
/**
27+
* this function is a non-static wrapper for same function,
28+
* so that we can use it from other places to estimate if reference
29+
* will fit in admin UDP packet
30+
*/
31+
int BencMessageWriter_writeDictTry(Dict* d, struct Message* msg, struct Except* eh);
32+
2633
#endif

client/Configurator.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "client/Configurator.h"
1717
#include "benc/String.h"
1818
#include "benc/Dict.h"
19+
#include "benc/serialization/standard/BencMessageWriter.h"
1920
#include "benc/Int.h"
2021
#include "benc/List.h"
2122
#include "memory/Allocator.h"
@@ -42,6 +43,8 @@ struct Context
4243
struct EventBase* base;
4344
};
4445

46+
const int abort_if_invalid_ref = 1;
47+
4548
static void rpcCallback(struct AdminClient_Promise* p, struct AdminClient_Result* res)
4649
{
4750
struct Context* ctx = p->userData;
@@ -211,7 +214,37 @@ static void udpInterface(Dict* config, struct Context* ctx)
211214
"is not a dictionary type.", key->bytes);
212215
exit(-1);
213216
}
214-
Dict* value = entry->val->as.dictionary;
217+
Dict* all = entry->val->as.dictionary;
218+
Dict* value = Dict_new(perCallAlloc);
219+
String* pub_d = Dict_getString(all, String_CONST("publicKey"));
220+
String* pss_d = Dict_getString(all, String_CONST("password"));
221+
String* peerName_d = Dict_getString(all, String_CONST("peerName"));
222+
String* login_d = Dict_getString(all, String_CONST("login"));
223+
224+
if ( !pub_d || !pss_d ) {
225+
const char * error_name = "(unknown)";
226+
if ( !pub_d ) {
227+
error_name = "publicKey";
228+
}
229+
if ( !pss_d ) {
230+
error_name = "password";
231+
}
232+
Log_warn(ctx->logger,
233+
"Skipping peer: missing %s for peer [%s]", error_name, key->bytes);
234+
if (abort_if_invalid_ref) {
235+
Assert_failure("Invalid peer reference");
236+
}
237+
else {
238+
entry = entry->next;
239+
continue;
240+
}
241+
}
242+
243+
Dict_putString(value, String_CONST("publicKey"), pub_d, perCallAlloc);
244+
Dict_putString(value, String_CONST("password"), pss_d, perCallAlloc);
245+
Dict_putString(value, String_CONST("peerName"), peerName_d, perCallAlloc);
246+
Dict_putString(value, String_CONST("login"), login_d, perCallAlloc);
247+
215248
Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes);
216249
key = String_clone(key, perCallAlloc);
217250
char* lastColon = CString_strrchr(key->bytes, ':');
@@ -236,6 +269,22 @@ static void udpInterface(Dict* config, struct Context* ctx)
236269
continue;
237270
}
238271
}
272+
struct Allocator* child = Allocator_child(ctx->alloc);
273+
struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE + 256, child);
274+
int r = BencMessageWriter_writeDictTry(value, msg, NULL);
275+
276+
const int max_reference_size = 298;
277+
if (r != 0 || msg->length > max_reference_size) {
278+
Log_warn(ctx->logger, "Peer skipped:");
279+
Log_warn(ctx->logger, "Too long peer reference for [%s]", key->bytes);
280+
if (abort_if_invalid_ref) {
281+
Assert_failure("Invalid peer reference");
282+
}
283+
else {
284+
entry = entry->next;
285+
continue;
286+
}
287+
}
239288
Dict_putInt(value, String_CONST("interfaceNumber"), ifNum, perCallAlloc);
240289
Dict_putString(value, String_CONST("address"), key, perCallAlloc);
241290
rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc);

0 commit comments

Comments
 (0)