Skip to content

Repository files navigation

VectorCore HSS

A high-performance Home Subscriber Server (HSS), PCRF, HLR, UDM, UDR, and PCF for 3GPP 2G/3G, LTE/4G, 5GC, and IMS networks, written in Go.


Features

  • Multi-interface Diameter server - S6a, S6c, S13, Cx, Sh, Gx, Rx, SWx, SLh, Zh on a single TCP/SCTP listener
  • GSUP/HLR - Osmocom IPA+GSUP server (port 4222) for OsmoMSC/OsmoSGSN; handles SendAuthInfo, UpdateLocation, PurgeMS; generates 2G triplets and 3G quintuplets for CSFB voice and SGs SMS
  • SMS routing (S6c) - Send-Routing-Info-for-SM (SRI-SM) resolves MSISDN to serving MME for MT SMS delivery via SGd/T4; Report-SM-Delivery-Status (RSDS) stores Message Waiting Data on delivery failure; Alert-Service-Centre (ALSC) is HSS-initiated and fires automatically when the subscriber re-attaches; SMS-in-MME registration state (MME-Number-for-MT-SMS, MME-Registered-for-SMS) tracked per subscriber via ULR
  • 5GC UDM, UDR, and PCF - N13, N10, N8, N15, and N7 support over a shared SBI listener; UDM, UDR, and PCF are co-located in one process with in-process data sharing; nudr-dr / N36 endpoints are exposed for internal service-to-service use
  • Milenage authentication - EUTRAN vector generation (AIR), EAP-AKA vector generation (SWx MAR), GBA vector generation (Zh MAR); custom c/r constant profiles per-AUC
  • Atomic SQN management - SELECT FOR UPDATE prevents SQN races during concurrent AIR from multiple MMEs
  • In-memory read cache - 60-second TTL cache on AUC and Subscriber hot paths
  • 5G NSA support - Access-Restriction-Data bitmask per subscriber controls NR secondary RAT access
  • GeoRed - Active-active N-node geographic redundancy over HTTP/2 with batched event replication; replicates OAM changes and dynamic state (SQN, serving MME/SGSN, Gx sessions) across nodes
  • TAC database - GSMA IMEI Type Allocation Code database loaded into memory at startup; enriches EIR history with device make and model
  • OAM REST API - Full CRUD over all subscriber data; OpenAPI 3.1 spec with interactive docs at /api/v1/docs
  • Prometheus metrics - Diameter request counters and latency histograms at GET /metrics
  • Dual transport - TCP always on; SCTP optional (requires kernel SCTP module)
  • PostgreSQL + SQLite - Production on PostgreSQL; SQLite for testing
  • GORM AutoMigrate - Schema is created or updated on startup; safe to run against existing data
  • Structured logging - JSON via go.uber.org/zap

Diameter Interfaces

S6a - LTE HSS <-> MME (3GPP TS 29.272)

CommandDirectionDescription
AIR / AIAMME -> HSSAuthentication-Information - generates Milenage EUTRAN vectors (RAND, XRES, AUTN, KASME). Supports 1-5 vectors per request and SQN re-synchronisation via AUTS.
ULR / ULAMME -> HSSUpdate-Location - registers the serving MME; returns full Subscription-Data (UE-AMBR, NAM, MSISDN, APN-Configuration-Profile with per-APN QoS).
PUR / PUAMME -> HSSPurge-UE - clears the serving MME on UE detach.
NOR / NOAMME -> HSSNotify - handles flags-only UE state changes (e.g. UE reachability, MPS registration).
CLR / CLAHSS -> MMECancel-Location - sent to the old MME when a subscriber re-attaches to a new one.
IDR / IDAHSS -> MMEInsert-Subscriber-Data - pushes updated subscription data to the serving MME.
DSR / DSAHSS -> MMEDelete-Subscriber-Data - instructs MME to remove subscription data.
RSR / RSAHSS -> MMEReset - instructs MME to re-authenticate all subscribers after a reset.

