diff --git a/config.yaml b/config.yaml index caf56988..d7580585 100644 --- a/config.yaml +++ b/config.yaml @@ -79,6 +79,15 @@ hss: - 'scscf.ims.mnc001.mcc001.3gppnetwork.org' roaming: + inbound: + # How to handle unknown IMSIs when inbound roaming. Valid options are: + # IMSI_UNKNOWN - Reject the request with the "IMSI_UNKNOWN" error code. + # ROAMING_NOT_ALLOWED - Reject the request with the "ROAMING_NOT_ALLOWED" error code. + # The latter is useful when operating a private network and public SIMs should not be allowed to connect. + # "Roaming not allowed" will cause the UE to not try again on this network. + # "Imsi unknown" may cause the UE to believe that its subscription is invalid. + # For private networks, "ROAMING_NOT_ALLOWED" is recommended. Otherwise, use "IMSI_UNKNOWN". + reject_unknown_imsis_with: "ROAMING_NOT_ALLOWED" outbound: # Whether or not to a subscriber to connect to an undefined network when outbound roaming. allow_undefined_networks: True diff --git a/docker/.env b/docker/.env index 318b63c4..0c9a49a6 100644 --- a/docker/.env +++ b/docker/.env @@ -26,6 +26,7 @@ HSS_DSR_EXTERNAL_IDENTIFIER=example HSS_IGNORE_PURGE_UE_REQUEST=False HSS_SCSCF_POOL=scscf.ims.mnc001.mcc001.3gppnetwork.org HSS_ROAMING_ALLOW_UNDEFINED_NETWORKS=True +HSS_ROAMING_REJECT_UNKNOWN_IMSIS_WITH="ROAMING_NOT_ALLOWED" HSS_SCTP_RTO_MAX=5000 HSS_SCTP_RTO_MIN=500 HSS_SCTP_RTO_INITIAL=1000 diff --git a/docker/config.yaml b/docker/config.yaml index 3644cc99..74ff10c7 100644 --- a/docker/config.yaml +++ b/docker/config.yaml @@ -79,6 +79,15 @@ hss: - "${HSS_SCSCF_POOL:-scscf.ims.mnc001.mcc001.3gppnetwork.org}" roaming: + inbound: + # How to handle unknown IMSIs when inbound roaming. Valid options are: + # IMSI_UNKNOWN - Reject the request with the "IMSI_UNKNOWN" error code. + # ROAMING_NOT_ALLOWED - Reject the request with the "ROAMING_NOT_ALLOWED" error code. + # The latter is useful when operating a private network and public SIMs should not be allowed to connect. + # "Roaming not allowed" will cause the UE to not try again on this network. + # "Imsi unknown" may cause the UE to believe that its subscription is invalid. + # For private networks, "ROAMING_NOT_ALLOWED" is recommended. Otherwise, use "IMSI_UNKNOWN". + reject_unknown_imsis_with: "${HSS_ROAMING_REJECT_UNKNOWN_IMSIS_WITH:-ROAMING_NOT_ALLOWED}" outbound: # Whether or not to a subscriber to connect to an undefined network when outbound roaming. allow_undefined_networks: ${HSS_ROAMING_ALLOW_UNDEFINED_NETWORKS:-True} diff --git a/lib/diameter.py b/lib/diameter.py index e220d03d..01963194 100755 --- a/lib/diameter.py +++ b/lib/diameter.py @@ -130,6 +130,13 @@ def __init__( ] + @staticmethod + def get_unknown_imsi_reject_cause() -> int: + if config['hss']['roaming']['inbound']['reject_unknown_imsis_with'] == 'ROAMING_NOT_ALLOWED': + return 5004 # DIAMETER_ERROR_ROAMING_NOT_ALLOWED + return 5001 # DIAMETER_ERROR_USER_UNKNOWN + + #Generates rounding for calculating padding def myround(self, n, base=4): if(n > 0): @@ -2244,7 +2251,7 @@ def Answer_16777251_318(self, packet_vars, avps): usePrefix=True, prefixHostname=self.hostname, prefixServiceName='metric') - #Handle if the subscriber is not present in HSS return "DIAMETER_ERROR_USER_UNKNOWN" + #Handle if the subscriber is not present in HSS return the appropriate error self.logTool.log(service='HSS', level='debug', message="Subscriber " + str(imsi) + " is unknown in database", redisClient=self.redisMessaging) avp = '' session_id = self.get_avp_data(avps, 263)[0] #Get Session-ID @@ -2255,7 +2262,7 @@ def Answer_16777251_318(self, packet_vars, avps): #Experimental Result AVP(Response Code for Failure) avp_experimental_result = '' avp_experimental_result += self.generate_vendor_avp(266, 40, 10415, '') #AVP Vendor ID - avp_experimental_result += self.generate_avp(298, 40, self.int_to_hex(5001, 4)) #AVP Experimental-Result-Code: DIAMETER_ERROR_USER_UNKNOWN (5001) + avp_experimental_result += self.generate_avp(298, 40, self.int_to_hex(self.get_unknown_imsi_reject_cause(), 4)) #AVP Experimental-Result-Code: DIAMETER_ERROR_USER_UNKNOWN (5001) or DIAMETER_ERROR_ROAMING_NOT_ALLOWED (5004) avp += self.generate_avp(297, 40, avp_experimental_result) #AVP Experimental-Result(297) avp += self.generate_avp(277, 40, "00000001") #Auth-Session-State diff --git a/lib/gsup/controller/air.py b/lib/gsup/controller/air.py index f1e6e210..49655e87 100644 --- a/lib/gsup/controller/air.py +++ b/lib/gsup/controller/air.py @@ -13,6 +13,7 @@ from logtool import LogTool from utils import validate_imsi, InvalidIMSI +from pyhss_config import config class AIRController(GsupController): def __init__(self, logger: LogTool, database: Database): @@ -27,6 +28,13 @@ def get_num_vectors_req(self, message: dict): return max_num return ret + @staticmethod + def _get_unknown_subscriber_reject_cause() -> GMMCause: + if config['hss']['roaming']['inbound']['reject_unknown_imsis_with'] == 'ROAMING_NOT_ALLOWED': + return GMMCause.ROAMING_NOTALLOWED + else: + return GMMCause.IMSI_UNKNOWN + async def handle_message(self, peer: IPAPeer, message: GsupMessage): request_dict = message.to_dict() imsi = GsupMessageUtil.get_first_ie_by_name(GsupMessageUtil.GSUP_MSG_IE_IMSI, request_dict) @@ -79,7 +87,7 @@ async def handle_message(self, peer: IPAPeer, message: GsupMessage): peer, GsupMessageBuilder().with_msg_type(MsgType.SEND_AUTH_INFO_ERROR) .with_ie('imsi', imsi) - .with_ie('cause', GMMCause.IMSI_UNKNOWN.value) + .with_ie('cause', self._get_unknown_subscriber_reject_cause().value) .build(), ) except Exception as e: diff --git a/tests/config.yaml b/tests/config.yaml index d400a6bc..8e957ee5 100644 --- a/tests/config.yaml +++ b/tests/config.yaml @@ -30,6 +30,8 @@ hss: - 'scscf.ims.mnc001.mcc001.3gppnetwork.org' roaming: + inbound: + reject_unknown_imsis_with: "ROAMING_NOT_ALLOWED" outbound: allow_undefined_networks: True