[PATCH] portmap: new applet
Lukas Huba
huba.lukas at centrum.cz
Sun May 1 14:22:15 UTC 2011
Hi BusyBox,
I have created new applet portmap (request from TODO list). This applet was mediumly tested.
Typical use:
`portmap` : Run and listen to all interfaces
`portmap -h a.b.c.d` : Run and listen to ip a.b.c.d
`portmap -p` : Run and listen to all interface and allow SET and UNSET procedures from port >= 1024
`portmap -r` : Run and listen to all interface and allow SET and UNSET procedures from any host
Code stats:
include/applets.src.h | 1 +
include/usage.src.h | 8 ++
networking/Config.src | 16 ++++
networking/Kbuild.src | 1 +
networking/portmap.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 240 insertions(+), 0 deletions(-)
create mode 100644 networking/portmap.c
Size stats:
function old new delta
check_security - 513 +513
portmap_main - 423 +423
_pmapproc - 390 +390
_pmapproc_set - 320 +320
_pmapproc_unset - 272 +272
.rodata 1985 2215 +230
create_and_bind_or_die - 215 +215
xsocket_type - 190 +190
_pmapproc_getport - 102 +102
xdotted2sockaddr - 49 +49
setsockopt_reuseaddr - 45 +45
create_and_bind_stream_or_die - 42 +42
create_and_bind_dgram_or_die - 42 +42
pl - 8 +8
applet_names 17 25 +8
applet_main 16 24 +8
pn - 4 +4
ifs - 4 +4
flags - 4 +4
const_int_1 - 4 +4
applet_nameofs 4 6 +2
------------------------------------------------------------------------------
(add/remove: 18/0 grow/shrink: 4/0 up/down: 2875/0) Total: 2875 bytes
text data bss dec hex filename
29947 1674 8320 39941 9c05 busybox_old
34547 1806 8336 44689 ae91 busybox_unstripped
Patch attached.
Lukas Huba
<huba.lukas at centrum.cz>
Signed-off-by: Lukas Huba <huba.lukas at centrum.cz>
---
include/applets.src.h | 1 +
include/usage.src.h | 8 ++
networking/Config.src | 16 ++++
networking/Kbuild.src | 1 +
networking/portmap.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 239 insertions(+), 0 deletions(-)
create mode 100644 networking/portmap.c
diff --git a/include/applets.src.h b/include/applets.src.h
index 133f376..e92f215 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -283,6 +283,7 @@ IF_PIPE_PROGRESS(APPLET(pipe_progress, BB_DIR_BIN, BB_SUID_DROP))
IF_PIVOT_ROOT(APPLET(pivot_root, BB_DIR_SBIN, BB_SUID_DROP))
IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill))
IF_POPMAILDIR(APPLET(popmaildir, BB_DIR_USR_SBIN, BB_SUID_DROP))
+IF_PORTMAP(APPLET(portmap, BB_DIR_SBIN, BB_SUID_DROP))
IF_PRINTENV(APPLET_NOFORK(printenv, printenv, BB_DIR_BIN, BB_SUID_DROP, printenv))
IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf))
IF_PS(APPLET(ps, BB_DIR_BIN, BB_SUID_DROP))
diff --git a/include/usage.src.h b/include/usage.src.h
index d836093..a94df3c 100644
--- a/include/usage.src.h
+++ b/include/usage.src.h
@@ -1834,6 +1834,14 @@ INSERT
"$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [<password_file]\n" \
"$ popmaildir ~/Maildir -- openssl s_client -quiet -connect pop.gmail.com:995 [<password_file]\n"
+#define portmap_trivial_usage \
+ "[hpr]"
+#define portmap_full_usage "\n\n" \
+ "RPC program, version to DARPA port mapper\n" \
+ "\nOptions:" \
+ "\n -h Specify specific IP addresses to bind to for requests" \
+ "\n -p Insecure mode. Allow calls to SET and UNSET from any port (allow port > 1024)" \
+ "\n -r Insecure mode. Allow calls to SET and UNSET from any host" \
#if ENABLE_DESKTOP
diff --git a/networking/Config.src b/networking/Config.src
index 8aeba0e..37866ac 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -656,6 +656,22 @@ config FEATURE_NTPD_SERVER
Make ntpd usable as a NTP server. If you disable this option
ntpd will be usable only as a NTP client.
+config PORTMAP
+ bool "portmap"
+ default n
+ select PLATFORM_LINUX
+ select FEATURE_SYSLOG
+ help
+ RPC program, version to DARPA port mapper.
+
+config PORTMAP_ITEMS_MAX
+ int "Maximum RPC services"
+ default 32
+ depends on PORTMAP
+ help
+ Maximum RPC services which portmap is able to store.
+ That's for better security.
+
config PSCAN
bool "pscan"
default y
diff --git a/networking/Kbuild.src b/networking/Kbuild.src
index 944f27b..3f1d026 100644
--- a/networking/Kbuild.src
+++ b/networking/Kbuild.src
@@ -30,6 +30,7 @@ lib-$(CONFIG_NC) += nc.o
lib-$(CONFIG_NETSTAT) += netstat.o
lib-$(CONFIG_NSLOOKUP) += nslookup.o
lib-$(CONFIG_NTPD) += ntpd.o
+lib-$(CONFIG_PORTMAP) += portmap.o
lib-$(CONFIG_PSCAN) += pscan.o
lib-$(CONFIG_ROUTE) += route.o
lib-$(CONFIG_SLATTACH) += slattach.o
diff --git a/networking/portmap.c b/networking/portmap.c
new file mode 100644
index 0000000..6dc2f5e
--- /dev/null
+++ b/networking/portmap.c
@@ -0,0 +1,213 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mini portmap implementation for busybox
+ *
+ * Copyright (C) 2011 by Lukas Huba <huba.lukas at centrum.cz>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+
+/* commandline parameters */
+int flags = 0;
+#define FLAGS_ARG "h:pr"
+#define FLAG_HOST (1 << 0)
+#define FLAG_SPORT (2 << 0)
+#define FLAG_SREMOTE (4 << 0)
+
+/* portmap items */
+int pn = 0;
+struct pmaplist *pl = NULL;
+
+/* default count of network interfaces (later it updates itself)
+ * it's for higher efficiency (re|m)alloc */
+int ifs = 5;
+
+static bool_t _pmapproc_set(struct pmap *pr) {
+ struct pmaplist *p, *pp = NULL, **n;
+ if (pn >= CONFIG_PORTMAP_ITEMS_MAX) {
+ bb_error_msg("All available resources are used! Count of registered "\
+ "RPC services is limited to %i.", CONFIG_PORTMAP_ITEMS_MAX);
+ return FALSE;
+ }
+ for(p=pl; p!=NULL; p=p->pml_next) {
+ if (p->pml_map.pm_prog == pr->pm_prog &&
+ p->pml_map.pm_vers == pr->pm_vers &&
+ p->pml_map.pm_prot == pr->pm_prot) {
+ return FALSE;
+ }
+ pp=p;
+ }
+ if (pp == NULL) {
+ n = &pl;
+ } else {
+ n = &(pp->pml_next);
+ }
+ (*n) = (struct pmaplist *)xmalloc(sizeof(struct pmaplist));
+ (*n)->pml_map = *pr;
+ (*n)->pml_next = NULL;
+ pn++;
+ return TRUE;
+}
+
+static bool_t _pmapproc_unset(struct pmap *pr) {
+ bool_t res = FALSE;
+ struct pmaplist *p, *pp = NULL;
+ for(p=pl; p!=NULL; p=p->pml_next) {
+ if (p->pml_map.pm_prog == pr->pm_prog &&
+ p->pml_map.pm_vers == pr->pm_vers) {
+ res = TRUE;
+ if (p->pml_next == NULL) {
+ if (pp == NULL) {
+ pl = NULL;
+ } else {
+ pp->pml_next = NULL;
+ }
+ } else {
+ if (pp == NULL) {
+ pl = p->pml_next;
+ } else {
+ pp->pml_next = p->pml_next;
+ }
+ }
+ free(p);
+ pn--;
+ } else {
+ pp=p;
+ }
+ }
+ return res;
+}
+
+static unsigned int _pmapproc_getport(struct pmap *pr) {
+ struct pmaplist *p;
+ for(p=pl; p!=NULL; p=p->pml_next) {
+ if (p->pml_map.pm_prog == pr->pm_prog &&
+ p->pml_map.pm_vers == pr->pm_vers) {
+ return p->pml_map.pm_port;
+ }
+ }
+ return 0;
+}
+
+static bool_t check_security(SVCXPRT *xprt) {
+ if (!(flags & FLAG_SPORT)) {
+ /* secure mode
+ * SET and UNSET procs can be exec only from port <= 1024 */
+ if (htons(svc_getcaller(xprt)->sin_port) > 1024) return FALSE;
+ }
+ if (!(flags & FLAG_SREMOTE)) {
+ /* secure mode
+ * SET and UNSET procs can be exec only from local machine */
+ int s, cnt = 0;
+ struct ifconf ifc;
+ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ ifc.ifc_req = NULL;
+ for(cnt=0; !cnt||ifc.ifc_len/sizeof(struct ifreq)==cnt; cnt+=ifs) {
+ ifc.ifc_len = (cnt+ifs)*sizeof(struct ifreq);
+ ifc.ifc_req = (struct ifreq *)xrealloc(ifc.ifc_req, ifc.ifc_len);
+ if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
+ bb_error_msg("ioctl(SIOCGIFCONF) error");
+ free(ifc.ifc_req);
+ return FALSE;
+ }
+ }
+ ifs = ifc.ifc_len/sizeof(struct ifreq)+1;
+ for(int i=0; i<cnt; i++) {
+ if (((struct sockaddr_in *)&ifc.ifc_req[i].ifr_addr)
+ ->sin_addr.s_addr == svc_getcaller(xprt)->sin_addr.s_addr) {
+ free(ifc.ifc_req);
+ return TRUE;
+ }
+ }
+ free(ifc.ifc_req);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void _pmapproc(struct svc_req *rqstp, SVCXPRT *xprt) {
+ unsigned int res;
+ struct pmap pmap;
+
+ if (rqstp->rq_proc == PMAPPROC_SET || rqstp->rq_proc == PMAPPROC_UNSET) {
+ if (check_security(xprt) == FALSE) {
+ svcerr_weakauth(xprt);
+ return;
+ }
+ }
+
+ if (rqstp->rq_proc > PMAPPROC_NULL && rqstp->rq_proc < PMAPPROC_DUMP)
+ if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (caddr_t)&pmap)) return;
+
+ switch(rqstp->rq_proc) {
+ case PMAPPROC_NULL:
+ svc_sendreply(xprt, (xdrproc_t)xdr_void, (caddr_t)NULL);
+ break;
+ case PMAPPROC_SET:
+ res = (unsigned int)_pmapproc_set(&pmap);
+ svc_sendreply(xprt, (xdrproc_t)xdr_bool, (caddr_t)&res);
+ break;
+ case PMAPPROC_UNSET:
+ res = (unsigned int)_pmapproc_unset(&pmap);
+ svc_sendreply(xprt, (xdrproc_t)xdr_bool, (caddr_t)&res);
+ break;
+ case PMAPPROC_GETPORT:
+ res = _pmapproc_getport(&pmap);
+ svc_sendreply(xprt, (xdrproc_t)xdr_u_int, (caddr_t)&res);
+ break;
+ case PMAPPROC_DUMP:
+ svc_sendreply(xprt, (xdrproc_t)xdr_pmaplist, (caddr_t)&pl);
+ break;
+ default:
+ svcerr_noproc(xprt);
+ }
+}
+
+int portmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int portmap_main(int argc, char **argv)
+{
+ char *host = (char *)"0.0.0.0";
+ if (argc >= 2) {
+ flags = getopt32(argv, FLAGS_ARG, &host);
+ }
+
+ bb_daemonize(DAEMON_CHDIR_ROOT);
+
+ openlog(applet_name, LOG_PID | LOG_ERR, LOG_DAEMON);
+ logmode |= LOGMODE_SYSLOG;
+
+ {
+ int sock;
+ SVCXPRT *xprt;
+ struct pmap pm = {PMAPPROG, PMAPVERS, IPPROTO_UDP, PMAPPORT};
+
+ /* udp listening */
+ sock = create_and_bind_dgram_or_die(host, PMAPPORT);
+ if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
+ bb_error_msg_and_die("Cannot start portmap!");
+ }
+ _pmapproc_set(&pm);
+ if (svc_register(xprt, PMAPPROG, PMAPVERS, _pmapproc, 0)) pn++;
+
+ /* tcp listening */
+ sock = create_and_bind_stream_or_die(host, PMAPPORT);
+ if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
+ == (SVCXPRT *)NULL) {
+ bb_error_msg_and_die("Cannot start portmap!");
+ }
+ pm.pm_prot = IPPROTO_TCP;
+ _pmapproc_set(&pm);
+ if (svc_register(xprt, PMAPPROG, PMAPVERS, _pmapproc, 0)) pn++;
+ }
+
+ svc_run();
+
+ return EXIT_SUCCESS;
+}
--
1.7.4.rc1
More information about the busybox
mailing list