S13 - Equipment Identity Register (3GPP TS 29.272)

CommandDirectionDescription
ECR / ECAMME -> HSSME-Identity-Check - checks IMEI against the EIR table; returns WHITELISTED (0), BLACKLISTED (1), or GREYLISTED (2). Supports exact and regex match modes. IMSI/IMEI pairs are optionally logged to eir_history.

S6c - SMS Routing HSS <-> SMS-SC (3GPP TS 29.338)

CommandDirectionDescription
SRI-SM / SRI-SMASMS-SC -> HSSSend-Routing-Info-for-SM - looks up subscriber by MSISDN (or IMSI, BCD-encoded on the wire); returns IMSI, serving MME address and realm, and MME-Number-for-MT-SMS so the SMS-SC can route the MT SMS via SGd/T4. Returns MWD-Status flags if message waiting data is pending.
RSDS / RSDSASMS-SC -> HSSReport-SM-Delivery-Status - on delivery failure (absent subscriber or memory-capacity exceeded) stores a Message Waiting Data record keyed to the SMS-SC; on successful delivery clears the MWD record. Supports MNRF and MCEF status flags per TS 29.338 §5.3.2.4.
ALSC / ALSCAHSS -> SMS-SCAlert-Service-Centre - HSS-initiated; sent to each SMS-SC with a pending MWD record when the subscriber re-attaches (triggered by ULR success). MWD is deleted only after the SMS-SC returns Result-Code 2001; if the peer is unreachable the MWD is left in place and retried on the next ULR.

The ULR handler on S6a detects SMS-in-MME capability from ULR-Flags and the MME-Number-for-MT-SMS AVP, stores the registration state on the subscriber record, and sets the MME-Registered-for-SMS bit in ULA-Flags. SRI-SM returns this MME number in the Serving-Node grouped AVP so the SMS-SC can route directly to the MME.

Cx - IMS HSS <-> CSCF (3GPP TS 29.228 / 29.229)

CommandDirectionDescription
UAR / UAACSCF -> HSSUser-Authorization - checks if a public identity is allowed to register at the requesting CSCF.
SAR / SAACSCF -> HSSServer-Assignment - records the S-CSCF serving a public identity; returns the IMS subscriber's Cx User-Data XML including IFC.
LIR / LIACSCF -> HSSLocation-Info - returns the S-CSCF name for a given public identity.
MAR / MAACSCF -> HSSMultimedia-Authentication - generates SIP Digest or AKA authentication data.
RTRHSS -> CSCFRegistration-Termination - forces de-registration of a public identity.
PPRHSS -> CSCFPush-Profile - pushes an updated IMS profile to the serving CSCF.

Sh - IMS HSS <-> Application Server (3GPP TS 29.328 / 29.329)

CommandDirectionDescription
UDR / UDAAS -> HSSUser-Data - returns Sh-Data XML (AVP 702) for a subscriber. Dynamically renders IMPU, IMPI, S-CSCF name, IMS user state, and IFC (IFC only returned for Data-Reference=13). Supports RepositoryData (AS-stored blob) and all standard Data-Reference values (0, 10-17).
PNR / PNAHSS -> ASPush-Notification - pushes updated subscriber data to the Application Server.

Gx - PCRF <-> PGW (3GPP TS 29.212)

CommandDirectionDescription
CCR / CCAPGW -> HSSCredit-Control - handles session establishment (CCR-I), modification (CCR-U), and termination (CCR-T). Tracks active PGW sessions in serving_apn.
RAR / RAAHSS -> PGWRe-Auth - installs or removes dedicated bearers on an active Gx session; triggered by AAR/STR from the P-CSCF via Rx.

Rx - P-CSCF <-> PCRF (3GPP TS 29.214)

CommandDirectionDescription
AAR / AAAP-CSCF -> HSSAA-Request - provisions QoS resources for a VoLTE media session; triggers a Gx RAR to the PGW to install a dedicated bearer.
STR / STAP-CSCF -> HSSSession-Termination - tears down the Rx session and triggers a Gx RAR to the PGW to remove the dedicated bearer.

