Skip to content
LIVE FEED

WikiSS7 Deep-Dive Reference: GTT / MAP ASN.1 BER / SIGTRAN M3UA

SS7 Deep-Dive Reference: GTT / MAP ASN.1 BER / SIGTRAN M3UA

Specs: ITU-T Q.711–Q.716 (SCCP), Q.771–Q.775 (TCAP), 3GPP TS 29.002 (MAP), RFC 4666 (M3UA), RFC 4960 (SCTP)


Part 1 — GTT: Global Title Translation

1.1 SCCP Addressing Overview

SCCP có hai loại address để route message:

Address typeDùng khiVí dụ
Point Code (PC) + SSNĐã biết chính xác node đíchMSC gửi đến HLR cùng mạng
Global Title (GT)Không biết PC — cần STP dịchSMSC gửi SRI-SM với MSISDN

SCCP address field (Called/Calling Party Address) chứa:

+---+---+---+---+---+---+---+---+
| AI (Address Indicator) 1 byte  |
+---+---+---+---+---+---+---+---+
  bit7: Point Code included?  (1=yes)
  bit6: SSN included?          (1=yes)
  bit5-4: GT indicator
    00 = No GT
    01 = GT with Nature of Address only
    10 = GT with Translation Type only
    11 = GT with TT + NP + ES + NAI    <-- phổ biến nhất (ITU)
    0100 = GT with TT + NP + ES + NAI  (ANSI variant)
  bit3: Routing Indicator
    0 = Route on GT  <-- STP làm GTT
    1 = Route on PC+SSN

1.2 Global Title Format (GTI=0011, ITU)

Đây là format chuẩn cho MAP traffic trong mạng GSM/3G:

+------------------+------------------+------------------+------------------+
| Translation Type | Numbering Plan   | Encoding Scheme  | Nature of Addr   |
|   (TT) 1 byte    |   (NP) 4 bits    |   (ES) 4 bits    |   (NAI) 1 byte   |
+------------------+------------------+------------------+------------------+
| Digits (BCD, semi-octet packed)                                           |
+--------------------------------------------------------------------------+

Translation Type (TT):

  • 0x00 = Unknown / not used
  • 0x09 = MAP Mobile (phổ biến nhất cho HLR/VLR queries)
  • 0x0A = ISUP (circuit related)

Numbering Plan (NP):

  • 0001 = ISDN/telephony (E.164) — dùng cho MSISDN, GT operator
  • 0110 = Land Mobile (E.212) — dùng cho IMSI

Encoding Scheme (ES):

  • 0001 = BCD odd number of digits
  • 0010 = BCD even number of digits

NAI (Nature of Address Indicator):

  • 0x04 = International number (E.164 với country code)

Ví dụ encode GT cho MSISDN +84901234567:

TT  = 0x09
NP+ES = 0x11 (NP=0001 ISDN, ES=0001 odd digits)
NAI = 0x04

Digits BCD packed (semi-octet, little-endian per nibble):
  +84901234567  →  strip '+' → 84901234567 (11 digits, odd)
  
  Packing (pairs, swapped nibbles):
  84 → 0x48
  90 → 0x09
  12 → 0x21
  34 → 0x43
  56 → 0x65
  7  → 0xF7  (F = filler for odd)
  
  GT bytes: 09 11 04 48 09 21 43 65 F7

1.3 GTT Process tại STP

STP nhận SCCP UDT với Called Party = GT, thực hiện:

Step 1: Đọc Translation Type (TT) → chọn translation table
Step 2: Đọc digits (GT number) → longest prefix match
Step 3: Tra bảng → lấy (DPC, SSN, new GT nếu intermediate)
Step 4: Rewrite Called Party Address:
        - Nếu destination là local: set Routing Indicator = PC+SSN, xóa GT
        - Nếu cần forward tiếp: giữ GT hoặc replace GT
Step 5: Set DPC trong MTP3 routing label → forward

GTT Table structure (conceptual):

Table ID: TT=0x09 (MAP Mobile)

