diff options
| -rw-r--r-- | conf.c | 5 | ||||
| -rw-r--r-- | fwd.c | 21 | ||||
| -rw-r--r-- | inany.c | 19 | ||||
| -rw-r--r-- | inany.h | 1 |
4 files changed, 40 insertions, 6 deletions
@@ -172,11 +172,6 @@ static void conf_ports_range_except(const struct ctx *c, char optname, for (i = base; i <= last; i++) { if (exclude && bitmap_isset(exclude, i)) break; - - if (bitmap_isset(fwd->map, i)) { - warn( -"Altering mapping of already mapped port number: %s", optarg); - } } if ((optname == 'T' || optname == 'U') && c->no_bindtodevice) { @@ -349,7 +349,7 @@ void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags, const uint8_t allowed_flags = FWD_WEAK | FWD_SCAN; unsigned num = (unsigned)last - first + 1; struct fwd_rule *new; - unsigned port; + unsigned i, port; ASSERT(!(flags & ~allowed_flags)); @@ -358,6 +358,25 @@ void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags, if ((fwd->sock_count + num) > ARRAY_SIZE(fwd->socks)) die("Too many listening sockets"); + /* Check for any conflicting entries */ + for (i = 0; i < fwd->count; i++) { + char newstr[INANY_ADDRSTRLEN], rulestr[INANY_ADDRSTRLEN]; + struct fwd_rule *rule = &fwd->rules[i]; + + if (!inany_matches(addr, fwd_rule_addr(rule))) + /* Non-conflicting addresses */ + continue; + + if (last < rule->first || rule->last < first) + /* Port ranges don't overlap */ + continue; + + die("Forwarding configuration conflict: %s/%u-%u versus %s/%u-%u", + inany_ntop(addr, newstr, sizeof(newstr)), first, last, + inany_ntop(fwd_rule_addr(rule), rulestr, sizeof(rulestr)), + rule->first, rule->last); + } + new = &fwd->rules[fwd->count++]; new->flags = flags; @@ -21,6 +21,25 @@ const union inany_addr inany_loopback4 = INANY_INIT4(IN4ADDR_LOOPBACK_INIT); const union inany_addr inany_any4 = INANY_INIT4(IN4ADDR_ANY_INIT); +/** inany_matches - Do two addresses match? + * @a, @b: IPv[46] addresses (NULL for 0.0.0.0 & ::) + * + * Return: true if they match, false otherwise + * + * Addresses match themselves, but also unspecified addresses of the same + * family. + */ +bool inany_matches(const union inany_addr *a, const union inany_addr *b) +{ + if (!a || !b) + return true; + + if (inany_is_unspecified(a) || inany_is_unspecified(b)) + return !!inany_v4(a) == !!inany_v4(b); + + return inany_equals(a, b); +} + /** inany_ntop - Convert an IPv[46] address to text format * @src: IPv[46] address (NULL for unspecified) * @dst: output buffer, minimum INANY_ADDRSTRLEN bytes @@ -293,6 +293,7 @@ static inline void inany_siphash_feed(struct siphash_state *state, #define INANY_ADDRSTRLEN MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) +bool inany_matches(const union inany_addr *a, const union inany_addr *b); const char *inany_ntop(const union inany_addr *src, char *dst, socklen_t size); int inany_pton(const char *src, union inany_addr *dst); |