SWx - AAA Server <-> HSS for non-3GPP WiFi (3GPP TS 29.273)

CommandDirectionDescription
MAR / MAAAAA -> HSSMultimedia-Authentication - generates EAP-AKA vectors (RAND, XRES, AUTN, CK, IK) for non-3GPP WiFi authentication.
SAR / SAAAAA -> HSSServer-Assignment - returns Non-3GPP-User-Data (access allowed or barred based on subscriber status).
RTRHSS -> AAARegistration-Termination - de-registers a non-3GPP session.
PPRHSS -> AAAPush-Profile - pushes an updated non-3GPP access profile to the AAA server.

SLh - GMLC <-> HSS for Location Services (3GPP TS 29.173)

CommandDirectionDescription
RIR / RIAGMLC -> HSSLCS-Routing-Info-Request/Answer (application ID 16777291, command code 8388622) returns serving-node routing information.

The GMLC uses the returned MME identity to route its SLg PLR to the MME. The HSS learns LTE MME name and realm from S6a ULR registration state. An attached subscriber returns MME-Name and MME-Realm; an existing subscriber without a usable serving node returns DIAMETER_ERROR_ABSENT_USER (4201), and an unknown subscriber returns DIAMETER_ERROR_USER_UNKNOWN (5001).

SLh authorizes the requesting GMLC by Origin-Realm, compared case insensitively with a trailing dot normalized. The HSS's own OriginRealm is always authorized. hss.SLhAuthorizedRealms adds specific external GMLC realms; an empty list authorizes no external realm. Unauthorized requests return DIAMETER_ERROR_UNAUTHORIZED_REQUESTING_NETWORK (5490). SLh normally uses SCTP; set hss.EnableSCTP: true (and provide kernel SCTP support) to enable the shared SCTP listener. TCP remains available for the other shared Diameter interfaces and lab interoperability.

Zh - BSF <-> HSS for GBA (3GPP TS 29.109)

CommandDirectionDescription
MAR / MAABSF -> HSSMultimedia-Authentication - generates GBA bootstrapping vectors for Generic Bootstrapping Architecture.

GSUP / HLR Interface

The GSUP server (port 4222 by default) implements the Osmocom IPA+GSUP protocol for 2G/3G circuit-switched authentication. It is used by OsmoMSC, OsmoSGSN, and OsmoSTP for CSFB voice and SGs SMS handling.

MessageDirectionDescription
SendAuthInfoMSC/SGSN -> HSSGenerates 2G triplets (RAND, SRES, Kc) or 3G quintuplets (RAND, XRES, CK, IK, AUTN) from Milenage.
UpdateLocationMSC/SGSN -> HSSRegisters the serving MSC or SGSN; returns subscriber data.
PurgeMSMSC/SGSN -> HSSClears the serving MSC/SGSN on detach.

Geographic Redundancy (GeoRed)

VectorCore HSS supports active-active N-node geographic redundancy. Each node replicates changes to its peers over HTTP/2 using batched event streams.

Two replication tracks are supported:

  • OAM sync - subscriber, AUC, APN, IMS subscriber, and EIR record changes
  • State sync - SQN increments, serving MME/SGSN assignments, Gx sessions

Events are batched by count (default 500) or age (default 10 ms) and delivered to each peer with bearer token authentication. Nodes are symmetric - any node can accept writes and will replicate to all others.


Roaming Control

Roaming is enforced at the Diameter layer on both AIR and ULR. When a subscriber attaches via a visited PLMN the HSS evaluates the following rules in order:

  1. Home network - always allowed (visited PLMN matches home MCC/MNC).
  2. Subscriber roaming switch - if roaming_enabled = false on the subscriber record the attach is rejected with ROAMING_NOT_ALLOWED.
  3. Network rule - the visited MCC/MNC is looked up in roaming_rules. If a matching rule exists its allow flag is applied.
  4. Undefined networks - if no rule matches, the roaming.allow_undefined_networks config flag controls whether the attach is permitted (default: true).

