155 lines
3.4 KiB
C
155 lines
3.4 KiB
C
/**
|
|
* @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);
|
|
if (err) {
|
|
DEBUG_WARNING("start: stunc_request_send(): (%m)\n", err);
|
|
}
|
|
|
|
return err;
|
|
}
|