Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b

Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/natbd/genalg.c b/src/natbd/genalg.c
new file mode 100644
index 0000000..50b3827
--- /dev/null
+++ b/src/natbd/genalg.c
@@ -0,0 +1,152 @@
+/**
+ * @file genalg.c  Detecting Generic ALGs
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re_types.h>
+#include <re_mbuf.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_sa.h>
+#include <re_list.h>
+#include <re_stun.h>
+#include <re_natbd.h>
+
+
+#define DEBUG_MODULE "natbd_genalg"
+#define DEBUG_LEVEL 7
+#include <re_dbg.h>
+
+
+/*
+  Detecting Generic ALGs
+
+   A number of NAT boxes are now being deployed into the market which
+   try to provide "generic" ALG functionality.  These generic ALGs hunt
+   for IP addresses, either in text or binary form within a packet, and
+   rewrite them if they match a binding.  This behavior can be detected
+   because the STUN server returns both the MAPPED-ADDRESS and XOR-
+   MAPPED-ADDRESS in the same response.  If the result in the two does
+   not match, there a NAT with a generic ALG in the path.
+ */
+
+
+/** Defines a NAT Generic ALG detection session */
+struct nat_genalg {
+	struct stun *stun;      /**< STUN Client               */
+	struct sa srv;          /**< Server address and port   */
+	int proto;              /**< IP protocol               */
+	nat_genalg_h *h;        /**< Result handler            */
+	void *arg;              /**< Handler argument          */
+};
+
+
+static void stun_response_handler(int err, uint16_t scode, const char *reason,
+				  const struct stun_msg *msg, void *arg)
+{
+	struct stun_attr *xmap, *map;
+	struct nat_genalg *ng = arg;
+	int status = 0;
+	(void)reason;
+
+	if (err) {
+		ng->h(err, 0, NULL, -1, NULL, ng->arg);
+		return;
+	}
+
+	switch (scode) {
+
+	case 0:
+		map  = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR);
+		xmap = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
+		if (!map || !xmap) {
+			ng->h(EINVAL, scode, reason, -1, NULL, ng->arg);
+			break;
+		}
+
+		status = sa_cmp(&map->v.sa, &xmap->v.sa, SA_ALL) ? -1 : 1;
+
+		ng->h(0, scode, reason, status, &xmap->v.sa, ng->arg);
+		break;
+
+	default:
+		ng->h(0, scode, reason, -1, NULL, ng->arg);
+		break;
+	}
+}
+
+
+static void genalg_destructor(void *data)
+{
+	struct nat_genalg *ng = data;
+
+	mem_deref(ng->stun);
+}
+
+
+/**
+ * Allocate a new NAT Generic ALG detection session
+ *
+ * @param ngp       Pointer to allocated NAT Generic ALG object
+ * @param srv       STUN Server IP address and port
+ * @param proto     Transport protocol
+ * @param conf      STUN configuration (Optional)
+ * @param gh        Generic ALG handler
+ * @param arg       Handler argument
+ *
+ * @return 0 if success, errorcode if failure
+ */
+int nat_genalg_alloc(struct nat_genalg **ngp, const struct sa *srv, int proto,
+		     const struct stun_conf *conf,
+		     nat_genalg_h *gh, void *arg)
+{
+	struct nat_genalg *ng;
+	int err;
+
+	if (!ngp || !srv || !proto || !gh)
+		return EINVAL;
+
+	ng = mem_zalloc(sizeof(*ng), genalg_destructor);
+	if (!ng)
+		return ENOMEM;
+
+	err = stun_alloc(&ng->stun, conf, NULL, NULL);
+	if (err)
+		goto out;
+
+	sa_cpy(&ng->srv, srv);
+	ng->proto = proto;
+	ng->h     = gh;
+	ng->arg   = arg;
+
+ out:
+	if (err)
+		mem_deref(ng);
+	else
+		*ngp = ng;
+
+	return err;
+}
+
+
+/**
+ * Start the NAT Generic ALG detection
+ *
+ * @param ng NAT Generic ALG object
+ *
+ * @return 0 if success, errorcode if failure
+ */
+int nat_genalg_start(struct nat_genalg *ng)
+{
+	int err;
+
+	if (!ng)
+		return EINVAL;
+
+	err = stun_request(NULL, ng->stun, ng->proto, NULL, &ng->srv, 0,
+			   STUN_METHOD_BINDING, NULL, 0, false,
+			   stun_response_handler, ng, 1,
+			   STUN_ATTR_SOFTWARE, stun_software);
+
+	return err;
+}