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;
+}