| GT Prefix     | Mask | DPC    | SSN | Action        | Description       |
|---------------|------|--------|-----|---------------|-------------------|
| +84           | /2   | 2-1-1  | 6   | Replace DPC   | Viettel HLR range |
| +8490         | /4   | 2-1-2  | 6   | Replace DPC   | Viettel HLR-2     |
| +8498         | /4   | 2-1-3  | 6   | Replace DPC   | Mobifone HLR      |
| +8479         | /4   | 3-2-1  | 6   | Forward+GTT   | Roaming, next STP |
| *             | /0   | 4-0-1  | 0   | Route to GW   | International GW  |

Longest prefix match: +8490... matches /4 trước /2.

1.4 Intermediate GTT vs Final GTT

Intermediate GTT (ISTP — Intermediate STP):
  - STP A làm GTT → thay DPC = STP B
  - Called Party GT giữ nguyên
  - STP B làm GTT tiếp (final)

Final GTT:
  - STP thay DPC = HLR PC, SSN = 6
  - Called Party → Routing Indicator = Route on PC+SSN
  - GT có thể bị xóa hoặc giữ lại tùy implementation

1.5 SCCP UDT Frame Layout

SCCP UDT (Class 0, Unitdata):

+--------+--------+
| MsgType=0x09    |  1 byte (UDT = 0x09)
+--------+--------+
| Class=0x00      |  1 byte (Class 0, no sequence)
+-----------------+
| Ptr to CdPA     |  1 byte (relative pointer)
| Ptr to CgPA     |  1 byte
| Ptr to Data     |  1 byte
+-----------------+
| CdPA Length     |  1 byte
| CdPA AI         |  1 byte (Address Indicator)
| CdPA SSN        |  1 byte (if present)
| CdPA GT         |  variable
+-----------------+
| CgPA Length     |  1 byte
| CgPA AI         |  1 byte
| CgPA SSN        |  1 byte
| CgPA GT         |  variable
+-----------------+
| Data Length     |  1 byte
| TCAP + MAP data |  variable
+-----------------+

Hex ví dụ SCCP UDT header:

09          # MsgType = UDT
00          # Protocol Class = 0
03          # Pointer to CdPA (offset 3 from here)
0E          # Pointer to CgPA
17          # Pointer to Data

# Called Party Address (CdPA) — HLR GT
09          # Length = 9 bytes
C4          # AI: GT=0011, PC=0, SSN=1, RI=GT
06          # SSN = 6 (HLR)
09 11 04    # TT=09, NP+ES=11, NAI=04
48 09 21 43 65 F7   # GT digits = +84901234567

# Calling Party Address (CgPA) — SMSC GT
07          # Length = 7 bytes
C4          # AI
87          # SSN = 135 (SMSC)
09 11 04
25 16 87 19 F6  # GT = +52618791 (SMSC number)

Part 2 — MAP Message Encoding: ASN.1 BER

2.1 Layering TCAP → MAP

SCCP Data field chứa:
  [TCAP]
    Begin / End / Continue / Abort
    DialoguePortion (optional)
    ComponentPortion
      [Component]
        Invoke / ReturnResult / ReturnError / Reject
        operationCode
        parameter  ← đây là MAP PDU, encoded ASN.1 BER

2.2 TCAP BER Structure

TCAP Begin (cho Invoke):

62 LL               # Begin APDU (tag 0x62, constructed)
  48 LL             # otid (Originating Transaction ID) tag=0x48
    XX XX XX XX     # 4-byte transaction ID
  
  6C LL             # Components (tag 0x6C, constructed)
    A1 LL           # Invoke component (tag 0xA1)
      02 01 NN      # invokeID (INTEGER, value=NN)
      02 01 OO      # operationCode (LOCAL INTEGER)
                    # OO = operation code (see MAP ops below)
      30 LL         # parameter (SEQUENCE)
        ...         # MAP-specific encoding

TCAP End (ReturnResult):