Roaming rules are managed via the OAM REST API (/api/v1/roaming_rules).

Config flag:

roaming:
allow_undefined_networks: true # allow roaming on networks with no explicit rule

OAM REST API

Served on port 8080 (configurable). Interactive documentation at http://<host>:8080/api/v1/docs.

See docs/api.md for the full reference.

ResourcePathDescription
APN/api/v1/apnAccess Point Name profiles
AUC/api/v1/subscriber/aucAuthentication Center (Ki, OPc, AMF, SQN)
Algorithm Profile/api/v1/subscriber/auc/profileCustom Milenage c/r constant sets
Subscriber/api/v1/subscriberEPC subscriber profiles
IMS Subscriber/api/v1/ims_subscriberIMS subscriber profiles
IFC Profile/api/v1/ims_subscriber/ifc_profileInitial Filter Criteria XML blobs
EIR/api/v1/eirEquipment Identity Register entries
EIR History/api/v1/eir/historyIMSI/IMEI audit log (read-only)
Roaming Rules/api/v1/roaming_rulesPer-network allow/deny rules enforced on AIR and ULR
Charging Rule/api/v1/apn/charging_ruleGx charging rules
TFT/api/v1/apn/charging_rule/tftTraffic Flow Templates
Subscriber Routing/api/v1/subscriber/routingStatic IP assignments per subscriber+APN
Serving APN/api/v1/oam/serving_apnActive PGW sessions
Subscriber Attributes/api/v1/subscriber/attributesKey-value store per subscriber
Emergency Subscriber/api/v1/oam/emergency_subscriberEmergency session tracking
Operation Log/api/v1/oam/operation_logAudit trail (read-only)
GeoRed Status/api/v1/geored/statusActive replication peer status
GeoRed Sync/api/v1/geored/syncTrigger a full resync to all peers

Quick Start

Prerequisites

  • Go 1.25+
  • PostgreSQL 14+ (or SQLite for testing)

Build

make build

Output: bin/hss

Configure

The full config.yaml with all sections:

