nat: Test rewriting of MGCP messages to patch ip and port

Add code to change the ip and port for audio data inside
MGCP messages. This is needed because the BSS might be
behind the NAT and can not reach the network directly and
might be behind a nat so the announced sourceport is not
the one as we see it.
This commit is contained in:
Holger Hans Peter Freyther 2010-04-01 06:48:52 +02:00
parent 8cdfe9fc37
commit c57575bea8
4 changed files with 152 additions and 0 deletions

View File

@ -184,5 +184,6 @@ void bsc_mgcp_free_endpoints(struct bsc_nat *nat);
int bsc_mgcp_init(struct bsc_nat *nat);
struct bsc_connection *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
struct msgb *bsc_mgcp_rewrite(struct msgb *msg, const char *ip, int port);
#endif

View File

@ -95,6 +95,67 @@ struct bsc_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
return NULL;
}
/* we need to replace some strings... */
struct msgb *bsc_mgcp_rewrite(struct msgb *input, const char *ip, int port)
{
static const char *ip_str = "c=IN IP4 ";
static const char *aud_str = "m=audio ";
char buf[128];
char *running, *token;
struct msgb *output;
if (msgb_l2len(input) > 4096 - 128) {
LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n");
return NULL;
}
output = msgb_alloc_headroom(4096, 128, "MGCP rewritten");
if (!output) {
LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n");
return NULL;
}
running = (char *) input->l2h;
output->l2h = output->data;
for (token = strsep(&running, "\n"); token; token = strsep(&running, "\n")) {
int len = strlen(token);
/* ignore completely empty lines for now */
if (len == 0)
continue;
if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) {
output->l3h = msgb_put(output, strlen(ip_str));
memcpy(output->l3h, ip_str, strlen(ip_str));
output->l3h = msgb_put(output, strlen(ip));
memcpy(output->l3h, ip, strlen(ip));
output->l3h = msgb_put(output, 2);
output->l3h[0] = '\r';
output->l3h[1] = '\n';
} else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) {
int payload;
if (sscanf(token, "m=audio %*d RTP/AVP %d", &payload) != 1) {
LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n");
msgb_free(output);
return NULL;
}
snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %d\r\n", port, payload);
buf[sizeof(buf)-1] = '\0';
output->l3h = msgb_put(output, strlen(buf));
memcpy(output->l3h, buf, strlen(buf));
} else {
output->l3h = msgb_put(output, len + 1);
memcpy(output->l3h, token, len);
output->l3h[len] = '\n';
}
}
return output;
}
static int mgcp_do_read(struct bsc_fd *fd)
{
struct bsc_nat *nat;

View File

@ -87,3 +87,58 @@ static const u_int8_t ass_cmd[] = {
0x00, 0x00, 0x49, 0x00, 0x01, 0x0b, 0x00, 0x09,
0x01, 0x0b, 0x03, 0x01, 0x0a, 0x11, 0x01, 0x00,
0x15 };
/*
* MGCP messages
*/
/* nothing to patch */
static const char crcx[] = "CRCX 23265295 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n";
static const char crcx_patched[] = "CRCX 23265295 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n";
/* patch the ip and port */
static const char crcx_resp[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
static const char crcx_resp_patched[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 10.0.0.1\r\nm=audio 999 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
/* patch the ip and port */
static const char mdcx[] = " MDCX 23330829 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 172.16.18.2\r\nt=0 0\r\nm=audio 4410 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n";
static const char mdcx_patched[] = " MDCX 23330829 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 10.0.0.23\r\nt=0 0\r\nm=audio 6666 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n";
static const char mdcx_resp[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
static const char mdcx_resp_patched[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 10.0.0.23\r\nm=audio 5555 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
struct mgcp_patch_test {
const char *orig;
const char *patch;
const char *ip;
const int port;
};
static const struct mgcp_patch_test mgcp_messages[] = {
{
.orig = crcx,
.patch = crcx_patched,
.ip = "0.0.0.0",
.port = 2323,
},
{
.orig = crcx_resp,
.patch = crcx_resp_patched,
.ip = "10.0.0.1",
.port = 999,
},
{
.orig = mdcx,
.patch = mdcx_patched,
.ip = "10.0.0.23",
.port = 6666,
},
{
.orig = mdcx_resp,
.patch = mdcx_resp_patched,
.ip = "10.0.0.23",
.port = 5555,
},
};

View File

@ -410,6 +410,40 @@ static void test_mgcp_find(void)
talloc_free(nat);
}
static void test_mgcp_rewrite(void)
{
int i;
struct msgb *input, *output;
fprintf(stderr, "Test rewriting MGCP messages.\n");
input = msgb_alloc(4096, "input");
for (i = 0; i < ARRAY_SIZE(mgcp_messages); ++i) {
const char *orig = mgcp_messages[i].orig;
const char *patc = mgcp_messages[i].patch;
const char *ip = mgcp_messages[i].ip;
const int port = mgcp_messages[i].port;
copy_to_msg(input, (const u_int8_t *) orig, strlen(orig) + 1);
output = bsc_mgcp_rewrite(input, ip, port);
if (msgb_l2len(output) != strlen(patc)) {
fprintf(stderr, "Wrong sizes for test: %d %d != %d != %d\n", i, msgb_l2len(output), strlen(patc), strlen(orig));
fprintf(stderr, "String '%s' vs '%s'\n", (const char *) output->l2h, patc);
abort();
}
if (memcmp(output->l2h, patc, msgb_l2len(output)) != 0) {
fprintf(stderr, "Broken on %d msg: '%s'\n", i, (const char *) output->l2h);
abort();
}
msgb_free(output);
}
msgb_free(input);
}
int main(int argc, char **argv)
{
struct debug_target *stderr_target;
@ -423,6 +457,7 @@ int main(int argc, char **argv)
test_paging();
test_mgcp_ass_tracking();
test_mgcp_find();
test_mgcp_rewrite();
return 0;
}