blob: 50b3827714afcc067066b237454a043f00feab35 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file genalg.c Detecting Generic ALGs
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <re_types.h>
7#include <re_mbuf.h>
8#include <re_fmt.h>
9#include <re_mem.h>
10#include <re_sa.h>
11#include <re_list.h>
12#include <re_stun.h>
13#include <re_natbd.h>
14
15
16#define DEBUG_MODULE "natbd_genalg"
17#define DEBUG_LEVEL 7
18#include <re_dbg.h>
19
20
21/*
22 Detecting Generic ALGs
23
24 A number of NAT boxes are now being deployed into the market which
25 try to provide "generic" ALG functionality. These generic ALGs hunt
26 for IP addresses, either in text or binary form within a packet, and
27 rewrite them if they match a binding. This behavior can be detected
28 because the STUN server returns both the MAPPED-ADDRESS and XOR-
29 MAPPED-ADDRESS in the same response. If the result in the two does
30 not match, there a NAT with a generic ALG in the path.
31 */
32
33
34/** Defines a NAT Generic ALG detection session */
35struct nat_genalg {
36 struct stun *stun; /**< STUN Client */
37 struct sa srv; /**< Server address and port */
38 int proto; /**< IP protocol */
39 nat_genalg_h *h; /**< Result handler */
40 void *arg; /**< Handler argument */
41};
42
43
44static void stun_response_handler(int err, uint16_t scode, const char *reason,
45 const struct stun_msg *msg, void *arg)
46{
47 struct stun_attr *xmap, *map;
48 struct nat_genalg *ng = arg;
49 int status = 0;
50 (void)reason;
51
52 if (err) {
53 ng->h(err, 0, NULL, -1, NULL, ng->arg);
54 return;
55 }
56
57 switch (scode) {
58
59 case 0:
60 map = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR);
61 xmap = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
62 if (!map || !xmap) {
63 ng->h(EINVAL, scode, reason, -1, NULL, ng->arg);
64 break;
65 }
66
67 status = sa_cmp(&map->v.sa, &xmap->v.sa, SA_ALL) ? -1 : 1;
68
69 ng->h(0, scode, reason, status, &xmap->v.sa, ng->arg);
70 break;
71
72 default:
73 ng->h(0, scode, reason, -1, NULL, ng->arg);
74 break;
75 }
76}
77
78
79static void genalg_destructor(void *data)
80{
81 struct nat_genalg *ng = data;
82
83 mem_deref(ng->stun);
84}
85
86
87/**
88 * Allocate a new NAT Generic ALG detection session
89 *
90 * @param ngp Pointer to allocated NAT Generic ALG object
91 * @param srv STUN Server IP address and port
92 * @param proto Transport protocol
93 * @param conf STUN configuration (Optional)
94 * @param gh Generic ALG handler
95 * @param arg Handler argument
96 *
97 * @return 0 if success, errorcode if failure
98 */
99int nat_genalg_alloc(struct nat_genalg **ngp, const struct sa *srv, int proto,
100 const struct stun_conf *conf,
101 nat_genalg_h *gh, void *arg)
102{
103 struct nat_genalg *ng;
104 int err;
105
106 if (!ngp || !srv || !proto || !gh)
107 return EINVAL;
108
109 ng = mem_zalloc(sizeof(*ng), genalg_destructor);
110 if (!ng)
111 return ENOMEM;
112
113 err = stun_alloc(&ng->stun, conf, NULL, NULL);
114 if (err)
115 goto out;
116
117 sa_cpy(&ng->srv, srv);
118 ng->proto = proto;
119 ng->h = gh;
120 ng->arg = arg;
121
122 out:
123 if (err)
124 mem_deref(ng);
125 else
126 *ngp = ng;
127
128 return err;
129}
130
131
132/**
133 * Start the NAT Generic ALG detection
134 *
135 * @param ng NAT Generic ALG object
136 *
137 * @return 0 if success, errorcode if failure
138 */
139int nat_genalg_start(struct nat_genalg *ng)
140{
141 int err;
142
143 if (!ng)
144 return EINVAL;
145
146 err = stun_request(NULL, ng->stun, ng->proto, NULL, &ng->srv, 0,
147 STUN_METHOD_BINDING, NULL, 0, false,
148 stun_response_handler, ng, 1,
149 STUN_ATTR_SOFTWARE, stun_software);
150
151 return err;
152}