Option name overhaul; introduced Masquerading options and logic
authorRick van Rein <rick@openfortress.nl>
Wed, 20 Sep 2017 23:07:06 +0000 (01:07 +0200)
committerRick van Rein <rick@openfortress.nl>
Wed, 20 Sep 2017 23:11:05 +0000 (01:11 +0200)
[sorry, but letters for port numbers trumped arbitrary daemon etc flagging]

6bed4peer.c
6bed4peer.man
6bed4router.c
6bed4router.man

index c049fc4..47ff2d6 100644 (file)
@@ -63,9 +63,9 @@ typedef enum {
 
 /*
  * The HAVE_SETUP_TUNNEL variable is used to determine whether absense of
- * the -t option leads to an error, or to an attempt to setup the tunnel.
+ * the -d option leads to an error, or to an attempt to setup the tunnel.
  * The setup_tunnel() function used for that is defined per platform, such
- * as for LINUX.  Remember to maintain the manpage's optionality for -t.
+ * as for LINUX.  Remember to maintain the manpage's optionality for -d.
  */
 #undef HAVE_SETUP_TUNNEL
 
@@ -1521,11 +1521,11 @@ char *short_opt = "s:t:dl:p:r:k:feh";
 
 struct option long_opt [] = {
        { "v4server", 1, NULL, 's' },
-       { "tundev", 1, NULL, 't' },
-       { "default-route", 0, NULL, 'd' },
+       { "tundev", 1, NULL, 'd' },
+       { "default-route", 0, NULL, 'r' },
        { "listen", 1, NULL, 'l' },
        { "port", 1, NULL, 'p' },
-       { "radius-multicast", 1, NULL, 'r' },
+       { "ttl", 1, NULL, 't' },
        { "foreground", 0, NULL, 'f' },
        { "fork-not", 0, NULL, 'f' },
        { "keepalive", 1, NULL, 'k' },
@@ -1575,10 +1575,10 @@ int process_args (int argc, char *argv []) {
                                break;
                        }
                        break;
-               case 't':
+               case 'd':
                        if (v6sox != -1) {
                                ok = 0;
-                               fprintf (stderr, "%s: Multiple -t arguments are not permitted\n", program);
+                               fprintf (stderr, "%s: Multiple -d arguments are not permitted\n", program);
                                break;
                        }
                        v6sox = open (optarg, O_RDWR);
@@ -1588,7 +1588,7 @@ int process_args (int argc, char *argv []) {
                                break;
                        }
                        break;
-               case 'd':
+               case 'r':
                        if (default_route) {
                                fprintf (stderr, "%s: You can only request default route setup once\n", program);
                                exit (1);
@@ -1627,9 +1627,9 @@ int process_args (int argc, char *argv []) {
                        }
                        log_to_stderr = true;
                        break;
-               case 'r':
+               case 't':
                        if (v4ttl_mcast != -1) {
-                               fprintf (stderr, "%s: You can set the radius for multicast once\n", program);
+                               fprintf (stderr, "%s: You can set the ttl for multicast once\n", program);
                                exit (1);
                        }
                        char *zero;
@@ -1676,9 +1676,9 @@ int process_args (int argc, char *argv []) {
        }
        if (help) {
 #ifdef HAVE_SETUP_TUNNEL
-               fprintf (stderr, "Usage: %s [-d] [-t /dev/tunX]\n       %s -h\n", program, program);
+               fprintf (stderr, "Usage: %s [-r] [-d /dev/tunX]\n       %s -h\n", program, program);
 #else
-               fprintf (stderr, "Usage: %s [-d] -t /dev/tunX\n       %s -h\n", program, program);
+               fprintf (stderr, "Usage: %s [-r] -d /dev/tunX\n       %s -h\n", program, program);
 #endif
                return 0;
        }
@@ -1693,7 +1693,7 @@ int process_args (int argc, char *argv []) {
 #ifdef HAVE_SETUP_TUNNEL
        if (v6sox == -1) {
                if (geteuid () != 0) {
-                       fprintf (stderr, "%s: You should be root, or use -t to specify an accessible tunnel device\n", program);
+                       fprintf (stderr, "%s: You should be root, or use -d to specify an accessible tunnel device\n", program);
                        return false;
                } else {
                        return setup_tunnel ();
@@ -1701,7 +1701,7 @@ int process_args (int argc, char *argv []) {
        }
 #else /* ! HAVE_SETUP_TUNNEL */
        if (v6sox == -1) {
-               fprintf (stderr, "%s: You must specify a tunnel device with -t that is accessible to you\n", program);
+               fprintf (stderr, "%s: You must specify a tunnel device with -d that is accessible to you\n", program);
                return 0;
        }
 #endif /* HAVE_SETUP_TUNNEL */
index 5f3139c..d58807a 100644 (file)
@@ -15,7 +15,7 @@
 6bed4client \- client-side daemon for instant-on IPv6 service
 .SH SYNOPSYS
 .B 6bed4client
-[\fB\-t\fR \fI/dev/tunX\fR] [\fB\-d\fR] [\fB\-f\fR] [\fB\-l\fR \fIv4addr\fR] [\fB\-p\fR \fIport\fR] [\fB\-r\fR \fIhops\fR] [\fB-s \fIv4addr\fR]
+[\fB\-d\fR \fI/dev/tunX\fR] [\fB\-r\fR] [\fB\-f\fR] [\fB\-l\fR \fIv4addr\fR] [\fB\-p\fR \fIport\fR] [\fB\-t\fR \fIhops\fR] [\fB-s \fIv4addr\fR]
 .PP
 .B 6bed4client
 [\fB\-h\fR]
@@ -88,7 +88,7 @@ can be used to support reception of incoming 6bed4 traffic on the
 forwarded port.
 .SH OPTIONS
 .TP
-\fB\-t\fR \fI/dev/tunX\fR
+\fB\-d\fR \fI/dev/tunX\fR
 .TP
 \fB\-\-tundev\fR \fI/dev/tunX\fR
 Instead of creating a tunnel for the duration that \fB6bed4server\fR runs,
@@ -97,7 +97,7 @@ the proper IPv6 prefix.  This option makes it possible for
 non-root users to run \fB6bed4server\fR.  All that is required is acccess to
 the tunnel device by the user that runs \fB6bed4server\fR.  Optional on Linux.
 .TP
-\fB\-d\fR
+\fB\-r\fR
 .TP
 \fB\-\-default\-route\fR
 Create a default route through the 6bed4 interface.  This means that the
@@ -158,9 +158,9 @@ it is only needed to get outside NAT and firewalls, but not to reach
 the central infrastructure.  The default is \fB\-\-keepalive 30,3\fR
 and may be automatically determined in future versions.
 .TP
-\fB\-r\fR \fIhops\fR
+\fB\-t\fR \fIhops\fR
 .TP
-\fB\-\-radius\fR \fIhops\fR
+\fB\-\-ttl\fR \fIhops\fR
 Set the multicast radius to the given number of hops, the default being 1.
 This number is used as the TTL on multicast messages, thereby determining
 whether routers are permitted to forward these packets.  The value 0
@@ -193,7 +193,7 @@ only fail with that other party.
 Whenever possible, 6bed4 connections are connected directly over the locally
 attached network.  This optimises the traffic by not passing it through an
 external router.  But it also implies trust in the peers on a local network;
-for this reason, it is possible to set \fB\-\-radius 0\fR and thereby
+for this reason, it is possible to set \fB\-\-ttl 0\fR and thereby
 disable the attempts to find peers locally.
 .PP
 The mechanism used to find peers locally is through multicast.  It is
@@ -203,16 +203,16 @@ response to a multicast query through Neighbor Solicitation is a unicast
 response through Neighbor Advertisement, in both cases encapsulated in
 UDP and IPv4.
 .PP
-The default setting \fB\-\-radius 1\fR works only on locally attached
+The default setting \fB\-\-ttl 1\fR works only on locally attached
 subnets.  This is generally safe, as this network is normally unfiltered.
 In places where filtering is applied within a subnet, the administrative
 staff should be prepared to stop confusion of network nodes; in case of
-6bed4, this means setting \fB\-\-radius 0\fR to avoid relying on an open
+6bed4, this means setting \fB\-\-ttl 0\fR to avoid relying on an open
 locally attached subnet.  This setting implies that the daemon does not
 listen for incoming queries over multicast.  The standards specify that
 multicast support is optional, so this does not break any standards.
 .PP
-Settings of \fB\-\-radius 2\fR and beyond are more dangerous; it could
+Settings of \fB\-\-ttl 2\fR and beyond are more dangerous; it could
 lead to asymmetric routes if not properly configured on a network.  The
 problem of asymmetric routes being that one half might go through a
 hole in NAT, which closes when traffic does not flow through bidirectionally.
index f392300..b2fa893 100644 (file)
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip6.h>
+#include <netinet/tcp.h>
 #include <netinet/udp.h>
 #include <netinet/icmp6.h>
 #include <arpa/inet.h>
 
+#ifndef BE_SO_LAME_TO_SUPPRESS_SCTP
+#include <linux/sctp.h>
+#endif
+
 #include <linux/if.h>
 #include <linux/if_tun.h>
 #include <linux/if_ether.h>
@@ -64,9 +69,9 @@
 
 /*
  * The HAVE_SETUP_TUNNEL variable is used to determine whether absense of
- * the -t option leads to an error, or to an attempt to setup the tunnel.
+ * the -d option leads to an error, or to an attempt to setup the tunnel.
  * The setup_tunnel() function used for that is defined per platform, such
- * as for LINUX.  Remember to maintain the manpage's optionality for -t.
+ * as for LINUX.  Remember to maintain the manpage's optionality for -d.
  */
 #undef HAVE_SETUP_TUNNEL
 
@@ -105,6 +110,11 @@ struct {
                struct {
                        struct ip6_hdr v6hdr;
                        struct icmp6_hdr v6icmphdr;
+#ifndef BE_SO_LAME_TO_SUPPRESS_SCTP
+                       struct sctphdr v6sctphdr;
+#endif
+                       struct tcphdr  v6tcphdr ;
+                       struct udphdr  v6udphdr ;
                } ndata;
        } udata;
 } v4data6;
@@ -125,6 +135,15 @@ struct {
 #define v4v6icmpcode   ( v4data6.udata.ndata.v6icmphdr.icmp6_code)
 #define v4v6icmpcksum  ( v4data6.udata.ndata.v6icmphdr.icmp6_cksum)
 
+#define v4v6sctpsrcport        ( v4data6.udata.ndata.v6sctphdr.source)
+#define v4v6sctpdstport        ( v4data6.udata.ndata.v6sctphdr.dest)
+
+#define v4v6tcpsrcport ( v4data6.udata.ndata.v6tcphdr.source)
+#define v4v6tcpdstport ( v4data6.udata.ndata.v6tcphdr.dest)
+
+#define v4v6udpsrcport ( v4data6.udata.ndata.v6udphdr.source)
+#define v4v6udpdstport ( v4data6.udata.ndata.v6udphdr.dest)
+
 #define v4ngbsoltarget (&v4data6.udata.ndata.v6icmphdr.icmp6_data8 [4])
 
 
@@ -166,6 +185,26 @@ uint8_t allrouters_linklocal_address [] = {
 };
 
 
+
+#ifndef MAXNUM_MASQHOST
+#define MAXNUM_MASQHOST 4
+#endif
+
+uint16_t num_masqhost = 0;
+uint8_t masqhost [MAXNUM_MASQHOST][16];
+
+// ports for 's', 't', 'u' -- SCTP, TCP, UDP have increasing numbers
+
+#ifndef MAXNUM_PORTPAIRS
+#define MAXNUM_PORTPAIRS 10
+#endif
+
+// masqportpairs holds triples <lowport,highport,masqhostnr>
+uint16_t num_masqportpairs [3] = { 0, 0, 0 };
+uint16_t masqportpairs [3][3*MAXNUM_PORTPAIRS];
+
+
+
 /*
  *
  * Driver routines
@@ -365,6 +404,7 @@ static inline bool is_local_override (struct in6_addr *ip6) {
 #define is_local_override(_) false
 #endif
 
+
 /*
  * Test if the provided IPv6 address matches the prefix used for 6bed4.
  *TODO: This is oversimplistic, it only cares for the Hetzner /64
@@ -416,6 +456,19 @@ bool validate_originator (struct in6_addr *ip6) {
 }
 
 
+
+/*
+ * Given a protocol and a port number, locate the masqhost that would match.
+ * The protocol is 0 for SCTP, 1 for TCP, 2 for UDP (alphabetic sequence).
+ * Returns a pointer to the address or NULL if not found.
+ */
+uint8_t *protoport2masqhost (uint8_t proto, uint16_t port) {
+       //NOTUSED// TODO:IMPLEMENT
+       return NULL;
+}
+
+
+
 /*
  * Major packet processing functions
  */
@@ -535,6 +588,49 @@ void handle_4to6_nd (ssize_t v4ngbcmdlen) {
  * checksum calculations.
  */
 void handle_4to6_plain_unicast (ssize_t v4datalen) {
+       //
+       // Masquerade the 6bed4router when addressing a configured port (range)
+       // but only when the destination address is the client's 6bed4router
+       if ((v4dst6->s6_addr [15] == 0x00)
+                       && (v4dst6->s6_addr [14] & 0x3f == 0x00)
+                       && (memcmp (v4dst6, v4src6, 14) == 0)) {
+               uint16_t *portpairs = NULL;
+               uint16_t numpairs = 0;
+               uint16_t port;
+               switch (v4v6nexthdr) {
+#ifndef BE_SO_LAME_TO_SUPPRESS_SCTP
+               case IPPROTO_SCTP:
+                       portpairs = masqportpairs [0];  // 's'
+                       numpairs  = num_masqportpairs [0];
+                       port = ntohs (v4v6srcport);
+                       break;
+#endif
+               case IPPROTO_TCP:
+                       portpairs = masqportpairs [1];  // 't'
+                       numpairs  = num_masqportpairs [1];
+                       port = v4v6tcpsrcport;
+                       break;
+               case IPPROTO_UDP:
+                       portpairs = masqportpairs [2];  // 'u'
+                       numpairs  = num_masqportpairs [2];
+                       port = v4v6udpsrcport;
+                       break;
+               default:
+                       break;
+               }
+               while (numpairs-- > 0) {
+                       if ((port >= portpairs [0]) && (port <= portpairs [1])) {
+                               //
+                               // Replace masqueraded address by 6bed4router's
+                               memcpy (v4dst6, masqhost [portpairs [2]], 16);
+                               //
+                               // Stop further attempts to masquerade
+                       }
+                       portpairs += 2;
+               }
+       }
+       //
+       // Relay the message to an IPv6 recipient on the native IPv6 side
 printf ("Writing IPv6, result = %zd\n",
        write (v6sox, &v4data6, sizeof (struct tun_pi) + v4datalen));
 }
@@ -635,6 +731,7 @@ void handle_4to6 (void) {
  * port, then package it as a tunnel message and forward it to IPv4:port.
  */
 void handle_6to4 (void) {
+       uint16_t mqh;
        //
        // Receive the IPv6 package and ensure a consistent size
        size_t rawlen = read (v6sox, &v6data6, sizeof (v6data6));
@@ -662,6 +759,18 @@ printf ("Received multicast IPv6 data, flags=0x%04x, proto=0x%04x\n", v6tuncmd.f
        }
 printf ("Received plain unicast IPv6 data, flags=0x%04x, proto=0x%04x\n", v6tuncmd.flags, v6tuncmd.proto);
        //
+       // Replace masqueraded addresses configured with -m and its default ::1
+       //TODO// Better use the port number to find the find the masqhost
+       for (mqh=0; mqh<num_masqhost; mqh++) {
+               if (memcmp (v6src6, masqhost [mqh], 16) == 0) {
+printf ("Masqueraded sender address in 6to4 set to the client's 6bed4router address\n");
+                       memcpy (v6src6, v6dst6, 15);
+                       v6src6->s6_addr [15] &= 0xc0;
+                       v6src6->s6_addr [16]  = 0x00;
+                       break;
+               }
+       }
+       //
        // Ensure that the incoming IPv6 address is properly formatted
        // Note that this avoids access to ::1/128, fe80::/10, fec0::/10
 #ifndef TODO_PERMIT_BOUNCE_FOR_32BIT_PREFIX
@@ -712,13 +821,19 @@ fflush (stdout);
 
 /* Option descriptive data structures */
 
-char *short_opt = "l:L:t:h";
+char *short_opt = "l:L:d:ht:u:s:m:";
 
 struct option long_opt [] = {
        { "v4listen", 1, NULL, 'l' },
        { "v6prefix", 1, NULL, 'L' },
-       { "tundev", 1, NULL, 't' },
+       { "tundev", 1, NULL, 'd' },
        { "help", 0, NULL, 'h' },
+       { "tcp", 1, NULL, 't' },
+       { "udp", 1, NULL, 'u' },
+       { "sctp", 1, NULL, 's' },
+       { "masqhost", 1, NULL, 'm' },
+       // { "fallback4", 1 NULL, 'f' },
+       // { "fallback6", 1, NULL, 'F' },
        { NULL, 0, NULL, 0 }    /* Array termination */
 };
 
@@ -729,8 +844,9 @@ int process_args (int argc, char *argv []) {
        int ok = 1;
        int help = (argc == 1);
        int done = 0;
+       int opt;
        while (!done) {
-               switch (getopt_long (argc, argv, short_opt, long_opt, NULL)) {
+               switch (opt = getopt_long (argc, argv, short_opt, long_opt, NULL)) {
                case -1:
                        done = 1;
                        if (optind != argc) {
@@ -790,10 +906,10 @@ int process_args (int argc, char *argv []) {
                                break;
                        }
                        break;
-               case 't':
+               case 'd':
                        if (v6sox != -1) {
                                ok = 0;
-                               fprintf (stderr, "%s: Multiple -t arguments are not permitted\n", program);
+                               fprintf (stderr, "%s: Multiple -d arguments are not permitted\n", program);
                                break;
                        }
                        v6sox = open (optarg, O_RDWR);
@@ -803,9 +919,77 @@ int process_args (int argc, char *argv []) {
                                break;
                        }
                        break;
+               case 's':
+               case 't':
+               case 'u':
+                       // Masqueraded port (range) for SCTP, TCP, UDP
+                       //TODO// Should we support ICMPv6 as well? [honeypots]
+                       if (num_masqhost == 0) {
+                               inet_pton (AF_INET6, "::1", masqhost [0]);
+                               num_masqhost = 1;
+                       }
+                       // Temporary variables in local scope
+                       {
+                               unsigned long fromport, toport;
+                               uint16_t *portpairs;
+                               errno = 0;
+                               if (*optarg != ':') {
+                                       fromport = strtoul (optarg, &optarg, 10);
+                               } else {
+                                       fromport = 1;
+                               }
+                               if (*optarg != ':') {
+                                       toport = fromport;
+                               } else if (*++optarg) {
+                                       toport = strtoul (optarg, &optarg, 10);
+                               } else {
+                                       toport = 65535;
+                               }
+                               if (errno || *optarg) {
+                                       fprintf (stderr, "%s: Failed to parse port or port:port\n", program);
+                                       ok = 0;
+                                       break;
+                               }
+                               if ((fromport < 1) || (fromport > toport) || (toport > 65535)) {
+                                       fprintf (stderr, "%s: Invalid port or port range\n", program);
+                                       ok = 0;
+                                       break;
+                               }
+                               if (++num_masqportpairs [opt-'s'] >= MAXNUM_PORTPAIRS) {
+                                       fprintf (stderr, "%s: You cannot define so many ports / port pairs\n", program);
+                                       ok = 0;
+                                       break;
+                               }
+                               portpairs = &masqportpairs [opt-'s'][3*(num_masqportpairs [opt-'s']-1)];
+                               portpairs [0] = fromport;
+                               portpairs [1] = toport;
+                               portpairs [2] = num_masqhost-1;
+                       }
+                       break;
+               case 'm':
+                       // Masqueraded host for TCP, UDP, SCTP (default is ::1)
+                       if (++num_masqhost >= MAXNUM_MASQHOST) {
+                               fprintf (stderr, "%s: No more than %d masquering hosts can be specified\n", program, MAXNUM_MASQHOST);
+                               ok = 0;
+                               break;
+                       }
+                       if (inet_pton (AF_INET6, optarg, masqhost [num_masqhost]) != 1) {
+                               fprintf (stderr, "%s: Unsupported masquerading host \"%s\"\n", program, optarg);
+                               ok = 0;
+                               break;
+                       }
+                       num_masqhost++;
+                       ok = 0; //TODO:IMPLEMENT//
+                       help = 1;
+                       break;
+               // case 'f':
+               // case 'F':
+               //      // Fallback addresses for IPv4, IPv6
+               //      ok = 0; //TODO:IMPLEMENT//
+               //      help = 1;
+               //      break;
                default:
                        ok = 0;
-                       help = 1;
                        /* continue into 'h' to produce usage information */
                case 'h':
                        help = 1;
@@ -817,9 +1001,11 @@ int process_args (int argc, char *argv []) {
        }
        if (help) {
 #ifdef HAVE_SETUP_TUNNEL
-               fprintf (stderr, "Usage: %s [-t /dev/tunX] -l <v4server> -L <v6prefix>/64\n       %s -h\n", program, program);
+               fprintf (stderr, "Usage: %s [-d /dev/tunX] -l <v4server> -L <v6prefix>/64\n       %s -h\n", program, program);
+               fprintf (stderr, "\tUse -s|-t|-u to masquerade a port (range) to last -m host or ::1\n");
 #else
-               fprintf (stderr, "Usage: %s -t /dev/tunX -l <v4server> -L <v6prefix>/64\n       %s -h\n", program, program);
+               fprintf (stderr, "Usage: %s -d /dev/tunX -l <v4server> -L <v6prefix>/64\n       %s -h\n", program, program);
+               fprintf (stderr, "\tUse -s|-t|-u to masquerade a port (range) to last -m host of ::1\n");
 #endif
                return ok;
        }
@@ -837,14 +1023,14 @@ int process_args (int argc, char *argv []) {
 #ifdef HAVE_SETUP_TUNNEL
        if (v6sox == -1) {
                if (geteuid () != 0) {
-                       fprintf (stderr, "%s: You should be root, or use -t to specify an accessible tunnel device\n", program);
+                       fprintf (stderr, "%s: You should be root, or use -d to specify an accessible tunnel device\n", program);
                        return 0;
                }
                ok = setup_tunnel ();
        }
 #else /* ! HAVE_SETUP_TUNNEL */
        if (v6sox == -1) {
-               fprintf (stderr, "%s: You must specify a tunnel device with -t that is accessible to you\n", program);
+               fprintf (stderr, "%s: You must specify a tunnel device with -d that is accessible to you\n", program);
                return 0;
        }
 #endif /* HAVE_SETUP_TUNNEL */
index 1cccc59..5e18f28 100644 (file)
 6bed4router \- server-side daemon for 6bed4 service
 .SH SYNOPSYS
 .B 6bed4router
-[\fB\-t\fR \fI/dev/tunX\fR] \fB\-l\fR \fIv4addr\fR \fB\-L\fR \fIv6prefix/64\fR
+[\fB\-d\fR \fI/dev/tunX\fR] \fB\-l\fR \fIv4addr\fR \fB\-L\fR \fIv6prefix/64\fR [\fB\-m\fR/\fBs\fR/\fBt\fR/\fBu\fR \fI...\fR]
 .PP
 .B 6bed4router
 [\fB\-h\fR]
 .SH DESCRIPTION
 .PP
 Through a \fB6bed4router\fR daemon, it is possible to make a small range of IPv6
-addresses available to IPv4-only users.  This means that even an IPv4-only
+addresses available to a potentially large number of IPv4-only users.  This means that even an IPv4-only
 network can host IPv6-only applications, as long as they can fall back on
 a tunnel based on this profile.
 .PP
-These tunnels are primarily intended for embedded devices, to assist them
-in instant changeover from being IPv4-only to being IPv6-only.  Given the
+Use the \fB6bed4router\fR on nodes that support \fB6bed4peer\fR clients
+anywhere; instead, use the \fB6bed4node\fR on nodes that want to provide
+native IPv6 on a local network.
+.PP
+These tunnels are intended for mobile and embedded devices, to assist them
+in instant changeover from being IPv4-only to eventually being IPv6-only.
+Given the
 restricted resources in embedded applications, this is likely to improve
 the speed of transitioning to IPv6.  To avoid cluttered access, these
 tunnels should be reserved for resource-hampered devices.  For routers,
@@ -71,7 +76,7 @@ but not without performing the SECURITY CHECKS desribed below
 on what is tossed at it.
 .SH OPTIONS
 .TP
-\fB\-t\fR \fI/dev/tunX\fR
+\fB\-d\fR \fI/dev/tunX\fR
 .TP
 \fB\-\-tundev\fR \fI/dev/tunX\fR
 Instead of creating a tunnel for the duration that \fB6bed4router\fR runs,
@@ -94,11 +99,40 @@ forward incoming IPv6 messages to IPv4-based UDP tunnel endpoints.
 See ADDRESS FORMAT below for an explanation of the lower half of
 the IPv6 addresses.  Required.
 .IP
-If no \fB\-t\fR option is given, a tunnel will be created for the time that
+If no \fB\-d\fR option is given, a tunnel will be created for the time that
 \fB6bed4router\fR is running, and the \fIv6prefix/64\fR is used as a router address
 on that interface.  Routing table entries will not be setup by \fB6bed4router\fR,
 nor will the general ablity to forward IPv6 traffic.
 .TP
+\fB\-m\fR \fIv6addr\fR
+.TP
+\fB\-\-masqhost\fR \fIv6addr\fR
+Use the given IPv6 address as the target for masqueraded operation.  This
+means that any ports setup with \fB\-\-sctp\fR, \fB\-\-tcp\fR or \fB\-\-udp\fR
+are forwarded
+to this address when addressed on the client's idea of the 6bed4 router
+address.  Note that the router only uses a few ICMPv6 messages, so the use
+of these additional ports can benefit various applications, ranging from
+authentication services to honeypots.
+.TP
+\fB\-s\fR \fIport\fR[\fB:\fIport\fR]
+.TP
+\fB\-t\fR \fIport\fR[\fB:\fIport\fR]
+.TP
+\fB\-u\fR \fIport\fR[\fB:\fIport\fR]
+.TP
+\fB\-sctp\fR \fIport\fR[\fB:\fIport\fR]
+.TP
+\fB\-tcp\fR \fIport\fR[\fB:\fIport\fR]
+.TP
+\fB\-udp\fR \fIport\fR[\fB:\fIport\fR]
+Apply the masquerading port or port range for SCTP, TCP or UDP to the
+masquerading host set by the last preceding \fB\-\-masqhost\fR option,
+or use \fB::1\fR
+if none was set yet.  Ports that have been previously bound will not make it,
+so it is possible to first relay a port with \fB\-t 22\fR to a service and
+then pass the rest to a honeypot with \fB\-t 1:65535\fR.
+.TP
 \fB\-h\fR
 .TP
 \fB\-\-help\fR