64 LL               # End APDU (tag 0x64)
  49 LL             # dtid (Destination Transaction ID)
    XX XX XX XX
  
  6C LL             # Components
    A2 LL           # ReturnResult (tag 0xA2)
      02 01 NN      # invokeID (same as Invoke)
      30 LL         # result + parameter
        02 01 OO    # operationCode
        30 LL       # parameter
          ...       # MAP result encoding

2.3 MAP Operation Codes (Local)

CodeOperationDirection
22 (0x16)sendRoutingInfoForSM (SRI-SM)SMSC → HLR
46 (0x2E)mt-forwardSM (MT-FSM)SMSC → MSC
44 (0x2C)forwardSM (MO-FSM)MSC → SMSC
2 (0x02)updateLocation (UL)VLR → HLR
22 (0x16)sendRoutingInfo (SRI)MSC → HLR
71 (0x47)anyTimeInterrogation (ATI)attacker → HLR
3 (0x03)cancelLocationHLR → VLR

2.4 SRI-SM Encoding (sendRoutingInfoForSM)

MAP TS 29.002 §10.3.4 — operation code = 0x16 (22)

Request:

MAP-SRI-SM-Arg ::= SEQUENCE {
    msisdn          [0] ISDN-AddressString,  -- victim MSISDN
    sm-RP-PRI       [1] BOOLEAN,             -- Priority flag
    serviceCentreAddress [2] AddressString,  -- SMSC address
    ...
}

BER Encoding ví dụ — SRI-SM cho MSISDN +84901234567, SMSC +84900000000:

TCAP Begin:
62 3A
  48 04 00 00 00 01      # otid = 0x00000001

  6C 32                  # Components
    A1 30                # Invoke
      02 01 01           # invokeID = 1
      02 01 16           # opCode = 22 (SRI-SM)
      
      30 28              # MAP-SRI-SM-Arg SEQUENCE
        81 07            # [1] msisdn (context 0, IMPLICIT)
                         # wait — correct tag:
        
        # ISDN-AddressString = OCTET STRING
        # [0] IMPLICIT OCTET STRING
        80 07            # tag=0x80 (context 0, primitive), len=7
          91             # TON/NPI: 0x91 = international E.164
          48 09 21 43 65 F7   # +84901234567 BCD

        81 01            # [1] sm-RP-PRI BOOLEAN
          FF             # TRUE

        82 07            # [2] serviceCentreAddress
          91             # TON/NPI international
          48 09 00 00 00 F0   # +84900000000 BCD

SRI-SM Response (ReturnResult):

MAP-SRI-SM-Res ::= SEQUENCE {
    imsi          [0] IMSI OPTIONAL,
    locationInfoWithLMSI [1] LocationInfoWithLMSI,
    ...
}

LocationInfoWithLMSI ::= SEQUENCE {
    networkNodeNumber  ISDN-AddressString,  -- serving MSC GT
    lmsi               LMSI OPTIONAL,       -- 4 bytes
    ...
}

BER encoding response:

64 2E                    # End APDU
  49 04 00 00 00 01      # dtid

  6C 26
    A2 24                # ReturnResult
      02 01 01           # invokeID = 1
      30 1F
        02 01 16         # opCode

        30 19            # MAP-SRI-SM-Res
          80 08          # [0] IMSI (BCD)
            21 43 62 10 32 54 76 F8   # IMSI 124361023456780 BCD

          A1 0D          # [1] LocationInfoWithLMSI
            04 07        # networkNodeNumber OCTET STRING
              91 48 09 21 00 00 F0   # MSC GT +84901200000
            04 04        # lmsi
              AB CD 12 34

2.5 MT-ForwardSM Encoding (mt-forwardSM)

MAP TS 29.002 §10.3.8 — operation code = 0x2E (46)

MAP-MT-Forward-SM-Arg ::= SEQUENCE {
    sm-RP-DA    SM-RP-DA,         -- Destination (IMSI or LMSI)
    sm-RP-OA    SM-RP-OA,         -- Originating (SMSC address)
    sm-RP-UI    SignalInfo,        -- SMS TPDU (TP-Deliver PDU)
    ...
}

