diff options
| author | David Gibson <david@gibson.dropbear.id.au> | 2026-07-07 14:24:51 +1000 |
|---|---|---|
| committer | Stefano Brivio <sbrivio@redhat.com> | 2026-07-08 20:58:59 +0200 |
| commit | c8145c3bb2cca31599eeb483e7c8e5d428c72b4b (patch) | |
| tree | 9583fcb47ff890d1866f87704d0e7fbc5f074c1c | |
| parent | bf2103815db917e532cad0b9b3530604de463d5a (diff) | |
| download | passt-c8145c3bb2cca31599eeb483e7c8e5d428c72b4b.tar passt-c8145c3bb2cca31599eeb483e7c8e5d428c72b4b.tar.gz passt-c8145c3bb2cca31599eeb483e7c8e5d428c72b4b.tar.bz2 passt-c8145c3bb2cca31599eeb483e7c8e5d428c72b4b.tar.lz passt-c8145c3bb2cca31599eeb483e7c8e5d428c72b4b.tar.xz passt-c8145c3bb2cca31599eeb483e7c8e5d428c72b4b.tar.zst passt-c8145c3bb2cca31599eeb483e7c8e5d428c72b4b.zip | |
fwd_rule: Parse target addresses for forwarding rules
Extend the parsing of forwarding rules (-[tu]) to allow the destination
address on the target side to be specified. For now just parse them, and
give an error if we try to create rules with a specified target address.
We'll implement the actual forwarding logic in another patch.
Format (for either command line or pesto):
-t 2222:192.0.2.1/2222
This should work along with all the other bits, that is, say:
-t 192.0.2.1%eth0/2222-2225:192.0.2.2/22-25
FIXME: Ban for -[TU] for now
FIXME: Check interaction with splice handling
[dwg: Syntax from Stefano's earlier draft, largely rewritten on top of new
parsing helpers]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
| -rw-r--r-- | fwd_rule.c | 77 | ||||
| -rw-r--r-- | passt.1 | 31 |
2 files changed, 85 insertions, 23 deletions
@@ -378,14 +378,17 @@ int fwd_rule_add(struct fwd_table *fwd, const struct fwd_rule *new) * @first: First port to forward * @last: Last port to forward * @exclude: Bitmap of ports to exclude (may be NULL) - * @to: Port to translate @first to when forwarding + * @tgt_addr: Destination address on the target side + * @tgt_first: Destination port to use for @first on the target side * @flags: Flags for forwarding entries */ static void fwd_rule_range_except(struct fwd_table *fwd, bool del, uint8_t proto, const union inany_addr *addr, const char *ifname, uint16_t first, uint16_t last, - const uint8_t *exclude, uint16_t to, + const uint8_t *exclude, + const union inany_addr *tgt_addr, + uint16_t tgt_first, uint8_t flags) { struct fwd_rule rule = { @@ -394,10 +397,18 @@ static void fwd_rule_range_except(struct fwd_table *fwd, bool del, .proto = proto, .flags = flags, }; + unsigned delta = tgt_first - first; char rulestr[FWD_RULE_STRLEN]; - unsigned delta = to - first; unsigned base, i; + if (tgt_addr && !inany_is_unspecified(tgt_addr)) { + char astr[INANY_ADDRSTRLEN]; + + info("Target address: %s", + inany_ntop(tgt_addr, astr, sizeof(astr))); + die("Target address remapping not yet implemented"); + } + if (!addr) rule.flags |= FWD_DUAL_STACK_ANY; if (ifname) { @@ -458,19 +469,31 @@ enum fwd_port_chunk_kind { * @cursor: Parsing point (see parse.c) * @kindp: Updated with kind of chunk we parsed * @lrange: Updated with listening port range (for INCLUDE & EXCLUDE) + * @taddr: Updated with target address (for INCLUDE & ALL) * @trange: Updated with target port range (for INCLUDE) */ static bool parse_port_chunk(const char **cursor, enum fwd_port_chunk_kind *kindp, struct port_range *lrange, + union inany_addr *taddr, struct port_range *trange) { struct port_range lr = { 0 }, tr = { 0 }; + union inany_addr taddr_tmp = inany_any6; enum fwd_port_chunk_kind kind; const char *p = *cursor; if (parse_literal(&p, "all")) { + const char *tgtspec = p; + kind = CHUNK_ALL; + if (p = tgtspec, + parse_literal(&p, ":") && + parse_inany(&p, &taddr_tmp)) { + /* Target address */ + } else { + p = tgtspec; + } } else if (parse_literal(&p, "auto")) { kind = CHUNK_AUTO; } else if (parse_literal(&p, "~")) { @@ -478,12 +501,29 @@ static bool parse_port_chunk(const char **cursor, if (!parse_port_range(&p, &lr)) return false; } else if (parse_port_range(&p, &lr)) { - kind = CHUNK_INCLUDE; + const char *tgtspec = p; - if (parse_literal(&p, ":")) { - if (!parse_port_range(&p, &tr)) - return false; + kind = CHUNK_INCLUDE; + if (p = tgtspec, + parse_literal(&p, ":") && + parse_inany(&p, &taddr_tmp) && + parse_literal(&p, "/") && + parse_port_range(&p, &tr)) { + /* Target address & range */ + } else if (p = tgtspec, + parse_literal(&p, ":") && + parse_inany(&p, &taddr_tmp)) { + /* Target address only */ + tr = lr; + } else if (p = tgtspec, + parse_literal(&p, ":") && + parse_port_range(&p, &tr)) { + /* Target range only */ + taddr_tmp = inany_any6; } else { + p = tgtspec; + /* No target specification */ + taddr_tmp = inany_any6; tr = lr; } } else { @@ -492,6 +532,8 @@ static bool parse_port_chunk(const char **cursor, *kindp = kind; *lrange = lr; + if (taddr) + *taddr = taddr_tmp; if (trange) *trange = tr; *cursor = p; @@ -551,6 +593,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, const char *spec) { uint8_t exclude[PORT_BITMAP_SIZE] = { 0 }; + union inany_addr all_taddr = inany_any6; enum fwd_port_chunk_kind kind; struct port_range lrange; bool exclude_only = true; @@ -561,7 +604,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, /* Consider excluded ranges and "auto" in the first pass */ p = spec; do { - if (!parse_port_chunk(&p, &kind, &lrange, NULL)) + if (!parse_port_chunk(&p, &kind, &lrange, NULL, NULL)) goto bad; switch (kind) { @@ -586,14 +629,19 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, p = spec; do { struct port_range trange; + union inany_addr taddr; - if (!parse_port_chunk(&p, &kind, &lrange, &trange)) + if (!parse_port_chunk(&p, &kind, &lrange, &taddr, &trange)) goto bad; switch (kind) { - case CHUNK_AUTO: /* already handled */ - case CHUNK_EXCLUDE: /* already handled */ - case CHUNK_ALL: /* handled later */ + case CHUNK_AUTO: + case CHUNK_EXCLUDE: + continue; /* already handled */ + + case CHUNK_ALL: + /* Save the address to use later */ + all_taddr = taddr; continue; case CHUNK_INCLUDE: @@ -604,7 +652,8 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, fwd_rule_range_except(fwd, del, proto, addr, ifname, lrange.first, lrange.last, - exclude, trange.first, flags); + exclude, &taddr, trange.first, + flags); break; default: goto bad; @@ -620,7 +669,7 @@ static void fwd_rule_parse_ports(struct fwd_table *fwd, bool del, uint8_t proto, fwd_rule_range_except(fwd, del, proto, addr, ifname, 1, NUM_PORTS - 1, exclude, - 1, flags | FWD_WEAK); + &all_taddr, 1, flags | FWD_WEAK); } return; bad: @@ -449,12 +449,15 @@ interface name (since Linux 5.7) can be specified. \fIports\fR is a comma-separated list of entries which may be any of: .TP -\fIfirst\fR[\fB-\fR\fIlast\fR][\fB:\fR\fItofirst\fR[\fB-\fR\fItolast\fR]] +\fIfirst\fR[\fB-\fR\fIlast\fR][\fB:\fR[\fItoaddr\fR\fB/\fR]\fItofirst\fR[\fB-\fR\fItolast\fR]] +.TP +\fIfirst\fR[\fB-\fR\fIlast\fR][\fB:\fR\fItoaddr\fR] Include range. Forward port numbers between \fIfirst\fR and \fIlast\fR -(inclusive) to ports between \fItofirst\fR and \fItolast\fR. If -\fItofirst\fR and \fItolast\fR are omitted, assume the same as -\fIfirst\fR and \fIlast\fR. If \fIlast\fR is omitted, assume the same -as \fIfirst\fR. +(inclusive) to ports between \fItofirst\fR and \fItolast\fR to address +\fItoaddr\fR. If \fItoaddr\fR is omitted, automatically determine the +guest or namespace address. If \fItofirst\fR and \fItolast\fR are +omitted, assume the same as \fIfirst\fR and \fIlast\fR. If \fIlast\fR +is omitted, assume the same as \fIfirst\fR. .TP \fB~\fR\fIfirst\fR[\fB-\fR\fIlast\fR] @@ -462,11 +465,13 @@ Exclude range. Don't forward port numbers between \fIfirst\fR and \fIlast\fR. This takes precedences over include ranges. .TP -.BR all +.BR all\fR[\fB:\fItoaddr\fR] Forward all unbound, non-ephemeral ports, not covered by exclude -ranges above, as permitted by current capabilities. For low (< 1024) -ports, see \fBNOTES\fR. No failures are reported for unavailable -ports, unless no ports could be forwarded at all. +ranges above, as permitted by current capabilities, to the +corresponding ports on address \fItoaddr\fR. If \fItoaddr\fR is +omitted, automatically determine the guest or namespace address. For +low (< 1024) ports, see \fBNOTES\fR. No failures are reported for +unavailable ports, unless no ports could be forwarded at all. .TP .BR auto @@ -516,6 +521,14 @@ Forward local port 22, bound to 192.0.2.1 and interface eth0, to port 22 -t %eth0/22 Forward local port 22, bound to any address on interface eth0, to port 22 .TP +-t 0.0.0.0/5000:192.0.2.5/6000 +Forward local port 5000, bound to any IPv4 address, to port 6000 on address 192.0.2.5. +.TP +-t 127.0.0.6/all:192.0.2.6 +For the local address 127.0.0.6, forward all unbound, non-ephemeral +ports as permitted by current capabilities to the corresponding port +on 192.0.2.6. +.TP -t 2000-5000,~3000-3010 Forward local ports between 2000 and 5000, except for those between 3000 and 3010 |
