diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 412d9a841..068ef68fb 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -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 diff --git a/openbsc/src/nat/bsc_mgcp_utils.c b/openbsc/src/nat/bsc_mgcp_utils.c index 0f45a91a5..3639a7b00 100644 --- a/openbsc/src/nat/bsc_mgcp_utils.c +++ b/openbsc/src/nat/bsc_mgcp_utils.c @@ -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; diff --git a/openbsc/tests/bsc-nat/bsc_data.c b/openbsc/tests/bsc-nat/bsc_data.c index ca170e2ac..28d506466 100644 --- a/openbsc/tests/bsc-nat/bsc_data.c +++ b/openbsc/tests/bsc-nat/bsc_data.c @@ -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, + }, +}; diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index 30f1490f1..217c4f415 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -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; }