SM-RP-DA ::= CHOICE {
    imsi        [0] IMSI,
    lmsi        [1] LMSI,
    ...
}

SM-RP-OA ::= CHOICE {
    msisdn      [2] ISDN-AddressString,
    serviceCentreAddressOA [4] AddressString,
}

BER Encoding MT-FSM:

TCAP Begin:
62 45
  48 04 00 00 00 02      # otid = 0x00000002

  6C 3D
    A1 3B
      02 01 01           # invokeID = 1
      02 01 2E           # opCode = 46 (mt-forwardSM)

      30 33              # MAP-MT-Forward-SM-Arg
        
        # sm-RP-DA: [0] IMSI
        A0 09
          04 08          # IMSI OCTET STRING
            21 43 62 10 32 54 76 F8

        # sm-RP-OA: [4] serviceCentreAddress (SMSC)
        A4 09
          04 07
            91 48 09 00 00 00 F0   # SMSC GT

        # sm-RP-UI: SignalInfo = OCTET STRING (SMS TPDU)
        04 17
          # TP-Deliver PDU (GSM 03.40):
          04             # MTI=00 (Deliver), MMS=0, RP=1
          0B             # TP-OA length = 11 digits
          91             # TP-OA TON/NPI = international
          84 09 01 82 43 F5   # Originating address +48901028345
          00             # TP-PID = 0
          00             # TP-DCS = 0 (GSM7)
          01 80 91 21 32 54 76   # TP-SCTS timestamp
          06             # TP-UDL = 6 chars
          C8 F7 1D 14 96 97   # TP-UD "Hello!" GSM7 encoded

2.6 ASN.1 BER Quick Reference

TagTypeNotes
0x02INTEGER
0x04OCTET STRINGdùng cho IMSI, addresses
0x05NULL
0x30SEQUENCE (constructed)
0x31SET (constructed)
0xA0..AFContext [0]..[15] constructedCHOICE/OPTIONAL fields
0x80..8FContext [0]..[15] primitiveIMPLICIT primitive

Length encoding:

< 128:   1 byte (e.g., 0x07)
>= 128:  0x81 LL (1 extra byte)
>= 256:  0x82 LL LL (2 extra bytes)

BCD/ISDN-AddressString format:

Byte 0: TON/NPI
  0x91 = international E.164
  0xA1 = national
  0x81 = unknown

Bytes 1+: digits BCD swapped nibbles, 0xF filler
  +84901234567 → 48 09 21 43 65 F7

2.7 Python Scapy — Build SRI-SM + MT-FSM

from scapy.all import *
from scapy.contrib.sctp import *

# Manual BER builder (Scapy không có MAP dissector built-in)
def encode_isdn_address(number: str) -> bytes:
    """E.164 → ISDN-AddressString BCD bytes"""
    digits = number.lstrip('+')
    if len(digits) % 2:
        digits += 'F'
    bcd = bytes(
        int(digits[i+1], 16) << 4 | int(digits[i], 16)
        for i in range(0, len(digits), 2)
    )
    return bytes([0x91]) + bcd  # TON/NPI=0x91

def encode_imsi(imsi: str) -> bytes:
    """IMSI → BCD bytes"""
    if len(imsi) % 2:
        imsi += 'F'
    return bytes(
        int(imsi[i+1], 16) << 4 | int(imsi[i], 16)
        for i in range(0, len(imsi), 2)
    )

def tlv(tag: int, value: bytes) -> bytes:
    """Simple BER TLV encoder (short form only)"""
    l = len(value)
    if l < 128:
        return bytes([tag, l]) + value
    elif l < 256:
        return bytes([tag, 0x81, l]) + value
    else:
        return bytes([tag, 0x82, (l >> 8) & 0xFF, l & 0xFF]) + value

