diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 6784fe8b3..7fc1fce2b 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -1,9 +1,6 @@ name: Build distribution packages on: - push: - branches: - - '**' pull_request: branches: - '**' diff --git a/.github/workflows/freebsd_build.yml b/.github/workflows/freebsd_build.yml index 16be7bd5c..4c265ad27 100644 --- a/.github/workflows/freebsd_build.yml +++ b/.github/workflows/freebsd_build.yml @@ -1,9 +1,6 @@ name: FreeBSD build on: - push: - branches: - - '**' pull_request: branches: - '**' diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml index af4e07083..c69f7f4d8 100644 --- a/.github/workflows/macos_build.yml +++ b/.github/workflows/macos_build.yml @@ -1,9 +1,6 @@ name: macOS build on: - push: - branches: - - '**' pull_request: branches: - '**' diff --git a/.gitignore b/.gitignore index f8b258817..f99c751dc 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ apps/py_sems/sip/*.h apps/rtmp/flash_phone/*.swf apps/rtmp/librtmp/librtmp.so.0 build/ +build_check/ cmake_install.cmake core.* core/etc/*.conf diff --git a/apps/sbc/SBCCallLeg.cpp b/apps/sbc/SBCCallLeg.cpp index d05b5225c..97d8ab165 100644 --- a/apps/sbc/SBCCallLeg.cpp +++ b/apps/sbc/SBCCallLeg.cpp @@ -36,6 +36,8 @@ #include "AmConfigReader.h" #include "AmSessionContainer.h" #include "AmSipHeaders.h" +#include "AmConfig.h" +#include "sip/defs.h" #include "SBCSimpleRelay.h" #include "RegisterDialog.h" #include "SubscriptionDialog.h" @@ -699,6 +701,15 @@ void SBCCallLeg::onSendRequest(AmSipRequest& req, int &flags) { CallLeg::onSendRequest(req, flags); } +void SBCCallLeg::onApplyIdentityHeader(string& hdrs, const char* hdr_name, int flags) +{ + if (!call_profile.send_user_agent) { + removeHeader(hdrs, hdr_name); + } else if (AmConfig::Signature.length() && getHeader(hdrs, hdr_name).empty()) { + hdrs += string(hdr_name) + COLSP + AmConfig::Signature + CRLF; + } +} + void SBCCallLeg::onRemoteDisappeared(const AmSipReply& reply) { CallLeg::onRemoteDisappeared(reply); diff --git a/apps/sbc/SBCCallLeg.h b/apps/sbc/SBCCallLeg.h index e83597b4a..43d117390 100644 --- a/apps/sbc/SBCCallLeg.h +++ b/apps/sbc/SBCCallLeg.h @@ -219,6 +219,7 @@ class SBCCallLeg : public CallLeg, public CredentialHolder void onSipReply(const AmSipRequest& req, const AmSipReply& reply, AmSipDialog::Status old_dlg_status); void onSendRequest(AmSipRequest& req, int &flags); + void onApplyIdentityHeader(string& hdrs, const char* hdr_name, int flags); virtual void onInitialReply(B2BSipReplyEvent *e); diff --git a/apps/sbc/SBCCallProfile.cpp b/apps/sbc/SBCCallProfile.cpp index 876000188..e53178347 100644 --- a/apps/sbc/SBCCallProfile.cpp +++ b/apps/sbc/SBCCallProfile.cpp @@ -358,6 +358,13 @@ bool SBCCallProfile::readFromConfiguration(const string& name, append_headers_req = cfg.getParameter("append_headers_req"); aleg_append_headers_req = cfg.getParameter("aleg_append_headers_req"); + send_user_agent = cfg.getParameter("send_user_agent") == "yes"; + if (send_user_agent && !AmConfig::Signature.empty()) + WARN("SBC profile '%s': send_user_agent=yes will disclose server identity " + "'%s' in User-Agent/Server headers on all outgoing SBC messages. " + "This may expose the server to targeted attacks (RFC 3261 SS20.41/20.35).\n", + name.c_str(), AmConfig::Signature.c_str()); + refuse_with = cfg.getParameter("refuse_with"); rtprelay_enabled = cfg.getParameter("enable_rtprelay"); diff --git a/apps/sbc/SBCCallProfile.h b/apps/sbc/SBCCallProfile.h index 7739dba4c..c4811f908 100644 --- a/apps/sbc/SBCCallProfile.h +++ b/apps/sbc/SBCCallProfile.h @@ -194,6 +194,8 @@ struct SBCCallProfile string append_headers_req; string aleg_append_headers_req; + bool send_user_agent; /**< inject User-Agent/Server identity headers (default: false) */ + string refuse_with; string rtprelay_enabled; @@ -386,7 +388,8 @@ struct SBCCallProfile reg_caching(false), max_491_retry_time(2000), log_rtp(false), - log_sip(false) + log_sip(false), + send_user_agent(false) { } ~SBCCallProfile() diff --git a/apps/sbc/etc/transparent.sbcprofile.conf b/apps/sbc/etc/transparent.sbcprofile.conf index ffbdf62ac..15f26d822 100644 --- a/apps/sbc/etc/transparent.sbcprofile.conf +++ b/apps/sbc/etc/transparent.sbcprofile.conf @@ -76,6 +76,19 @@ #sdp_alinesfilter_list=crypto,x-cap #sdp_anonymize=yes +## User-Agent / Server identity header policy +# +# send_user_agent=yes +# Inject the server identity string (configured via use_default_signature or +# signature in sems.conf) as a User-Agent header on outgoing requests and a +# Server header on outgoing replies. If the upstream UAC already provided a +# User-Agent, it is forwarded as-is; the signature is only added when the +# header is absent. +# Default: no (suppress both headers to prevent software-version disclosure; +# see RFC 3261 §20.41 and §20.35). +# +#send_user_agent=yes + ## append extra headers #append_headers="P-Source-IP: $si\r\nP-Source-Port: $sp\r\n" diff --git a/core/AmB2BSession.cpp b/core/AmB2BSession.cpp index 9137e02e2..79b264af3 100644 --- a/core/AmB2BSession.cpp +++ b/core/AmB2BSession.cpp @@ -431,7 +431,7 @@ void AmB2BSession::updateLocalBody(AmMimeBody& body) if (!sdp) return; if (!sdp->getLen()) { - sdp->clear(); + body.deletePart(SIP_APPLICATION_SDP); return; } diff --git a/core/AmBasicSipDialog.cpp b/core/AmBasicSipDialog.cpp index 87c7f7891..12ae7ee87 100644 --- a/core/AmBasicSipDialog.cpp +++ b/core/AmBasicSipDialog.cpp @@ -541,6 +541,14 @@ int AmBasicSipDialog::onTxRequest(AmSipRequest& req, int& flags) return 0; } +void AmBasicSipEventHandler::onApplyIdentityHeader(string& hdrs, + const char* hdr_name, + int flags) +{ + if (!(flags & SIP_FLAGS_VERBATIM) && AmConfig::Signature.length()) + hdrs += string(hdr_name) + COLSP + AmConfig::Signature + CRLF; +} + int AmBasicSipDialog::onTxReply(const AmSipRequest& req, AmSipReply& reply, int& flags) { @@ -637,11 +645,7 @@ int AmBasicSipDialog::reply(const AmSipRequest& req, return -1; } - if (!(flags & SIP_FLAGS_VERBATIM)) { - // add Signature - if (AmConfig::Signature.length()) - reply.hdrs += SIP_HDR_COLSP(SIP_HDR_SERVER) + AmConfig::Signature + CRLF; - } + if (hdl) hdl->onApplyIdentityHeader(reply.hdrs, SIP_HDR_SERVER, flags); if ((code > 100 && code < 300) && !(flags & SIP_FLAGS_NOCONTACT)) { /* if 300<=code<400, explicit contact setting should be done */ @@ -734,11 +738,7 @@ int AmBasicSipDialog::sendRequest(const string& method, req.contact = getContactHdr(); } - if (!(flags & SIP_FLAGS_VERBATIM)) { - // add Signature - if (AmConfig::Signature.length()) - req.hdrs += SIP_HDR_COLSP(SIP_HDR_USER_AGENT) + AmConfig::Signature + CRLF; - } + if (hdl) hdl->onApplyIdentityHeader(req.hdrs, SIP_HDR_USER_AGENT, flags); int send_flags = 0; if(patch_ruri_next_hop && remote_tag.empty()) { diff --git a/core/AmBasicSipDialog.h b/core/AmBasicSipDialog.h index 4d9179d59..c20cdd96f 100644 --- a/core/AmBasicSipDialog.h +++ b/core/AmBasicSipDialog.h @@ -446,11 +446,27 @@ class AmBasicSipEventHandler /** Hook called before a request is sent */ virtual void onSendRequest(AmSipRequest& req, int& flags) {} - + /** Hook called before a reply is sent */ - virtual void onSendReply(const AmSipRequest& req, + virtual void onSendReply(const AmSipRequest& req, AmSipReply& reply, int& flags) {} + /** + * Hook called by AmBasicSipDialog to apply User-Agent (requests) and Server + * (replies) identity header policy before a message is sent to the transport. + * + * The default implementation reproduces the original SEMS behaviour: inject + * AmConfig::Signature when the header is absent and SIP_FLAGS_VERBATIM is not + * set. Subclasses (e.g. the SBC) may override to enforce a different policy + * such as stripping forwarded identity headers or controlling injection via a + * per-call-profile option. + * + * @param hdrs The outgoing message's extra header block (modifiable). + * @param hdr_name SIP_HDR_USER_AGENT for requests, SIP_HDR_SERVER for replies. + * @param flags Send flags (SIP_FLAGS_*) for the current message. + */ + virtual void onApplyIdentityHeader(string& hdrs, const char* hdr_name, int flags); + /** Hook called after a request has been sent */ virtual void onRequestSent(const AmSipRequest& req) {} diff --git a/core/AmConfig.cpp b/core/AmConfig.cpp index 9b502505d..f5fb879eb 100644 --- a/core/AmConfig.cpp +++ b/core/AmConfig.cpp @@ -471,10 +471,10 @@ int AmConfig::readConfiguration() if (cfg.hasParameter("exclude_payloads")) ExcludePayloads = cfg.getParameter("exclude_payloads"); - // user_agent + // user_agent / server identity if (cfg.getParameter("use_default_signature")=="yes") Signature = DEFAULT_SIGNATURE; - else + else Signature = cfg.getParameter("signature"); if (cfg.hasParameter("max_forwards")) { diff --git a/core/AmConfig.h b/core/AmConfig.h index c0bf1c775..1e7270c67 100644 --- a/core/AmConfig.h +++ b/core/AmConfig.h @@ -211,7 +211,7 @@ struct AmConfig static unsigned int DSCPforRtp; /** Ignore Low CSeq on NOTIFY - for RFC 3265 instead of 5057 */ static bool IgnoreNotifyLowerCSeq; - /** Server/User-Agent header (optional) */ + /** Server/User-Agent header string (empty = not configured) */ static string Signature; /** Value of Max-Forward header field for new requests */ static unsigned int MaxForwards; diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index 9e2d8b050..bd23e8f5d 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -875,11 +875,7 @@ int AmSipDialog::send_200_ack(unsigned int inv_cseq, if(onTxRequest(req,flags) < 0) return -1; - if (!(flags&SIP_FLAGS_VERBATIM)) { - // add Signature - if (AmConfig::Signature.length()) - req.hdrs += SIP_HDR_COLSP(SIP_HDR_USER_AGENT) + AmConfig::Signature + CRLF; - } + if (hdl) hdl->onApplyIdentityHeader(req.hdrs, SIP_HDR_USER_AGENT, flags); int res = SipCtrlInterface::send(req, local_tag, remote_tag.empty() || !next_hop_1st_req ? diff --git a/core/etc/sems.conf.sample b/core/etc/sems.conf.sample index 6ae7a2b99..0c61ee1b6 100644 --- a/core/etc/sems.conf.sample +++ b/core/etc/sems.conf.sample @@ -465,7 +465,7 @@ loglevel=2 # optional parameter: use_default_signature={yes|no} # -# - use a Server/User-Agent header with the SEMS server +# - use a Server/User-Agent header with the SEMS server # signature and version. # # default=no diff --git a/core/md5.cpp b/core/md5.cpp index e36082b57..36c1a162e 100644 --- a/core/md5.cpp +++ b/core/md5.cpp @@ -57,9 +57,9 @@ documentation and/or software. #define S43 15 #define S44 21 -static void MD5Transform(UINT4 [4], unsigned char [64]); +static void MD5Transform(UINT4 [4], const unsigned char [64]); static void Encode(unsigned char *, UINT4 *, unsigned int); -static void Decode(UINT4 *, unsigned char *, unsigned int); +static void Decode(UINT4 *, const unsigned char *, unsigned int); static void MD5_memcpy(POINTER, POINTER, unsigned int); static void MD5_memset(POINTER, int, unsigned int); @@ -122,7 +122,7 @@ void MD5Init (MD5_CTX *context) context. */ void MD5Update (MD5_CTX *context, /* context */ - unsigned char *input, /* input block */ + const unsigned char *input, /* input block */ unsigned int inputLen /* length of input block */ ) { @@ -191,7 +191,7 @@ void MD5Final (unsigned char digest[16], MD5_CTX *context) /* MD5 basic transformation. Transforms state based on block. */ -static void MD5Transform (UINT4 state[4], unsigned char block[64]) +static void MD5Transform (UINT4 state[4], const unsigned char block[64]) { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; @@ -297,7 +297,7 @@ static void Encode (unsigned char *output, UINT4 *input, unsigned int len) /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ -static void Decode (UINT4 *output, unsigned char *input, unsigned int len) +static void Decode (UINT4 *output, const unsigned char *input, unsigned int len) { unsigned int i, j; diff --git a/core/md5.h b/core/md5.h index 1552a089c..ed73ae000 100644 --- a/core/md5.h +++ b/core/md5.h @@ -36,6 +36,6 @@ typedef struct { } MD5_CTX; void MD5Init(MD5_CTX *); -void MD5Update(MD5_CTX *, unsigned char *, unsigned int); +void MD5Update(MD5_CTX *, const unsigned char *, unsigned int); void MD5Final(unsigned char [16], MD5_CTX *); #endif /* MD5_H */