173 lines
5.6 KiB
C++
173 lines
5.6 KiB
C++
// Copyright (c) Vitaliy Filippov, 2019+
|
|
// License: VNPL-1.1 (see README.md for details)
|
|
//
|
|
// Portmap service for NFS proxy
|
|
|
|
#include <netinet/in.h>
|
|
#include <string.h>
|
|
|
|
#include "nfs_portmap.h"
|
|
|
|
#include "libnfs-raw-portmap.h"
|
|
|
|
#include "sha256.h"
|
|
#include "base64.h"
|
|
|
|
/*
|
|
* The NULL procedure. All protocols/versions must provide a NULL procedure
|
|
* as index 0.
|
|
* It is used by clients, and rpcinfo, to "ping" a service and verify that
|
|
* the service is available and that it does support the indicated version.
|
|
*/
|
|
static int pmap2_null_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque)
|
|
{
|
|
rpc_send_reply(rpc, call, NULL, (zdrproc_t)zdr_void, 0);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* v2 GETPORT.
|
|
* This is the lookup function for portmapper version 2.
|
|
* A client provides program, version and protocol (tcp or udp)
|
|
* and portmapper returns which port that service is available on,
|
|
* (or 0 if no such program is registered.)
|
|
*/
|
|
static int pmap2_getport_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque)
|
|
{
|
|
portmap_service_t *self = (portmap_service_t *)opaque;
|
|
PMAP2GETPORTargs *args = (PMAP2GETPORTargs *)call->body.cbody.args;
|
|
uint32_t port = 0;
|
|
auto it = self->reg_ports.lower_bound((portmap_id_t){
|
|
.prog = args->prog,
|
|
.vers = args->vers,
|
|
.udp = args->prot == IPPROTO_UDP,
|
|
.ipv6 = false,
|
|
});
|
|
if (it != self->reg_ports.end() &&
|
|
it->prog == args->prog && it->vers == args->vers &&
|
|
it->udp == (args->prot == IPPROTO_UDP))
|
|
{
|
|
port = it->port;
|
|
}
|
|
rpc_send_reply(rpc, call, &port, (zdrproc_t)zdr_uint32_t, sizeof(uint32_t));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* v2 DUMP.
|
|
* This RPC returns a list of all endpoints that are registered with
|
|
* portmapper.
|
|
*/
|
|
static int pmap2_dump_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque)
|
|
{
|
|
portmap_service_t *self = (portmap_service_t *)opaque;
|
|
pmap2_mapping_list *list = new pmap2_mapping_list[self->reg_ports.size()];
|
|
int i = 0;
|
|
for (auto it = self->reg_ports.begin(); it != self->reg_ports.end(); it++)
|
|
{
|
|
if (it->ipv6)
|
|
continue;
|
|
list[i] = {
|
|
.map = {
|
|
.prog = it->prog,
|
|
.vers = it->vers,
|
|
.prot = it->udp ? IPPROTO_UDP : IPPROTO_TCP,
|
|
.port = it->port,
|
|
},
|
|
.next = list+i+1,
|
|
};
|
|
i++;
|
|
}
|
|
list[i-1].next = NULL;
|
|
// Send reply
|
|
PMAP2DUMPres reply;
|
|
reply.list = list;
|
|
rpc_send_reply(rpc, call, &reply, (zdrproc_t)zdr_PMAP2DUMPres, sizeof(PMAP2DUMPres));
|
|
reply.list = NULL;
|
|
delete list;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* v3 GETADDR.
|
|
* This is the lookup function for portmapper version 3.
|
|
*/
|
|
static int pmap3_getaddr_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque)
|
|
{
|
|
portmap_service_t *self = (portmap_service_t *)opaque;
|
|
PMAP3GETADDRargs *args = (PMAP3GETADDRargs *)call->body.cbody.args;
|
|
portmap_id_t ref = (portmap_id_t){
|
|
.prog = args->prog,
|
|
.vers = args->vers,
|
|
.udp = !strcmp(args->netid, "udp") || !strcmp(args->netid, "udp6"),
|
|
.ipv6 = !strcmp(args->netid, "tcp6") || !strcmp(args->netid, "udp6"),
|
|
};
|
|
auto it = self->reg_ports.lower_bound(ref);
|
|
PMAP3GETADDRres reply;
|
|
if (it != self->reg_ports.end() &&
|
|
it->prog == ref.prog && it->vers == ref.vers &&
|
|
it->udp == ref.udp && it->ipv6 == ref.ipv6)
|
|
{
|
|
reply.addr = (char*)it->addr.c_str();
|
|
}
|
|
rpc_send_reply(rpc, call, &reply, (zdrproc_t)zdr_PMAP3GETADDRres, sizeof(PMAP3GETADDRres));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* v3 DUMP.
|
|
* This RPC returns a list of all endpoints that are registered with
|
|
* portmapper.
|
|
*/
|
|
static int pmap3_dump_proc(struct rpc_context *rpc, struct rpc_msg *call, void *opaque)
|
|
{
|
|
portmap_service_t *self = (portmap_service_t *)opaque;
|
|
pmap3_mapping_list *list = new pmap3_mapping_list[self->reg_ports.size()];
|
|
int i = 0;
|
|
for (auto it = self->reg_ports.begin(); it != self->reg_ports.end(); it++)
|
|
{
|
|
list[i] = (pmap3_mapping_list){
|
|
.map = {
|
|
.prog = it->prog,
|
|
.vers = it->vers,
|
|
.netid = (char*)(it->ipv6
|
|
? (it->udp ? "udp6" : "tcp6")
|
|
: (it->udp ? "udp" : "tcp")),
|
|
.addr = (char*)it->addr.c_str(), // 0.0.0.0.port
|
|
.owner = (char*)it->owner.c_str(),
|
|
},
|
|
.next = list+i+1,
|
|
};
|
|
i++;
|
|
}
|
|
list[i-1].next = NULL;
|
|
// Send reply
|
|
PMAP3DUMPres reply;
|
|
reply.list = list;
|
|
rpc_send_reply(rpc, call, &reply, (zdrproc_t)zdr_PMAP3DUMPres, sizeof(PMAP3DUMPres));
|
|
reply.list = NULL;
|
|
delete list;
|
|
return 0;
|
|
}
|
|
|
|
portmap_service_t::portmap_service_t()
|
|
{
|
|
pmap2_pt.push_back((service_proc){PMAP2_NULL, pmap2_null_proc, (zdrproc_t)zdr_void, 0, this});
|
|
pmap2_pt.push_back((service_proc){PMAP2_GETPORT, pmap2_getport_proc, (zdrproc_t)zdr_PMAP2GETPORTargs, sizeof(PMAP2GETPORTargs), this});
|
|
pmap2_pt.push_back((service_proc){PMAP2_DUMP, pmap2_dump_proc, (zdrproc_t)zdr_void, 0, this});
|
|
pmap3_pt.push_back((service_proc){PMAP3_NULL, pmap2_null_proc, (zdrproc_t)zdr_void, 0, this});
|
|
pmap3_pt.push_back((service_proc){PMAP3_GETADDR, pmap3_getaddr_proc, (zdrproc_t)zdr_PMAP3GETADDRargs, sizeof(PMAP3GETADDRargs), this});
|
|
pmap3_pt.push_back((service_proc){PMAP3_DUMP, pmap3_dump_proc, (zdrproc_t)zdr_void, 0, this});
|
|
}
|
|
|
|
std::string sha256(const std::string & str)
|
|
{
|
|
std::string hash;
|
|
hash.resize(32);
|
|
SHA256_CTX ctx;
|
|
sha256_init(&ctx);
|
|
sha256_update(&ctx, (uint8_t*)str.data(), str.size());
|
|
sha256_final(&ctx, (uint8_t*)hash.data());
|
|
return hash;
|
|
}
|