hss:
OriginHost: hss01.epc.mnc001.mcc001.3gppnetwork.orgOriginRealm: epc.mnc001.mcc001.3gppnetwork.orgBindAddress: "::"BindPort: 3868EnableSCTP: false # set true to also listen on SCTP (requires kernel sctp module)DWRInterval: 30CancelLocationRequest_Enabled: trueMCC: "001"MNC: "01"scscf_pool:
- 'sip:scscf.ims.mnc001.mcc001.3gppnetwork.org'# TLSCertFile: /etc/hss/tls/cert.pem # uncomment for DiameterTLS (RFC 6733)# TLSKeyFile: /etc/hss/tls/key.pemdatabase:
db_type: postgresqlserver: localhostport: 5432username: hsspassword: hssdatabase: hsspool_size: 30pool_idle: 10pool_recycle: 300logging:
# Supported levels: debug, info, warn, errorlevel: infofile: /var/log/hss.log # write logs to this file (comment out to disable)# Use -d flag to force debug level and enable console outputeir:
# no_match_response: response code when an IMEI has no matching EIR rule.# EIR response codes (3GPP TS 29.272 §7.3.51 Equipment-Status):# 0 = WHITELISTED device is allowed (default)# 1 = BLACKLISTED device is denied# 2 = GREYLISTED device is allowed with operator-defined restrictionsno_match_response: 0imsi_imei_logging: true# tac_db_enabled loads the GSMA Type Allocation Code (IMEI device database)# into memory and enriches EIR history with device make/model.# NOTE: TAC here = IMEI Type Allocation Code, NOT the RAN Tracking Area Code.tac_db_enabled: truegeored:
enabled: falsenode_id: "hss01"# unique identifier for this node (required when enabled)listen_port: 9869# inter-node listener port (h2c or TLS)bearer_token: "changeme"# shared token for inter-node auth# tls_cert_file: "" # leave blank for cleartext h2c# tls_key_file: ""sync_oam: true # replicate OAM changes (subscriber, AUC, APN, IMS, EIR)sync_state: true # replicate dynamic state (SQN, serving MME/SGSN, Gx sessions)batch_max_events: 500# flush batch after this many eventsbatch_max_age_ms: 10# flush batch after this many millisecondsqueue_size: 10000# per-peer outbound queue depthperiodic_sync_interval_s: 0# 0 = disabled; >0 triggers a full resync every N secondspeers: []# peers:# - node_id: "hss02"# address: "192.168.1.2:9869"# bearer_token: "changeme"gsup:
# GSUP/HLR listener for Osmocom MSC/SGSN (OsmoMSC, OsmoSGSN).# Used for 2G/3G circuit-switched auth: SGs SMS and CSFB voice.# Protocol: Osmocom IPA + GSUP over TCP (default port 4222).enabled: truebind_address: "::"bind_port: 42225gc:
sbi:
bind_address: "::"bind_port: 7777# Optional TLS for HTTPS + HTTP/2.# tls_cert_file: /etc/hss/tls/5gc.crt# tls_key_file: /etc/hss/tls/5gc.keyoauth2_enabled: falseoauth2_bypass: trueclient:
mode: directscp_address: ""# used when mode: scp# Fixed delay between NRF registration retry attempts.reconnect_holdoff_time: 2sudm:
enabled: falsemcc: "001"mnc: "01"nrf_address: ""nf_instance_id: ""suci_decryption_keys: []pcf:
enabled: falsemcc: "001"mnc: "01"nrf_address: ""nf_instance_id: ""api:
enabled: truebind_address: "::"bind_port: 8080# tls_cert_file: /etc/hss/tls/cert.pem # uncomment for HTTPS# tls_key_file: /etc/hss/tls/key.pemauth_enabled: falseapi_keys: []# api_keys:# - "your-secret-key-here"

Run

./bin/hss -c config.yaml

On startup the server will:

  1. Connect to PostgreSQL and run AutoMigrate on all tables
  2. Load the GSMA TAC database into memory (if tac_db_enabled)
  3. Start the Diameter listener on TCP port 3868 (and SCTP if enabled)
  4. Start the GSUP/HLR listener on TCP port 4222 (if enabled)
  5. Start the shared 5GC SBI listener on port 7777 for UDM/UDR/PCF (if enabled)
  6. Start the OAM REST API on port 8080 (if enabled)
  7. Start the GeoRed replication listener on port 9869 (if enabled)

Provision a subscriber

BASE=http://localhost:8080
# 1. Create APN
APN_ID=$(curl -s -X POST $BASE/apn \ -H "Content-Type: application/json" \ -d '{"apn":"internet","apn_ambr_dl":999999999,"apn_ambr_ul":999999999,"ip_version":0}' \| python3 -c "import sys,json; print(json.load(sys.stdin)['apn_id'])")# 2. Create AUC (replace Ki/OPc with your SIM values)
AUC_ID=$(curl -s -X POST $BASE/auc \ -H "Content-Type: application/json" \ -d '{"ki":"465B5CE8B199B49FAA5F0A2EE238A6BC","opc":"E8ED289DEBA952E4283B54E88E6183CA","amf":"8000","imsi":"001010000000001"}' \| python3 -c "import sys,json; print(json.load(sys.stdin)['auc_id'])")# 3. Create EPC subscriber
curl -s -X POST $BASE/subscriber \
-H "Content-Type: application/json" \
-d "{\"imsi\":\"001010000000001\",\"auc_id\":$AUC_ID,\"default_apn\":$APN_ID,\"apn_list\":\"$APN_ID\",\"msisdn\":\"0000000001\"}"# 4. Create IMS subscriber (links to EPC subscriber by MSISDN)
curl -s -X POST $BASE/ims_subscriber \
-H "Content-Type: application/json" \
-d '{"msisdn":"0000000001","imsi":"001010000000001"}'

