aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/libalias/alias_db.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/libalias/alias_db.c')
-rw-r--r--sys/netinet/libalias/alias_db.c162
1 files changed, 132 insertions, 30 deletions
diff --git a/sys/netinet/libalias/alias_db.c b/sys/netinet/libalias/alias_db.c
index 167201fa1b8f..c143d74a2f45 100644
--- a/sys/netinet/libalias/alias_db.c
+++ b/sys/netinet/libalias/alias_db.c
@@ -28,13 +28,13 @@
#include <sys/cdefs.h>
#ifdef _KERNEL
-#include <machine/stdarg.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/rwlock.h>
+#include <sys/stdarg.h>
#include <sys/syslog.h>
#else
#include <stdarg.h>
@@ -93,6 +93,8 @@ DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
SPLAY_GENERATE(splay_out, alias_link, all.out, cmp_out);
SPLAY_GENERATE(splay_in, group_in, in, cmp_in);
+SPLAY_GENERATE(splay_internal_endpoint, alias_link, all.internal_endpoint,
+ cmp_internal_endpoint);
static struct group_in *
StartPointIn(struct libalias *la,
@@ -235,6 +237,19 @@ GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
+ if ((la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
+ lnk->link_type == LINK_UDP) {
+ /* Try reuse the same alias address:port for all destinations
+ * from the same internal address:port, as per RFC 4787.
+ */
+ struct alias_link *search_result = FindLinkByInternalEndpoint(
+ la, lnk->src_addr, lnk->src_port, lnk->link_type);
+ if (search_result != NULL) {
+ lnk->alias_port = search_result->alias_port;
+ return (0);
+ }
+ }
+
/*
* When the PKT_ALIAS_SAME_PORTS option is chosen,
* the first try will be the actual source port. If
@@ -254,10 +269,18 @@ GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
if (grp == NULL)
break;
+ /* As per RFC 4787, UDP cannot share the same alias port among
+ * multiple internal endpoints
+ */
+ if ((la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
+ lnk->link_type == LINK_UDP)
+ continue;
+
LIST_FOREACH(search_result, &grp->full, all.in) {
- if (lnk->dst_addr.s_addr == search_result->dst_addr.s_addr &&
+ if (lnk->dst_addr.s_addr ==
+ search_result->dst_addr.s_addr &&
lnk->dst_port == search_result->dst_port)
- break; /* found match */
+ break; /* found match */
}
if (search_result == NULL)
break;
@@ -496,6 +519,10 @@ DeleteLink(struct alias_link **plnk, int deletePermanent)
/* Adjust input table pointers */
LIST_REMOVE(lnk, all.in);
+ /* Adjust "internal endpoint" table pointer */
+ SPLAY_REMOVE(splay_internal_endpoint,
+ &la->linkSplayInternalEndpoint, lnk);
+
/* Remove intermediate node, if empty */
grp = StartPointIn(la, lnk->alias_addr, lnk->alias_port, lnk->link_type, 0);
if (grp != NULL &&
@@ -696,6 +723,10 @@ AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
LIST_INSERT_HEAD(&grp->partial, lnk, all.in);
else
LIST_INSERT_HEAD(&grp->full, lnk, all.in);
+
+ /* Set up pointers for "internal endpoint" lookup table */
+ SPLAY_INSERT(splay_internal_endpoint,
+ &la->linkSplayInternalEndpoint, lnk);
}
break;
}
@@ -868,8 +899,18 @@ _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
case 0:
LIST_FOREACH(lnk, &grp->full, all.in) {
if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
- lnk->dst_port == dst_port)
- return (UseLink(la, lnk));
+ lnk->dst_port == dst_port) {
+ struct alias_link *found;
+
+ found = UseLink(la, lnk);
+ if (found != NULL)
+ return (found);
+ /* link expired */
+ grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
+ if (grp == NULL)
+ return (NULL);
+ break;
+ }
}
break;
case LINK_UNKNOWN_DEST_PORT:
@@ -954,6 +995,14 @@ FindLinkIn(struct libalias *la, struct in_addr dst_addr,
lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
link_type, replace_partial_links);
+ if (lnk == NULL &&
+ (la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
+ link_type == LINK_UDP &&
+ !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
+ lnk = _FindLinkIn(la, ANY_ADDR, alias_addr, 0, alias_port,
+ link_type, replace_partial_links);
+ }
+
if (lnk == NULL) {
/*
* The following allows permanent links to be specified as
@@ -970,6 +1019,20 @@ FindLinkIn(struct libalias *la, struct in_addr dst_addr,
return (lnk);
}
+static struct alias_link *
+FindLinkByInternalEndpoint(struct libalias *la, struct in_addr src_addr,
+ u_short src_port,
+ int link_type)
+{
+ struct alias_link needle = {
+ .src_addr = src_addr,
+ .src_port = src_port,
+ .link_type = link_type
+ };
+ LIBALIAS_LOCK_ASSERT(la);
+ return SPLAY_FIND(splay_internal_endpoint, &la->linkSplayInternalEndpoint, &needle);
+}
+
/* External routines for finding/adding links
-- "external" means outside alias_db.c, but within alias*.c --
@@ -986,15 +1049,19 @@ FindLinkIn(struct libalias *la, struct in_addr dst_addr,
(prototypes in alias_local.h)
*/
-struct alias_link *
+int
FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_short id_alias,
- int create)
+ int create,
+ struct alias_link **lnkp)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
+
+ *lnkp = NULL;
+
lnk = FindLinkIn(la, dst_addr, alias_addr,
NO_DEST_PORT, id_alias,
LINK_ICMP, 0);
@@ -1005,19 +1072,26 @@ FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
lnk = AddLink(la, target_addr, dst_addr, alias_addr,
id_alias, NO_DEST_PORT, id_alias,
LINK_ICMP);
+ if (lnk == NULL)
+ return (PKT_ALIAS_ERROR);
}
- return (lnk);
+ *lnkp = lnk;
+ return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
}
-struct alias_link *
+int
FindIcmpOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_short id,
- int create)
+ int create,
+ struct alias_link **lnkp)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
+
+ *lnkp = NULL;
+
lnk = FindLinkOut(la, src_addr, dst_addr,
id, NO_DEST_PORT,
LINK_ICMP, 0);
@@ -1028,8 +1102,11 @@ FindIcmpOut(struct libalias *la, struct in_addr src_addr,
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
id, NO_DEST_PORT, GET_ALIAS_ID,
LINK_ICMP);
+ if (lnk == NULL)
+ return (PKT_ALIAS_ERROR);
}
- return (lnk);
+ *lnkp = lnk;
+ return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
}
struct alias_link *
@@ -1083,18 +1160,21 @@ FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
LINK_FRAGMENT_PTR, 0);
}
-struct alias_link *
+int
FindProtoIn(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
- u_char proto)
+ u_char proto,
+ struct alias_link **lnkp)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
+
+ *lnkp = NULL;
+
lnk = FindLinkIn(la, dst_addr, alias_addr,
NO_DEST_PORT, 0,
proto, 1);
-
if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
struct in_addr target_addr;
@@ -1102,22 +1182,28 @@ FindProtoIn(struct libalias *la, struct in_addr dst_addr,
lnk = AddLink(la, target_addr, dst_addr, alias_addr,
NO_SRC_PORT, NO_DEST_PORT, 0,
proto);
+ if (lnk == NULL)
+ return (PKT_ALIAS_ERROR);
}
- return (lnk);
+ *lnkp = lnk;
+ return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
}
-struct alias_link *
+int
FindProtoOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
- u_char proto)
+ u_char proto,
+ struct alias_link **lnkp)
{
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
+
+ *lnkp = NULL;
+
lnk = FindLinkOut(la, src_addr, dst_addr,
NO_SRC_PORT, NO_DEST_PORT,
proto, 1);
-
if (lnk == NULL) {
struct in_addr alias_addr;
@@ -1125,22 +1211,29 @@ FindProtoOut(struct libalias *la, struct in_addr src_addr,
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
NO_SRC_PORT, NO_DEST_PORT, 0,
proto);
+ if (lnk == NULL)
+ return (PKT_ALIAS_ERROR);
}
- return (lnk);
+ *lnkp = lnk;
+ return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
}
-struct alias_link *
+int
FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
struct in_addr alias_addr,
u_short dst_port,
u_short alias_port,
u_char proto,
- int create)
+ int create,
+ struct alias_link **lnkp)
{
int link_type;
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
+
+ *lnkp = NULL;
+
switch (proto) {
case IPPROTO_UDP:
link_type = LINK_UDP;
@@ -1149,8 +1242,7 @@ FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
link_type = LINK_TCP;
break;
default:
- return (NULL);
- break;
+ return (PKT_ALIAS_IGNORED);
}
lnk = FindLinkIn(la, dst_addr, alias_addr,
@@ -1164,22 +1256,30 @@ FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
lnk = AddLink(la, target_addr, dst_addr, alias_addr,
alias_port, dst_port, alias_port,
link_type);
+ if (lnk == NULL)
+ return (PKT_ALIAS_ERROR);
+
}
- return (lnk);
+ *lnkp = lnk;
+ return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
}
-struct alias_link *
+int
FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
struct in_addr dst_addr,
u_short src_port,
u_short dst_port,
u_char proto,
- int create)
+ int create,
+ struct alias_link **lnkp)
{
int link_type;
struct alias_link *lnk;
LIBALIAS_LOCK_ASSERT(la);
+
+ *lnkp = NULL;
+
switch (proto) {
case IPPROTO_UDP:
link_type = LINK_UDP;
@@ -1188,12 +1288,10 @@ FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
link_type = LINK_TCP;
break;
default:
- return (NULL);
- break;
+ return (PKT_ALIAS_IGNORED);
}
lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
-
if (lnk == NULL && create) {
struct in_addr alias_addr;
@@ -1201,8 +1299,11 @@ FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
lnk = AddLink(la, src_addr, dst_addr, alias_addr,
src_port, dst_port, GET_ALIAS_PORT,
link_type);
+ if (lnk == NULL)
+ return (PKT_ALIAS_ERROR);
}
- return (lnk);
+ *lnkp = lnk;
+ return (lnk != NULL ? PKT_ALIAS_OK : PKT_ALIAS_IGNORED);
}
struct alias_link *
@@ -2100,6 +2201,7 @@ LibAliasInit(struct libalias *la)
SPLAY_INIT(&la->linkSplayIn);
SPLAY_INIT(&la->linkSplayOut);
+ SPLAY_INIT(&la->linkSplayInternalEndpoint);
LIST_INIT(&la->pptpList);
TAILQ_INIT(&la->checkExpire);
#ifdef _KERNEL