def build_sri_sm(msisdn: str, smsc: str, invoke_id: int = 1,
                 otid: bytes = b'\x00\x00\x00\x01') -> bytes:
    msisdn_bytes = encode_isdn_address(msisdn)
    smsc_bytes   = encode_isdn_address(smsc)

    # MAP SRI-SM Arg
    map_arg = (
        tlv(0x80, msisdn_bytes) +          # [0] msisdn
        tlv(0x81, b'\xFF') +               # [1] sm-RP-PRI = TRUE
        tlv(0x82, smsc_bytes)              # [2] serviceCentreAddress
    )
    map_seq = tlv(0x30, map_arg)

    # TCAP Component: Invoke
    component = (
        tlv(0x02, bytes([invoke_id])) +    # invokeID
        tlv(0x02, bytes([0x16])) +         # opCode = 22
        map_seq
    )
    invoke = tlv(0xA1, component)
    components = tlv(0x6C, invoke)

    # TCAP Begin
    tcap = tlv(0x48, otid) + components
    return tlv(0x62, tcap)

# Test
pdu = build_sri_sm("+84901234567", "+84900000000")
print(pdu.hex())

Part 3 — SIGTRAN M3UA Association Setup

3.1 SIGTRAN Stack Recap

Application (MAP/ISUP)
     ↓
   SCCP
     ↓
   M3UA          ← MTP3 User Adaptation Layer (RFC 4666)
     ↓
   SCTP          ← Stream Control Transmission Protocol (RFC 4960)
     ↓
    IP

Roles:

RoleAbbrevMô tả
Signaling GatewaySGPSTP phía mạng SS7 legacy
Application Server ProcessASPApplication phía IP (ss7-sms-generator)
Application ServerASLogical entity gom nhiều ASP
Signaling Gateway ProcessSGPPhía STP

3.2 M3UA Message Types

ClassMessages
TransferDATA (payload)
SSNM (SS7 Signaling Network Mgmt)DUNA, DAVA, DAUD, SCON, DUPU, DRST
ASPSM (ASP State Mgmt)ASPUP, ASPUP-ACK, ASPDN, ASPDN-ACK, BEAT, BEAT-ACK
ASPTM (ASP Traffic Mgmt)ASPAC, ASPAC-ACK, ASPIA, ASPIA-ACK
MGMTERR, NTFY
RKM (Routing Key Mgmt)REG-REQ, REG-RSP, DEREG-REQ, DEREG-RSP

3.3 Association Bring-Up Sequence

ASP (ss7-sms-generator)          SGP (STP/SG)
        |                               |
        |---[SCTP INIT]---------------->|  SCTP 4-way handshake
        |<--[SCTP INIT-ACK]-------------|
        |---[SCTP COOKIE-ECHO]--------->|
        |<--[SCTP COOKIE-ACK]-----------|
        |                               |
        |---[ASPUP]-------------------->|  M3UA layer
        |<--[ASPUP-ACK]-----------------|
        |                               |
        |---[ASPAC (Active)]----------->|  Request traffic
        |<--[ASPAC-ACK]-----------------|
        |                               |
        |<--[DAVA (Dest Available)]-----|  DPC reachable notify
        |                               |
        |---[DATA (SCCP/TCAP/MAP)]----->|  Actual SS7 payload
        |<--[DATA (response)]-----------|

3.4 M3UA Packet Format

Common Header (8 bytes, mọi M3UA message):

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Version    |   Reserved    | Message Class | Message Type  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Message Length                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Parameters ...                            |
  • Version = 0x01
  • Message Class / Type:
ClassTypeName
0x010x01ASPUP
0x010x02ASPDN
0x010x03BEAT
0x010x04BEAT-ACK
0x010x05ASPUP-ACK
0x010x06ASPDN-ACK
0x020x01ASPAC
0x020x02ASPIA
0x020x03ASPAC-ACK
0x020x04ASPIA-ACK
0x030x01ERR
0x030x02NTFY
0x040x01DUNA
0x040x02DAVA
0x040x03DAUD
0x060x01DATA

M3UA Parameters (Tag-Length-Value):