Architecture

MME / CSCF / PGW / AAA / AS / BSF / GMLC (Diameter peers)
|
+-- internal/diameter/server.go StateMachine, handler wiring, TCP/SCTP listener
|
+-- internal/diameter/s6a/ AIR, ULR, PUR, NOR; HSS-originated CLR, IDR, DSR, RSR
+-- internal/diameter/s6c/ SRI-SM, RSDS; HSS-originated ALSC (SMS routing + MWD)
+-- internal/diameter/s13/ ECR (EIR check)
+-- internal/diameter/cx/ UAR, SAR, LIR, MAR; HSS-originated RTR, PPR
+-- internal/diameter/sh/ UDR; HSS-originated PNR
+-- internal/diameter/gx/ CCR; HSS-originated RAR
+-- internal/diameter/rx/ AAR, STR; triggers Gx RAR to PGW for VoLTE bearers
+-- internal/diameter/swx/ MAR, SAR; HSS-originated RTR, PPR
+-- internal/diameter/slh/ RIR/RIA (GMLC location routing)
+-- internal/diameter/zh/ MAR (GBA bootstrapping)
OsmoMSC / OsmoSGSN (GSUP)
|
+-- internal/gsup/ SendAuthInfo, UpdateLocation, PurgeMS over IPA+GSUP
internal/crypto/auth.go Milenage: EUTRAN vectors, EAP-AKA, 2G/3G triplets/quintuplets
internal/ims/shprofile.go 3GPP TS 29.328 Sh-Data XML renderer (IMPU, IMPI, SCSCF, IFC)
internal/ims/cxprofile.go 3GPP TS 29.228 Cx User-Data XML renderer
internal/repository/postgres/store.go Repository: PostgreSQL via GORM + sync.Map cache (60s TTL)
internal/geored/ Active-active N-node replication over HTTP/2
internal/api/ OAM REST API (huma/v2, chi, OpenAPI 3.1)
internal/metrics/ Prometheus counters and histograms
internal/taccache/ GSMA TAC database in-memory cache

Request flow (AIR example):

AIR received on TCP/SCTP
-> server.go logging, metrics wrap, peer tracking
-> s6a/air.go parse request, validate IMSI
-> repository GetAUCByIMSI (cache hit or PostgreSQL)
-> crypto/auth.go GenerateEUTRANVectors (Milenage x N)
-> repository AtomicGetAndIncrementSQN (SELECT FOR UPDATE)
-> s6a/air.go build AIA with E-UTRAN-Vector AVPs
-> geored PublishSQNUpdate (replicate to peers if GeoRed enabled)
-> server.go write AIA to connection

Technology Stack

ComponentLibrary
Diameter protocolgithub.com/fiorix/go-diameter/v4
Milenage / EAP-AKAgithub.com/emakeev/milenage
ORMgorm.io/gorm + gorm.io/driver/postgres
REST API frameworkgithub.com/danielgtaylor/huma/v2 (OpenAPI 3.1)
HTTP routergithub.com/go-chi/chi/v5
Metricsgithub.com/prometheus/client_golang
Logginggo.uber.org/zap
Configgopkg.in/yaml.v3

Database

Supports PostgreSQL (production) and SQLite (testing). Set database.db_type to postgresql or sqlite in config.yaml. GORM AutoMigrate runs on every startup - it is additive-only and safe to run against an existing PyHSS database.

Tables:apn, auc, algorithm_profile, subscriber, subscriber_routing, serving_apn, ims_subscriber, ifc_profile, roaming_network, roaming_rule, emergency_subscriber, charging_rule, tft, eir, eir_history, subscriber_attributes, operation_log, message_waiting_data


Documentation

DocumentDescription
docs/api.mdFull OAM REST API reference - all endpoints, fields, and curl examples

About

Home Subscriber Server (HSS),PCRF,EIR,HLR,UDM,UDR and PCF for 3GPP 2/3G LTE/4G 5GC and IMS

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages