diff --git a/configure.ac b/configure.ac index 84a1767..97e3fbc 100644 --- a/configure.ac +++ b/configure.ac @@ -49,4 +49,5 @@ AC_OUTPUT( tests/mtp/Makefile tests/patching/Makefile tests/isup/Makefile + tests/mgcp/Makefile Makefile) diff --git a/include/Makefile.am b/include/Makefile.am index a4cdfb3..acaf137 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,7 @@ noinst_HEADERS = mtp_level3.h mtp_data.h ipaccess.h thread.h mtp_pcap.h \ mgcp_ss7.h bss_patch.h bssap_sccp.h bsc_data.h udp_input.h \ snmp_mtp.h cellmgr_debug.h bsc_sccp.h bsc_ussd.h sctp_m2ua.h \ - isup_types.h counter.h msc_connection.h ss7_application.h + isup_types.h counter.h msc_connection.h ss7_application.h \ + mgcp_patch.h SUBDIRS = mgcp diff --git a/include/mgcp_patch.h b/include/mgcp_patch.h new file mode 100644 index 0000000..d672b3b --- /dev/null +++ b/include/mgcp_patch.h @@ -0,0 +1,9 @@ +#ifndef MGCP_PATCH_H +#define MGCP_PATCH_H + +#include + +struct ss7_application; +struct msgb *mgcp_patch(struct ss7_application *app, struct msgb *msg); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 092a183..2a38185 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,7 @@ cellmgr_ng_SOURCES = main.c mtp_layer3.c thread.c input/ipaccess.c pcap.c \ bss_patch.c bssap_sccp.c bsc_sccp.c bsc_ussd.c links.c \ msc_conn.c link_udp.c snmp_mtp.c debug.c isup.c \ mtp_link.c counter.c sccp_state.c bsc.c ss7_application.c \ - vty_interface_legacy.c vty_interface_cmds.c + vty_interface_legacy.c vty_interface_cmds.c mgcp_patch.c cellmgr_ng_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) $(NEXUSWARE_C7_LIBS) \ -lpthread -lnetsnmp -lcrypto @@ -21,6 +21,6 @@ osmo_stp_SOURCES = main_stp.c mtp_layer3.c thread.c pcap.c link_udp.c snmp_mtp.c debug.c links.c isup.c sctp_m2ua.c msc_conn.c sccp_state.c \ bss_patch.c bssap_sccp.c bsc_sccp.c bsc_ussd.c input/ipaccess.c \ mtp_link.c counter.c bsc.c ss7_application.c \ - vty_interface.c vty_interface_cmds.c + vty_interface.c vty_interface_cmds.c mgcp_patch.c osmo_stp_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) $(NEXUSWARE_C7_LIBS) \ -lpthread -lnetsnmp -lcrypto -lm2ua -lsctp diff --git a/src/mgcp_patch.c b/src/mgcp_patch.c new file mode 100644 index 0000000..0924f03 --- /dev/null +++ b/src/mgcp_patch.c @@ -0,0 +1,111 @@ +/* MGCP message patching */ +/* + * (C) 2011 by Holger Hans Peter Freyther + * (C) 2011 by On-Waves + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include + + +struct msgb *mgcp_patch(struct ss7_application *app, struct msgb *msg) +{ + char *token, *remaining; + struct msgb *out; + int len, out_len, state, i; + + if (!app->mgcp_domain_name) + return msg; + + if (msgb_tailroom(msg) <= strlen(app->mgcp_domain_name)) { + LOGP(DMGCP, LOGL_ERROR, "Not enough space to add a zero line.\n"); + return msg; + } + + msg->l2h[msgb_l2len(msg)] = '\0'; + + /** + * We now need to rewrite the message, but actually only the first + * line and the rest can be copied. + */ + out = msgb_alloc_headroom(4096, 128, "MGCP Patch Copy"); + if (!out) { + LOGP(DMGCP, LOGL_ERROR, "Failed to create the MSGB copy.\n"); + return NULL; + } + + + remaining = (char *) msg->l2h; + token = strsep(&remaining, "\n"); + if (!token) { + LOGP(DMGCP, LOGL_ERROR, "Failed to split the MGCP.\n"); + msgb_free(out); + return msg; + } + + len = strlen(token); + out->l2h = msgb_put(out, 0); + + /* + * State machine for copying and modifying the MGCP line, first find + * half of the endpoint, put ours, copy the rest of the line + */ + state = 0; + for (i = 0; i < len; ++i) { + switch (state) { + case 2: + if (token[i] == '@') + state += 1; + msgb_v_put(out, token[i]); + break; + case 3: + /* copy the new name */ + out->l3h = msgb_put(out, strlen(app->mgcp_domain_name)); + memcpy(out->l3h, app->mgcp_domain_name, msgb_l3len(out)); + + /* skip everything to the next whitespace */ + for (; i < len; ++i) { + if (token[i] == ' ') { + break; + } + } + + for (; i < len; ++i) + msgb_v_put(out, token[i]); + msgb_v_put(out, '\n'); + break; + default: + if (token[i] == ' ') + state += 1; + msgb_v_put(out, token[i]); + break; + } + } + + /* append the rest */ + out_len = msgb_l2len(msg) - len - 1; + out->l3h = msgb_put(out, out_len); + memcpy(out->l3h, &msg->l2h[len + 1], out_len); + + msgb_free(msg); + return out; +} + diff --git a/src/msc_conn.c b/src/msc_conn.c index 6e6109f..f079e99 100644 --- a/src/msc_conn.c +++ b/src/msc_conn.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -157,6 +158,7 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd) } else if (hh->proto == IPAC_PROTO_SCCP) { msc_dispatch_sccp(fw, msg); } else if (hh->proto == NAT_MUX) { + msg = mgcp_patch(fw->app, msg); mgcp_forward(fw, msg->l2h, msgb_l2len(msg)); } else { LOGP(DMSC, LOGL_ERROR, "Unknown IPA proto 0x%x\n", hh->proto); diff --git a/tests/Makefile.am b/tests/Makefile.am index 6ffa86d..d7cebd8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1 +1 @@ -SUBDIRS = mtp patching isup +SUBDIRS = mtp patching isup mgcp diff --git a/tests/mgcp/Makefile.am b/tests/mgcp/Makefile.am new file mode 100644 index 0000000..2e8db48 --- /dev/null +++ b/tests/mgcp/Makefile.am @@ -0,0 +1,6 @@ +INCLUDES = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) +noinst_PROGRAMS = mgcp_patch_test + +mgcp_patch_test_SOURCES = mgcp_patch_test.c $(top_srcdir)/src/mgcp_patch.c +mgcp_patch_test_LDADD = $(LIBOSMOCORE_LIBS) diff --git a/tests/mgcp/mgcp_patch_test.c b/tests/mgcp/mgcp_patch_test.c new file mode 100644 index 0000000..335cfcf --- /dev/null +++ b/tests/mgcp/mgcp_patch_test.c @@ -0,0 +1,103 @@ +/* + * (C) 2011 by Holger Hans Peter Freyther + * (C) 2011 by On-Waves + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include + +static const char mgcp_in[] = + "MDCX 23213 14@mgw MGCP 1.0\r\n" + "C: 4a84ad5d25f\r\n" + "I: %d\r\n" + "L: p:20, a:GSM-EFR, nt:IN\r\n" + "M: recvonly\r\n\r\n" + "v=0\r\n" + "o=- 258696477 0 IN IP4 172.16.1.107\r\n" + "s=-\r\n" + "c=IN IP4 172.16.1.107\r\n" + "t=0 0\r\n" + "m=audio 6666 RTP/AVP 127\r\n" + "a=rtpmap:127 GSM-EFR/8000/1\r\n" + "a=ptime:20\r\n" + "a=recvonly\r\n" + "m=image 4402 udptl t38\r\n" + "a=T38FaxVersion:0\r\n" + "a=T38MaxBitRate:14400\r\n"; + +static const char mgcp_out[] = + "MDCX 23213 14@foo2 MGCP 1.0\r\n" + "C: 4a84ad5d25f\r\n" + "I: %d\r\n" + "L: p:20, a:GSM-EFR, nt:IN\r\n" + "M: recvonly\r\n\r\n" + "v=0\r\n" + "o=- 258696477 0 IN IP4 172.16.1.107\r\n" + "s=-\r\n" + "c=IN IP4 172.16.1.107\r\n" + "t=0 0\r\n" + "m=audio 6666 RTP/AVP 127\r\n" + "a=rtpmap:127 GSM-EFR/8000/1\r\n" + "a=ptime:20\r\n" + "a=recvonly\r\n" + "m=image 4402 udptl t38\r\n" + "a=T38FaxVersion:0\r\n" + "a=T38MaxBitRate:14400\r\n"; + +#define ASSERT(a, cmp, b, text) \ + if (!((a) cmp (b))) { \ + fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, text); \ + abort(); \ + } + +static void test_endp_name_rewriting() +{ + struct ss7_application app; + memset(&app, 0, sizeof(app)); + + app.mgcp_domain_name = "foo2"; + + /* prepare */ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "test"); + msg->l2h = msgb_put(msg, strlen(mgcp_in)); + memcpy(msg->l2h, mgcp_in, msgb_l2len(msg)); + + /* patch it now */ + struct msgb *msg_out = mgcp_patch(&app, msg); + msg_out->l2h[msgb_l2len(msg_out)] = '\0'; +#ifdef DEBUG + printf("Want : '%s'\n", mgcp_out); + printf("Outpu: '%s'\n", (const char *) msg_out->l2h); + printf("%s\n", osmo_hexdump(mgcp_out, strlen(mgcp_out))); + printf("%s\n", osmo_hexdump(msg_out->l2h, msgb_l2len(msg_out))); +#endif + ASSERT(msg_out, !=, msg, "msg should not be the same"); + + ASSERT(msgb_l2len(msg_out), ==, strlen(mgcp_out), "Output size wrong"); + ASSERT(strcmp((const char *)msg_out->l2h, mgcp_out), ==, 0, "Text don't match"); +} + +int main(int argc, char **argv) +{ + test_endp_name_rewriting(); + + return 0; +}