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.
- 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
| Command | Direction | Description |
|---|---|---|
| AIR / AIA | MME -> HSS | Authentication-Information - generates Milenage EUTRAN vectors (RAND, XRES, AUTN, KASME). Supports 1-5 vectors per request and SQN re-synchronisation via AUTS. |
| ULR / ULA | MME -> HSS | Update-Location - registers the serving MME; returns full Subscription-Data (UE-AMBR, NAM, MSISDN, APN-Configuration-Profile with per-APN QoS). |
| PUR / PUA | MME -> HSS | Purge-UE - clears the serving MME on UE detach. |
| NOR / NOA | MME -> HSS | Notify - handles flags-only UE state changes (e.g. UE reachability, MPS registration). |
| CLR / CLA | HSS -> MME | Cancel-Location - sent to the old MME when a subscriber re-attaches to a new one. |
| IDR / IDA | HSS -> MME | Insert-Subscriber-Data - pushes updated subscription data to the serving MME. |
| DSR / DSA | HSS -> MME | Delete-Subscriber-Data - instructs MME to remove subscription data. |
| RSR / RSA | HSS -> MME | Reset - instructs MME to re-authenticate all subscribers after a reset. |
| Command | Direction | Description |
|---|---|---|
| ECR / ECA | MME -> HSS | ME-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. |
| Command | Direction | Description |
|---|---|---|
| SRI-SM / SRI-SMA | SMS-SC -> HSS | Send-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 / RSDSA | SMS-SC -> HSS | Report-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 / ALSCA | HSS -> SMS-SC | Alert-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.
| Command | Direction | Description |
|---|---|---|
| UAR / UAA | CSCF -> HSS | User-Authorization - checks if a public identity is allowed to register at the requesting CSCF. |
| SAR / SAA | CSCF -> HSS | Server-Assignment - records the S-CSCF serving a public identity; returns the IMS subscriber's Cx User-Data XML including IFC. |
| LIR / LIA | CSCF -> HSS | Location-Info - returns the S-CSCF name for a given public identity. |
| MAR / MAA | CSCF -> HSS | Multimedia-Authentication - generates SIP Digest or AKA authentication data. |
| RTR | HSS -> CSCF | Registration-Termination - forces de-registration of a public identity. |
| PPR | HSS -> CSCF | Push-Profile - pushes an updated IMS profile to the serving CSCF. |
| Command | Direction | Description |
|---|---|---|
| UDR / UDA | AS -> HSS | User-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 / PNA | HSS -> AS | Push-Notification - pushes updated subscriber data to the Application Server. |
| Command | Direction | Description |
|---|---|---|
| CCR / CCA | PGW -> HSS | Credit-Control - handles session establishment (CCR-I), modification (CCR-U), and termination (CCR-T). Tracks active PGW sessions in serving_apn. |
| RAR / RAA | HSS -> PGW | Re-Auth - installs or removes dedicated bearers on an active Gx session; triggered by AAR/STR from the P-CSCF via Rx. |
| Command | Direction | Description |
|---|---|---|
| AAR / AAA | P-CSCF -> HSS | AA-Request - provisions QoS resources for a VoLTE media session; triggers a Gx RAR to the PGW to install a dedicated bearer. |
| STR / STA | P-CSCF -> HSS | Session-Termination - tears down the Rx session and triggers a Gx RAR to the PGW to remove the dedicated bearer. |
| Command | Direction | Description |
|---|---|---|
| MAR / MAA | AAA -> HSS | Multimedia-Authentication - generates EAP-AKA vectors (RAND, XRES, AUTN, CK, IK) for non-3GPP WiFi authentication. |
| SAR / SAA | AAA -> HSS | Server-Assignment - returns Non-3GPP-User-Data (access allowed or barred based on subscriber status). |
| RTR | HSS -> AAA | Registration-Termination - de-registers a non-3GPP session. |
| PPR | HSS -> AAA | Push-Profile - pushes an updated non-3GPP access profile to the AAA server. |
| Command | Direction | Description |
|---|---|---|
| LRR / LRA | E-CSCF -> HSS | LCS-Routing-Info - returns routing information for emergency location services. |
| Command | Direction | Description |
|---|---|---|
| MAR / MAA | BSF -> HSS | Multimedia-Authentication - generates GBA bootstrapping vectors for Generic Bootstrapping Architecture. |
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.
| Message | Direction | Description |
|---|---|---|
| SendAuthInfo | MSC/SGSN -> HSS | Generates 2G triplets (RAND, SRES, Kc) or 3G quintuplets (RAND, XRES, CK, IK, AUTN) from Milenage. |
| UpdateLocation | MSC/SGSN -> HSS | Registers the serving MSC or SGSN; returns subscriber data. |
| PurgeMS | MSC/SGSN -> HSS | Clears the serving MSC/SGSN on detach. |
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 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:
- Home network - always allowed (visited PLMN matches home MCC/MNC).
- Subscriber roaming switch - if
roaming_enabled = falseon the subscriber record the attach is rejected with ROAMING_NOT_ALLOWED. - Network rule - the visited MCC/MNC is looked up in
roaming_rules. If a matching rule exists itsallowflag is applied. - Undefined networks - if no rule matches, the
roaming.allow_undefined_networksconfig 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 ruleServed on port 8080 (configurable). Interactive documentation at http://<host>:8080/api/v1/docs.
See docs/api.md for the full reference.
| Resource | Path | Description |
|---|---|---|
| APN | /api/v1/apn |
Access Point Name profiles |
| AUC | /api/v1/subscriber/auc |
Authentication Center (Ki, OPc, AMF, SQN) |
| Algorithm Profile | /api/v1/subscriber/auc/profile |
Custom Milenage c/r constant sets |
| Subscriber | /api/v1/subscriber |
EPC subscriber profiles |
| IMS Subscriber | /api/v1/ims_subscriber |
IMS subscriber profiles |
| IFC Profile | /api/v1/ims_subscriber/ifc_profile |
Initial Filter Criteria XML blobs |
| EIR | /api/v1/eir |
Equipment Identity Register entries |
| EIR History | /api/v1/eir/history |
IMSI/IMEI audit log (read-only) |
| Roaming Rules | /api/v1/roaming_rules |
Per-network allow/deny rules enforced on AIR and ULR |
| Charging Rule | /api/v1/apn/charging_rule |
Gx charging rules |
| TFT | /api/v1/apn/charging_rule/tft |
Traffic Flow Templates |
| Subscriber Routing | /api/v1/subscriber/routing |
Static IP assignments per subscriber+APN |
| Serving APN | /api/v1/oam/serving_apn |
Active PGW sessions |
| Subscriber Attributes | /api/v1/subscriber/attributes |
Key-value store per subscriber |
| Emergency Subscriber | /api/v1/oam/emergency_subscriber |
Emergency session tracking |
| Operation Log | /api/v1/oam/operation_log |
Audit trail (read-only) |
| GeoRed Status | /api/v1/geored/status |
Active replication peer status |
| GeoRed Sync | /api/v1/geored/sync |
Trigger a full resync to all peers |
- Go 1.25+
- PostgreSQL 14+ (or SQLite for testing)
make buildOutput: bin/hss
The full config.yaml with all sections:
hss:
OriginHost: hss01.epc.mnc001.mcc001.3gppnetwork.org
OriginRealm: epc.mnc001.mcc001.3gppnetwork.org
BindAddress: "::"
BindPort: 3868
EnableSCTP: false # set true to also listen on SCTP (requires kernel sctp module)
DWRInterval: 30
CancelLocationRequest_Enabled: true
MCC: "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.pem
database:
db_type: postgresql
server: localhost
port: 5432
username: hss
password: hss
database: hss
pool_size: 30
pool_idle: 10
pool_recycle: 300
logging:
# Supported levels: debug, info, warn, error
level: info
file: /var/log/hss.log # write logs to this file (comment out to disable)
# Use -d flag to force debug level and enable console output
eir:
# 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 restrictions
no_match_response: 0
imsi_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: true
geored:
enabled: false
node_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 events
batch_max_age_ms: 10 # flush batch after this many milliseconds
queue_size: 10000 # per-peer outbound queue depth
periodic_sync_interval_s: 0 # 0 = disabled; >0 triggers a full resync every N seconds
peers: []
# 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: true
bind_address: "::"
bind_port: 4222
5gc:
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.key
oauth2_enabled: false
oauth2_bypass: true
client:
mode: direct
scp_address: "" # used when mode: scp
# Fixed delay between NRF registration retry attempts.
reconnect_holdoff_time: 2s
udm:
enabled: false
mcc: "001"
mnc: "01"
nrf_address: ""
nf_instance_id: ""
suci_decryption_keys: []
pcf:
enabled: false
mcc: "001"
mnc: "01"
nrf_address: ""
nf_instance_id: ""
api:
enabled: true
bind_address: "::"
bind_port: 8080
# tls_cert_file: /etc/hss/tls/cert.pem # uncomment for HTTPS
# tls_key_file: /etc/hss/tls/key.pem
auth_enabled: false
api_keys: []
# api_keys:
# - "your-secret-key-here"./bin/hss -c config.yamlOn startup the server will:
- Connect to PostgreSQL and run AutoMigrate on all tables
- Load the GSMA TAC database into memory (if tac_db_enabled)
- Start the Diameter listener on TCP port 3868 (and SCTP if enabled)
- Start the GSUP/HLR listener on TCP port 4222 (if enabled)
- Start the shared 5GC SBI listener on port 7777 for UDM/UDR/PCF (if enabled)
- Start the OAM REST API on port 8080 (if enabled)
- Start the GeoRed replication listener on port 9869 (if enabled)
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"}'MME / CSCF / PGW / AAA / AS / BSF / E-CSCF (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/ LRR (emergency 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
| Component | Library |
|---|---|
| Diameter protocol | github.com/fiorix/go-diameter/v4 |
| Milenage / EAP-AKA | github.com/emakeev/milenage |
| ORM | gorm.io/gorm + gorm.io/driver/postgres |
| REST API framework | github.com/danielgtaylor/huma/v2 (OpenAPI 3.1) |
| HTTP router | github.com/go-chi/chi/v5 |
| Metrics | github.com/prometheus/client_golang |
| Logging | go.uber.org/zap |
| Config | gopkg.in/yaml.v3 |
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
| Document | Description |
|---|---|
| docs/api.md | Full OAM REST API reference - all endpoints, fields, and curl examples |