TagParameterUsed in
0x0006Traffic Mode TypeASPAC
0x0007Error CodeERR
0x0008StatusNTFY
0x000BASP IdentifierASPUP
0x000CAffected Point CodeDUNA/DAVA
0x0200Network AppearanceDATA, DUNA/DAVA
0x0201Routing ContextDATA, ASPAC
0x0202Protocol DataDATA (chứa MTP3+SCCP payload)
0x0203Correlation IDREG-REQ
0x0204Registration ResultREG-RSP
0x0205Deregistration ResultDEREG-RSP

3.5 M3UA DATA Message — Protocol Data Parameter

DATA message = M3UA header + Routing Context + Protocol Data:

M3UA Header:
  01 00 06 01       # Version=1, Rsvd=0, Class=Transfer(6), Type=DATA(1)
  00 00 00 34       # Length = 52 bytes total

Parameters:
  02 01 00 08       # Tag=0x0201 (Routing Context), Len=8
  00 00 00 01       # RC = 1

  02 02 00 25       # Tag=0x0202 (Protocol Data), Len=37
    # MTP3 Routing Label (ITU 32-bit):
    00 02 01 02     # OPC=2-1-2 (DPC=2-1-1 OPC=sender) packed
                    # ITU: bits[0-13]=DPC, [14-27]=OPC, [28-31]=SLS
    
    # Actually layout:
    # [31-28]=SLS(4) [27-14]=OPC(14) [13-0]=DPC(14)
    # DPC=2-1-1: zone=2(2b), area=1(8b), id=1(4b) = 0b10_00000001_0001
    # OPC=2-1-2: = 0b10_00000001_0010
    # SLS=0
    
    03              # Service Indicator = 0x03 (SCCP)
    83              # Network Indicator = 0x83 (ITU national + spare)
    
    # SCCP UDT payload follows:
    09 00 03 0E 17 ... (SCCP UDT as shown in Part 1)

MTP3 Routing Label bit layout (ITU, 32-bit):

Bit:  31-28   27-14       13-0
      [SLS]   [OPC 14b]   [DPC 14b]

ITU Point Code x-y-z → 14 bits:
  zone(2b) | area(8b) | id(4b)
  
PC 2-1-5: 10 | 00000001 | 0101 = 0b10_00000001_0101 = 0x0815
PC 2-1-1: 10 | 00000001 | 0001 = 0b10_00000001_0001 = 0x0811

3.6 ASPUP / ASPAC Hex Detail

ASPUP:

01 00 01 01       # Class=ASPSM(1), Type=ASPUP(1)
00 00 00 10       # Length = 16

00 0B 00 08       # Tag=ASP Identifier(0x000B), Len=8
00 00 00 2A       # ASP ID = 42 (arbitrary)

ASPAC (Traffic Mode = Override):

01 00 02 01       # Class=ASPTM(2), Type=ASPAC(1)
00 00 00 18       # Length = 24

00 06 00 08       # Tag=Traffic Mode Type(0x0006), Len=8
00 00 00 01       # Override (1) — only this ASP active

02 01 00 08       # Tag=Routing Context(0x0201), Len=8
00 00 00 01       # RC=1

ASPAC-ACK:

01 00 02 03       # Class=ASPTM(2), Type=ASPAC-ACK(3)
00 00 00 18

00 06 00 08
00 00 00 01

02 01 00 08
00 00 00 01

3.7 SCTP Details (RFC 4960)

M3UA chạy trên SCTP. Các điểm quan trọng:

SCTP vs TCP:

  • Multi-stream: tránh head-of-line blocking
  • Multi-homing: failover IP tự động
  • Message boundaries preserved (không stream-based như TCP)
  • Built-in heartbeat (HEARTBEAT chunk)

SCTP Port cho SIGTRAN:

  • M3UA: port 2905
  • SUA (SCCP User Adaptation): port 14001
  • IUA (ISDN Q.921 User Adaptation): port 9900

SCTP Chunk types:

