aboutgitcodebugslistschat
path: root/fwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'fwd.c')
-rw-r--r--fwd.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/fwd.c b/fwd.c
index 961c533..ecf939b 100644
--- a/fwd.c
+++ b/fwd.c
@@ -13,6 +13,7 @@
* Author: David Gibson <david@gibson.dropbear.id.au>
*/
+#include <assert.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
@@ -22,6 +23,8 @@
#include "util.h"
#include "ip.h"
+#include "siphash.h"
+#include "inany.h"
#include "fwd.h"
#include "passt.h"
#include "lineread.h"
@@ -301,6 +304,20 @@ parse_err:
}
/**
+ * fwd_rule_addr() - Return match address for a rule
+ * @rule: Forwarding rule
+ *
+ * Return: matching address for rule, NULL if it matches all addresses
+ */
+static const union inany_addr *fwd_rule_addr(const struct fwd_rule *rule)
+{
+ if (rule->flags & FWD_DUAL_STACK_ANY)
+ return NULL;
+
+ return &rule->addr;
+}
+
+/**
* fwd_port_is_ephemeral() - Is port number ephemeral?
* @port: Port number
*
@@ -313,6 +330,92 @@ bool fwd_port_is_ephemeral(in_port_t port)
return (port >= fwd_ephemeral_min) && (port <= fwd_ephemeral_max);
}
+/**
+ * fwd_rule_add() - Add a rule to a forwarding table
+ * @fwd: Table to add to
+ * @flags: Flags for this entry
+ * @addr: Our address to forward (NULL for both 0.0.0.0 and ::)
+ * @ifname: Only forward from this interface name, if non-empty
+ * @first: First port number to forward
+ * @last: Last port number to forward
+ * @to: First port of target port range to map to
+ */
+void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags,
+ const union inany_addr *addr, const char *ifname,
+ in_port_t first, in_port_t last, in_port_t to)
+{
+ /* Flags which can be set from the caller */
+ const uint8_t allowed_flags = FWD_WEAK;
+ struct fwd_rule *new;
+ unsigned port;
+
+ ASSERT(!(flags & ~allowed_flags));
+
+ if (fwd->count >= ARRAY_SIZE(fwd->rules))
+ die("Too many port forwarding ranges");
+
+ new = &fwd->rules[fwd->count++];
+ new->flags = flags;
+
+ if (addr) {
+ new->addr = *addr;
+ } else {
+ new->addr = inany_any6;
+ new->flags |= FWD_DUAL_STACK_ANY;
+ }
+
+ memset(new->ifname, 0, sizeof(new->ifname));
+ if (ifname) {
+ int ret;
+
+ ret = snprintf(new->ifname, sizeof(new->ifname), "%s", ifname);
+ if (ret <= 0 || (size_t)ret >= sizeof(new->ifname))
+ die("Invalid interface name: %s", ifname);
+ }
+
+ ASSERT(first <= last);
+ new->first = first;
+ new->last = last;
+
+ new->to = to;
+
+ for (port = new->first; port <= new->last; port++) {
+ /* Fill in the legacy data structures to match the table */
+ bitmap_set(fwd->map, port);
+ fwd->delta[port] = new->to - new->first;
+ }
+}
+
+/**
+ * fwd_rules_print() - Print forwarding rules for debugging
+ * @fwd: Table to print
+ */
+void fwd_rules_print(const struct fwd_ports *fwd)
+{
+ unsigned i;
+
+ for (i = 0; i < fwd->count; i++) {
+ const struct fwd_rule *rule = &fwd->rules[i];
+ const char *percent = *rule->ifname ? "%" : "";
+ char addr[INANY_ADDRSTRLEN];
+ const char *weak = "";
+
+ inany_ntop(fwd_rule_addr(rule), addr, sizeof(addr));
+ if (rule->flags & FWD_WEAK)
+ weak = " (best effort)";
+
+ if (rule->first == rule->last) {
+ info(" [%s]%s%s:%hu => %hu %s",
+ addr, percent, rule->ifname,
+ rule->first, rule->to, weak);
+ } else {
+ info(" [%s]%s%s:%hu-%hu => %hu-%hu %s",
+ addr, percent, rule->ifname, rule->first, rule->last,
+ rule->to, rule->last - rule->first + rule->to, weak);
+ }
+ }
+}
+
/* See enum in kernel's include/net/tcp_states.h */
#define UDP_LISTEN 0x07
#define TCP_LISTEN 0x0a