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
<[email protected]>

Signed-off-by: Lukas Huba <[email protected]>
---
 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 <[email protected]>
+ *
+ * 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
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to