0x00 = DATA
0x01 = INIT
0x02 = INIT-ACK
0x03 = SACK
0x04 = HEARTBEAT
0x05 = HEARTBEAT-ACK
0x06 = ABORT
0x07 = SHUTDOWN
0x08 = SHUTDOWN-ACK
0x0A = COOKIE-ECHO
0x0B = COOKIE-ACK
0x0E = SHUTDOWN-COMPLETE

Linux SCTP socket (Java JNA context):

// SCTP one-to-one socket
int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);

// Multi-homing: bind multiple IPs
struct sockaddr_in addrs[2];
sctp_bindx(fd, addrs, 2, SCTP_BINDX_ADD_ADDR);

// Stream count
struct sctp_initmsg init = {
    .sinit_num_ostreams   = 2,
    .sinit_max_instreams  = 2,
    .sinit_max_attempts   = 3,
    .sinit_max_init_timeo = 1000
};
setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init));

// Send on stream 0 (M3UA uses stream 0 typically)
struct sctp_sndrcvinfo sinfo = { .sinfo_stream = 0 };
sctp_send(fd, m3ua_buf, m3ua_len, &sinfo, 0);

3.8 Java Implementation (JNA + SCTP cho ss7-sms-generator)

// M3UA frame builder
public class M3UABuilder {
    
    // M3UA Common Header
    public static byte[] header(int msgClass, int msgType, int bodyLen) {
        ByteBuffer buf = ByteBuffer.allocate(8);
        buf.put((byte) 0x01);           // version
        buf.put((byte) 0x00);           // reserved
        buf.put((byte) msgClass);
        buf.put((byte) msgType);
        buf.putInt(8 + bodyLen);        // total length
        return buf.array();
    }
    
    // TLV parameter
    public static byte[] param(int tag, byte[] value) {
        int len = 4 + value.length;
        int padded = (len + 3) & ~3;    // 4-byte aligned
        ByteBuffer buf = ByteBuffer.allocate(padded);
        buf.putShort((short) tag);
        buf.putShort((short) len);
        buf.put(value);
        // padding bytes already zero
        return buf.array();
    }
    
    // ASPUP message
    public static byte[] aspup(int aspId) {
        byte[] aspIdParam = param(0x000B,
            ByteBuffer.allocate(4).putInt(aspId).array());
        byte[] body = aspIdParam;
        return concat(header(0x01, 0x01, body.length), body);
    }
    
    // ASPAC message (Override mode, RC=1)
    public static byte[] aspac(int routingContext) {
        byte[] tmParam = param(0x0006,
            ByteBuffer.allocate(4).putInt(1).array()); // Override
        byte[] rcParam = param(0x0201,
            ByteBuffer.allocate(4).putInt(routingContext).array());
        byte[] body = concat(tmParam, rcParam);
        return concat(header(0x02, 0x01, body.length), body);
    }
    
    // DATA message wrapping SCCP payload
    public static byte[] data(int routingContext,
                               int opc, int dpc, int sls,
                               byte sio,
                               byte[] sccpPayload) {
        // MTP3 Routing Label (ITU 32-bit, little-endian in M3UA)
        // M3UA Protocol Data: OPC, DPC as 32-bit big-endian each
        ByteBuffer protData = ByteBuffer.allocate(8 + sccpPayload.length);
        protData.putInt(opc);       // OPC 32-bit (upper 18 bits unused for ITU)
        protData.putInt(dpc);       // DPC 32-bit
        protData.put((byte) sls);   // SLS
        protData.put(sio);          // Service Indicator + NI
        protData.put((byte) 0x00);  // spare
        protData.put((byte) 0x00);  // spare
        protData.put(sccpPayload);
        
        byte[] pdParam = param(0x0202, protData.array());
        byte[] rcParam = param(0x0201,
            ByteBuffer.allocate(4).putInt(routingContext).array());
        byte[] body = concat(rcParam, pdParam);
        return concat(header(0x06, 0x01, body.length), body);
    }
    
