aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--conf.c112
-rw-r--r--passt.128
2 files changed, 127 insertions, 13 deletions
diff --git a/conf.c b/conf.c
index cff71ff..14356b7 100644
--- a/conf.c
+++ b/conf.c
@@ -124,12 +124,12 @@ enum conf_port_type {
static int conf_ports(struct ctx *c, char optname, const char *optarg,
enum conf_port_type *set)
{
- int start_src = -1, end_src = -1, start_dst = -1, end_dst = -1;
+ int start_src, end_src, start_dst, end_dst, exclude_only = 1, i, port;
+ char addr_buf[sizeof(struct in6_addr)] = { 0 }, *addr = addr_buf;
void (*remap)(in_port_t port, in_port_t delta);
- char addr_buf[sizeof(struct in6_addr)] = { 0 };
+ uint8_t *map, exclude[USHRT_MAX / 8] = { 0 };
+ char buf[BUFSIZ], *sep, *spec, *p;
sa_family_t af = AF_UNSPEC;
- char buf[BUFSIZ], *sep, *p, *addr = addr_buf;
- uint8_t *map;
if (optname == 't') {
map = c->tcp.port_to_tap;
@@ -186,9 +186,9 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
strncpy(buf, optarg, sizeof(buf) - 1);
- if ((p = strchr(buf, '/'))) {
- *p = 0;
- p++;
+ if ((spec = strchr(buf, '/'))) {
+ *spec = 0;
+ spec++;
if (optname != 't' && optname != 'u')
goto bad;
@@ -200,16 +200,97 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
else
goto bad;
} else {
- p = buf;
+ spec = buf;
addr = NULL;
}
- if (strspn(p, "0123456789-,:") != strlen(p))
+ if (strspn(spec, "0123456789-,:~") != strlen(spec))
goto bad;
+ /* Mark all exclusions first, they might be given after base ranges */
+ p = spec;
+ start_src = end_src = -1;
do {
- int i, port;
+ while (*p != '~' && start_src == -1) {
+ exclude_only = 0;
+
+ if (!(p = strchr(p, ',')))
+ break;
+
+ p++;
+ }
+ if (!p || !*p)
+ break;
+
+ if (*p == '~')
+ p++;
+
+ errno = 0;
+ port = strtol(p, &sep, 10);
+ if (sep == p)
+ break;
+
+ if (port < 0 || port > USHRT_MAX || errno)
+ goto bad;
+
+ switch (*sep) {
+ case '-':
+ if (start_src == -1) /* ~22-... */
+ start_src = port;
+ break;
+ case ',':
+ case 0:
+ if (start_src == -1) /* ~80 */
+ start_src = end_src = port;
+ else if (end_src == -1) /* ~22-25 */
+ end_src = port;
+ else
+ goto bad;
+
+ if (start_src > end_src) /* ~80-22 */
+ goto bad;
+
+ for (i = start_src; i <= end_src; i++) {
+ if (bitmap_isset(exclude, i))
+ goto overlap;
+
+ bitmap_set(exclude, i);
+ }
+ break;
+ default:
+ goto bad;
+ }
+ p = sep + 1;
+ } while (*sep);
+
+ if (exclude_only) {
+ for (i = 0; i < PORT_EPHEMERAL_MIN; i++) {
+ if (bitmap_isset(exclude, i))
+ continue;
+
+ bitmap_set(map, i);
+
+ if (optname == 't')
+ tcp_sock_init(c, 0, af, addr, i);
+ else if (optname == 'u')
+ udp_sock_init(c, 0, af, addr, i);
+ }
+
+ return 0;
+ }
+
+ /* Now process base ranges, skipping exclusions */
+ start_src = end_src = start_dst = end_dst = -1;
+ p = spec;
+ do {
+ while (*p == '~') {
+ if (!(p = strchr(p, ',')))
+ break;
+ p++;
+ }
+ if (!p || !*p)
+ break;
errno = 0;
port = strtol(p, &sep, 10);
@@ -281,6 +362,9 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
if (bitmap_isset(map, i))
goto overlap;
+ if (bitmap_isset(exclude, i))
+ continue;
+
bitmap_set(map, i);
if (start_dst != -1) {
@@ -726,7 +810,9 @@ static void usage(const char *name)
info( " 'all': forward all unbound, non-ephemeral ports");
info( " a comma-separated list, optionally ranged with '-'");
info( " and optional target ports after ':', with optional");
- info( " address specification suffixed by '/'. Examples:");
+ info( " address specification suffixed by '/'. Ranges can be");
+ info( " reduced by excluding ports or ranges prefixed by '~'");
+ info( " Examples:");
info( " -t 22 Forward local port 22 to 22 on guest");
info( " -t 22:23 Forward local port 22 to 23 on guest");
info( " -t 22,25 Forward ports 22, 25 to ports 22, 25");
@@ -734,6 +820,8 @@ static void usage(const char *name)
info( " -t 22-80:32-90 Forward ports 22 to 80 to");
info( " corresponding port numbers plus 10");
info( " -t 192.0.2.1/5 Bind port 5 of 192.0.2.1 to guest");
+ info( " -t 5-25,~10-20 Forward ports 5 to 9, and 21 to 25");
+ info( " -t ~25 Forward all ports except for 25");
info( " default: none");
info( " -u, --udp-ports SPEC UDP port forwarding to guest");
info( " SPEC is as described for TCP above");
@@ -757,6 +845,8 @@ pasta_opts:
info( " -t 22-80:32-90 Forward ports 22 to 80 to");
info( " corresponding port numbers plus 10");
info( " -t 192.0.2.1/5 Bind port 5 of 192.0.2.1 to namespace");
+ info( " -t 5-25,~10-20 Forward ports 5 to 9, and 21 to 25");
+ info( " -t ~25 Forward all bound ports except for 25");
info( " default: auto");
info( " IPv6 bound ports are also forwarded for IPv4");
info( " -u, --udp-ports SPEC UDP port forwarding to namespace");
diff --git a/passt.1 b/passt.1
index c7c43be..4e06c0c 100644
--- a/passt.1
+++ b/passt.1
@@ -306,7 +306,10 @@ For low (< 1024) ports, see \fBNOTES\fR.
.BR ports
A comma-separated list of ports, optionally ranged with \fI-\fR, and,
optionally, with target ports after \fI:\fR, if they differ. Specific addresses
-can be bound as well, separated by \fI/\fR. Examples:
+can be bound as well, separated by \fI/\fR. Within given ranges, selected ports
+and ranges can be excluded by an additional specification prefixed by \fI~\fR.
+Specifying excluded ranges only implies that all other ports are forwarded.
+Examples:
.RS
.TP
-t 22
@@ -326,6 +329,15 @@ Forward local ports 22 to 80 to corresponding ports on the guest plus 10
.TP
-t 192.0.2.1/22
Forward local port 22, bound to 192.0.2.1, to port 22 on the guest
+.TP
+-t 2000-5000,~3000-3010
+Forward local ports 2000 to 5000, but not 3000 to 3010
+.TP
+-t 192.0.2.1/20-30,~25
+Forward local ports 20 to 24, and 26 to 30, bound to 192.0.2.1
+.TP
+-t ~20000-20010
+Forward all ports to the guest, except for the range from 20000 to 20010
.RE
Default is \fBnone\fR.
@@ -368,7 +380,10 @@ periodically derived (every second) from listening sockets reported by
.BR ports
A comma-separated list of ports, optionally ranged with \fI-\fR, and,
optionally, with target ports after \fI:\fR, if they differ. Specific addresses
-can be bound as well, separated by \fI/\fR. Examples:
+can be bound as well, separated by \fI/\fR. Within given ranges, selected ports
+and ranges can be excluded by an additional specification prefixed by \fI~\fR.
+Specifying excluded ranges only implies that all other ports are forwarded.
+Examples:
.RS
.TP
-t 22
@@ -389,6 +404,15 @@ namespace
.TP
-t 192.0.2.1/22
Forward local port 22, bound to 192.0.2.1, to port 22 in the target namespace
+.TP
+-t 2000-5000,~3000-3010
+Forward local ports 2000 to 5000, but not 3000 to 3010
+.TP
+-t 192.0.2.1/20-30,~25
+Forward local ports 20 to 24, and 26 to 30, bound to 192.0.2.1
+.TP
+-t ~20000-20010
+Forward all ports to the namespace, except for the range from 20000 to 20010
.RE
IPv6 bound ports are also forwarded for IPv4.