123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- /* vim: set expandtab ts=4 sw=4: */
- /*
- * You may redistribute this program and/or modify it under the terms of
- * the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #include "benc/Int.h"
- #include "admin/Admin.h"
- #include "memory/Allocator.h"
- #include "net/InterfaceController.h"
- #include "util/events/EventBase.h"
- #include "util/platform/Sockaddr.h"
- #include "crypto/Key.h"
- #include "interface/UDPInterface_admin.h"
- #include "interface/UDPInterface.h"
- #include "util/Identity.h"
- #define ArrayList_TYPE struct UDPInterface
- #define ArrayList_NAME UDPInterface
- #include "util/ArrayList.h"
- struct Context
- {
- EventBase_t* eventBase;
- struct Allocator* alloc;
- struct Log* logger;
- struct Admin* admin;
- struct ArrayList_UDPInterface* ifaces;
- struct InterfaceController* ic;
- struct GlobalConfig* globalConf;
- Identity
- };
- static struct UDPInterface* getIface(struct Context* ctx,
- Dict* args,
- String* txid,
- struct Allocator* requestAlloc,
- uint32_t* ifNumP)
- {
- int64_t* interfaceNumber = Dict_getIntC(args, "interfaceNumber");
- uint32_t ifNum = (interfaceNumber) ? ((uint32_t) *interfaceNumber) : 0;
- if (ifNumP) { *ifNumP = ifNum; }
- struct UDPInterface* udpif = ArrayList_UDPInterface_get(ctx->ifaces, ifNum);
- if (!udpif) {
- Dict* out = Dict_new(requestAlloc);
- Dict_putStringCC(out, "error", "no such interface for interfaceNumber", requestAlloc);
- Admin_sendMessage(out, txid, ctx->admin);
- }
- return udpif;
- }
- static void beginConnection(Dict* args,
- void* vcontext,
- String* txid,
- struct Allocator* requestAlloc)
- {
- struct Context* ctx = Identity_check((struct Context*) vcontext);
- uint32_t ifNum = 0;
- struct UDPInterface* udpIf = getIface(ctx, args, txid, requestAlloc, &ifNum);
- if (!udpIf) { return; }
- String* password = Dict_getStringC(args, "password");
- String* login = Dict_getStringC(args, "login");
- String* publicKey = Dict_getStringC(args, "publicKey");
- String* address = Dict_getStringC(args, "address");
- String* peerName = Dict_getStringC(args, "peerName");
- int64_t* versionP = Dict_getIntC(args, "version");
- int version = Version_DEFAULT_ASSUMPTION;
- if (versionP) { version = *versionP; }
- char* error = NULL;
- Log_debug(ctx->logger, "Peering with [%s]", publicKey->bytes);
- struct Sockaddr_storage ss;
- uint8_t pkBytes[32];
- int ret;
- if ((ret = Key_parse(publicKey, pkBytes, NULL))) {
- error = Key_parse_strerror(ret);
- } else if (Sockaddr_parse(address->bytes, &ss)) {
- error = "unable to parse ip address and port.";
- } else if (Sockaddr_getFamily(&ss.addr) != Sockaddr_getFamily(udpIf->generic.addr)) {
- error = "different address type than this socket is bound to.";
- } else {
- struct Sockaddr* addr = &ss.addr;
- char* addrPtr = NULL;
- int addrLen = Sockaddr_getAddress(&ss.addr, &addrPtr);
- Assert_true(addrLen > 0);
- struct Allocator* tempAlloc = Allocator_child(ctx->alloc);
- if (Bits_isZero(addrPtr, addrLen)) {
- // unspec'd address, convert to loopback
- if (Sockaddr_getFamily(addr) == Sockaddr_AF_INET) {
- addr = Sockaddr_clone(Sockaddr_LOOPBACK, tempAlloc);
- } else if (Sockaddr_getFamily(addr) == Sockaddr_AF_INET6) {
- addr = Sockaddr_clone(Sockaddr_LOOPBACK6, tempAlloc);
- } else {
- Assert_failure("Sockaddr which is not AF_INET nor AF_INET6");
- }
- Sockaddr_setPort(addr, Sockaddr_getPort(&ss.addr));
- }
- int ret = InterfaceController_bootstrapPeer(
- ctx->ic, ifNum, pkBytes, addr, password, login, peerName, version);
- Allocator_free(tempAlloc);
- if (ret) {
- switch(ret) {
- case InterfaceController_bootstrapPeer_BAD_IFNUM:
- // Should never happen, should be caught in getIface()
- error = "interface deregistered";
- break;
- case InterfaceController_bootstrapPeer_BAD_KEY:
- error = "invalid cjdns public key.";
- break;
- case InterfaceController_bootstrapPeer_OUT_OF_SPACE:
- error = "no more space to register with the switch.";
- break;
- default:
- error = "unknown error";
- break;
- }
- } else {
- error = "none";
- }
- }
- Dict* out = Dict_new(requestAlloc);
- Dict_putStringCC(out, "error", error, requestAlloc);
- Admin_sendMessage(out, txid, ctx->admin);
- }
- static struct UDPInterface* setupLibuvUDP(struct Context* ctx,
- struct Sockaddr* addr,
- uint16_t beaconPort,
- uint8_t dscp,
- String* txid,
- struct Allocator* alloc)
- {
- struct Er_Ret* er = NULL;
- struct UDPInterface* udpIf = Er_check(&er, UDPInterface_new(
- ctx->eventBase, addr, beaconPort, alloc, ctx->logger, ctx->globalConf));
- if (er) {
- Dict* out = Dict_new(alloc);
- Dict_putStringCC(out, "error", er->message, alloc);
- Admin_sendMessage(out, txid, ctx->admin);
- Allocator_free(alloc);
- return NULL;
- } else if (dscp) {
- if (UDPInterface_setDSCP(udpIf, dscp)) {
- Log_warn(ctx->logger, "Set DSCP failed");
- }
- }
- return udpIf;
- }
- static void newInterface2(struct Context* ctx,
- struct Sockaddr* addr,
- uint8_t dscp,
- String* txid,
- struct Allocator* requestAlloc,
- uint16_t beaconPort)
- {
- struct Allocator* const alloc = Allocator_child(ctx->alloc);
- struct UDPInterface* udpif = setupLibuvUDP(ctx, addr, beaconPort, dscp, txid, alloc);
- if (!udpif) { return; }
- String* name = String_printf(requestAlloc, "UDP/IPv%d/%s",
- (Sockaddr_getFamily(addr) == Sockaddr_AF_INET ? 4 : 6),
- Sockaddr_print(addr, requestAlloc));
- struct InterfaceController_Iface* ici =
- InterfaceController_newIface(ctx->ic, name, alloc);
- Iface_plumb(&ici->addrIf, udpif->generic.iface);
- ArrayList_UDPInterface_put(ctx->ifaces, ici->ifNum, udpif);
- Dict* out = Dict_new(requestAlloc);
- Dict_putStringCC(out, "error", "none", requestAlloc);
- Dict_putIntC(out, "interfaceNumber", ici->ifNum, requestAlloc);
- char* printedAddr = Sockaddr_print(udpif->generic.addr, requestAlloc);
- Dict_putStringCC(out,
- "bindAddress",
- printedAddr,
- requestAlloc);
- Admin_sendMessage(out, txid, ctx->admin);
- }
- static void newInterface(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
- {
- struct Context* ctx = Identity_check((struct Context*) vcontext);
- String* bindAddress = Dict_getStringC(args, "bindAddress");
- int64_t* dscpValue = Dict_getIntC(args, "dscp");
- uint8_t dscp = dscpValue ? ((uint8_t) *dscpValue) : 0;
- int64_t* beaconPort_p = Dict_getIntC(args, "beaconPort");
- uint16_t beaconPort = beaconPort_p ? ((uint16_t) *beaconPort_p) : 0;
- struct Sockaddr_storage addr;
- if (Sockaddr_parse((bindAddress) ? bindAddress->bytes : "0.0.0.0", &addr)) {
- Dict out = Dict_CONST(
- String_CONST("error"), String_OBJ(String_CONST("Failed to parse address")), NULL
- );
- Admin_sendMessage(&out, txid, ctx->admin);
- return;
- }
- newInterface2(ctx, &addr.addr, dscp, txid, requestAlloc, beaconPort);
- }
- static void listDevices(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
- {
- struct Context* ctx = Identity_check((struct Context*) vcontext);
- Dict* out = Dict_new(requestAlloc);
- struct Er_Ret* er = NULL;
- List* list = Er_check(&er, UDPInterface_listDevices(requestAlloc));
- if (er) {
- Dict_putStringCC(out, "error", er->message, requestAlloc);
- } else {
- Dict_putListC(out, "ret", list, requestAlloc);
- }
- Admin_sendMessage(out, txid, ctx->admin);
- }
- static void setBroadcastDevices(
- Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
- {
- struct Context* ctx = Identity_check((struct Context*) vcontext);
- struct UDPInterface* udpif = getIface(ctx, args, txid, requestAlloc, NULL);
- if (!udpif) { return; }
- UDPInterface_setBroadcastDevices(udpif, Dict_getListC(args, "devices"));
- Dict* out = Dict_new(requestAlloc);
- Dict_putStringCC(out, "error", "none", requestAlloc);
- Admin_sendMessage(out, txid, ctx->admin);
- }
- static void getBroadcastDevices(
- Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
- {
- struct Context* ctx = Identity_check((struct Context*) vcontext);
- struct UDPInterface* udpif = getIface(ctx, args, txid, requestAlloc, NULL);
- if (!udpif) { return; }
- Dict* out = Dict_new(requestAlloc);
- Dict_putStringCC(out, "error", "none", requestAlloc);
- List* devices = UDPInterface_getBroadcastDevices(udpif, requestAlloc);
- Dict_putListC(out, "devices", devices, requestAlloc);
- Admin_sendMessage(out, txid, ctx->admin);
- }
- static void getBroadcastAddrs(
- Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
- {
- struct Context* ctx = Identity_check((struct Context*) vcontext);
- struct UDPInterface* udpif = getIface(ctx, args, txid, requestAlloc, NULL);
- if (!udpif) { return; }
- Dict* out = Dict_new(requestAlloc);
- Dict_putStringCC(out, "error", "none", requestAlloc);
- List* addrs = UDPInterface_getBroadcastAddrs(udpif, requestAlloc);
- Dict_putListC(out, "addrs", addrs, requestAlloc);
- Admin_sendMessage(out, txid, ctx->admin);
- }
- static void beacon(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
- {
- int64_t* stateP = Dict_getIntC(args, "state");
- int64_t* ifNumP = Dict_getIntC(args, "interfaceNumber");
- uint32_t ifNum = (ifNumP) ? ((uint32_t) *ifNumP) : 0;
- uint32_t state = (stateP) ? ((uint32_t) *stateP) : 0xffffffff;
- struct Context* ctx = Identity_check((struct Context*) vcontext);
- char* error = NULL;
- int ret = InterfaceController_beaconState(ctx->ic, ifNum, state);
- if (ret == InterfaceController_beaconState_NO_SUCH_IFACE) {
- error = "invalid interfaceNumber";
- } else if (ret == InterfaceController_beaconState_INVALID_STATE) {
- error = "invalid state";
- } else if (ret) {
- error = "internal";
- }
- if (error) {
- Dict* out = Dict_new(requestAlloc);
- Dict_putStringCC(out, "error", error, requestAlloc);
- Admin_sendMessage(out, txid, ctx->admin);
- return;
- }
- char* stateStr = "disabled";
- if (state == InterfaceController_beaconState_newState_ACCEPT) {
- stateStr = "accepting";
- } else if (state == InterfaceController_beaconState_newState_SEND) {
- stateStr = "sending and accepting";
- }
- Dict out = Dict_CONST(
- String_CONST("error"), String_OBJ(String_CONST("none")), Dict_CONST(
- String_CONST("state"), Int_OBJ(state), Dict_CONST(
- String_CONST("stateName"), String_OBJ(String_CONST(stateStr)), NULL
- )));
- Admin_sendMessage(&out, txid, ctx->admin);
- }
- static void getFd(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
- {
- struct Context* ctx = Identity_check((struct Context*) vcontext);
- struct UDPInterface* udpif = getIface(ctx, args, txid, requestAlloc, NULL);
- if (!udpif) {
- return;
- }
- int fd = UDPInterface_getFd(udpif);
- Dict* out = Dict_new(requestAlloc);
- Dict_putIntC(out, "fd", fd, requestAlloc);
- Dict_putStringCC(out, "error", "none", requestAlloc);
- Admin_sendMessage(out, txid, ctx->admin);
- }
- void UDPInterface_admin_register(EventBase_t* base,
- struct Allocator* alloc,
- struct Log* logger,
- struct Admin* admin,
- struct InterfaceController* ic,
- struct GlobalConfig* globalConf)
- {
- struct Context* ctx = Allocator_clone(alloc, (&(struct Context) {
- .eventBase = base,
- .alloc = alloc,
- .logger = logger,
- .admin = admin,
- .ic = ic,
- .globalConf = globalConf
- }));
- Identity_set(ctx);
- ctx->ifaces = ArrayList_UDPInterface_new(alloc);
- Admin_registerFunction("UDPInterface_new", newInterface, ctx, true,
- ((struct Admin_FunctionArg[]) {
- { .name = "bindAddress", .required = 0, .type = "String" },
- { .name = "dscp", .required = 0, .type = "Int" },
- { .name = "beaconPort", .required = 0, .type = "Int" }
- }), admin);
- Admin_registerFunction("UDPInterface_beginConnection", beginConnection, ctx, true,
- ((struct Admin_FunctionArg[]) {
- { .name = "interfaceNumber", .required = 0, .type = "Int" },
- { .name = "password", .required = 0, .type = "String" },
- { .name = "publicKey", .required = 1, .type = "String" },
- { .name = "address", .required = 1, .type = "String" },
- { .name = "login", .required = 0, .type = "String" },
- { .name = "peerName", .required = 0, .type = "String" },
- { .name = "version", .required = 0, .type = "Int" },
- }), admin);
- Admin_registerFunction("UDPInterface_listDevices", listDevices, ctx, true, NULL, admin);
- Admin_registerFunction("UDPInterface_setBroadcastDevices", setBroadcastDevices, ctx, true,
- ((struct Admin_FunctionArg[]) {
- { .name = "interfaceNumber", .required = 0, .type = "Int" },
- { .name = "devices", .required = 1, .type = "List" }
- }), admin);
- Admin_registerFunction("UDPInterface_getBroadcastDevices", getBroadcastDevices, ctx, true,
- ((struct Admin_FunctionArg[]) {
- { .name = "interfaceNumber", .required = 0, .type = "Int" }
- }), admin);
- Admin_registerFunction("UDPInterface_getBroadcastAddrs", getBroadcastAddrs, ctx, true,
- ((struct Admin_FunctionArg[]) {
- { .name = "interfaceNumber", .required = 0, .type = "Int" }
- }), admin);
- Admin_registerFunction("UDPInterface_beacon", beacon, ctx, true,
- ((struct Admin_FunctionArg[]) {
- { .name = "interfaceNumber", .required = 0, .type = "Int" },
- { .name = "state", .required = 0, .type = "Int" }
- }), admin);
- Admin_registerFunction("UDPInterface_getFd", getFd, ctx, true,
- ((struct Admin_FunctionArg[]) {
- { .name = "interfaceNumber", .required = 0, .type = "Int" },
- }), admin);
- }
|