    private static byte[] concat(byte[]... arrays) {
        int total = 0;
        for (byte[] a : arrays) total += a.length;
        byte[] result = new byte[total];
        int pos = 0;
        for (byte[] a : arrays) {
            System.arraycopy(a, 0, result, pos, a.length);
            pos += a.length;
        }
        return result;
    }
}

Usage trong ss7-sms-generator:

// 1. Bring up M3UA association (via SCTP)
SctpChannel channel = SctpChannel.open();
channel.connect(new InetSocketAddress("stp.lab.local", 2905));

byte[] aspupMsg = M3UABuilder.aspup(42);
channel.send(ByteBuffer.wrap(aspupMsg), null);
// Wait for ASPUP-ACK...

byte[] aspac = M3UABuilder.aspac(1);
channel.send(ByteBuffer.wrap(aspac), null);
// Wait for ASPAC-ACK...

// 2. Build SCCP+MAP payload
byte[] sriSmPdu = SriSmBuilder.build("+84901234567", "+84900000000");
byte[] sccpUdt  = SccpBuilder.buildUDT(
    sriSmPdu,
    new SccpAddr(GT_INDICATOR, "+84901234567", SSN_HLR),  // CdPA
    new SccpAddr(GT_INDICATOR, "+84900000000", SSN_SMSC)  // CgPA
);

// 3. Wrap in M3UA DATA
byte[] m3uaData = M3UABuilder.data(
    1,          // routing context
    0x0812,     // OPC (2-1-2 = SMSC)
    0x0811,     // DPC (2-1-1 = STP/HLR)
    0,          // SLS
    (byte)0x03, // SIO: SI=3 (SCCP), NI=0
    sccpUdt
);

channel.send(ByteBuffer.wrap(m3uaData), null);

3.9 Wireshark Filter Quick Reference

# Tất cả SCTP traffic
sctp

# M3UA layer
m3ua

# SCCP
sccp

# TCAP
tcap

# MAP
gsm_map

# Filter SRI-SM operation
gsm_map.opr.code == 22

# Filter MT-ForwardSM
gsm_map.opr.code == 46

# Filter by MSISDN in Called Party
sccp.called.digits == "84901234567"

# M3UA ASPUP messages
m3ua.message_class == 1 && m3ua.message_type == 1

# M3UA DATA messages only
m3ua.message_class == 6 && m3ua.message_type == 1

Part 4 — Tích hợp: Flow đầy đủ cho ss7-sms-generator

ss7-sms-generator
(Quarkus + JNA / SCTP)
        |
        | SCTP port 2905
        v
+------------------+
|   STP (SGP)      |   ← có thể là Osmocom STP lab hoặc inject thẳng
|   GTT Table      |       vào Suricata bắt interface
+------------------+
        |
        | SS7 (SCCP UDT)
        v
+------------------+
|   HLR / SMSC sim |   ← Open5GS HSS hoặc SigPloit listener
+------------------+

Suricata bắt trên:
  - SCTP port 2905 (M3UA)
  - hoặc raw AF_PACKET (nếu inject thẳng Ethernet)

Rule ví dụ detect SRI-SM burst (location tracking via SMS):
  alert sctp any any -> any 2905 (
    msg:"SS7 SRI-SM burst - possible SMS interception";
    content:"|62|";       # TCAP Begin
    content:"|02 01 16|"; # opCode = 22 (SRI-SM)
    threshold: type threshold, track by_src, count 10, seconds 60;
    sid:9000001; rev:1;
  )

Rule detect MT-ForwardSM từ GT không trong whitelist:
  alert sctp any any -> any 2905 (
    msg:"SS7 MT-ForwardSM from unknown SMSC GT";
    content:"|02 01 2E|"; # opCode = 46
    sid:9000002; rev:1;
  )

References

SpecCoverage
ITU-T Q.711–Q.716SCCP
ITU-T Q.771–Q.775TCAP
3GPP TS 29.002MAP
RFC 4666M3UA
RFC 4960SCTP
GSMA FS.11SS7 security categories
3GPP TS 23.040SMS (TP layer)
Contact
Facebook
TOP