2 * Routines for ETSI TS 103 221-2 V1.6.1 (2022-06), Internal Network Interface X2/X3 for Lawful Interception
3 * Roy Zhang <roy.zhang@nokia-sbell.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include <epan/packet.h>
13 #include <epan/ipproto.h>
14 #include <epan/unit_strings.h>
15 #include "packet-tls.h"
17 void proto_reg_handoff_li5g(void);
18 void proto_register_li5g(void);
20 static int proto_li5g
;
21 static int hf_li5g_version
;
22 static int hf_li5g_pduType
;
23 static int hf_li5g_headerLen
;
24 static int hf_li5g_payloadLen
;
25 static int hf_li5g_payloadFormat
;
26 static int hf_li5g_payloadDirection
;
27 static int hf_li5g_xid
;
28 static int hf_li5g_cid
;
29 static int hf_li5g_attrType
;
30 static int hf_li5g_attrLen
;
31 static int hf_li5g_pld
;
33 /* the min Attribute Type is 1 */
34 #define LI_5G_ATTR_TYPE_MAX 23
35 /* the min header length */
36 #define LI_5G_HEADER_LEN_MIN 40
39 static int ett_attrContents
[LI_5G_ATTR_TYPE_MAX
];
40 static int hf_li5g_attrContents
[LI_5G_ATTR_TYPE_MAX
];
41 static dissector_handle_t li5g_handle
;
43 static dissector_table_t li5g_subdissector_table
;
45 static const value_string pdu_type_vals
[] = {
49 {4, "Keepalive Acknowledgement"},
53 static const value_string payload_format_vals
[] = {
54 { 0, "Reserved for Keepalive"},
55 { 1, "ETSI TS 102 232-1 Defined Payload"},
56 { 2, "3GPP TS 33.128 Defined Payload"},
57 { 3, "3GPP TS 33.108 Defined Payload"},
58 { 4, "Proprietary Payload"},
61 { 7, "Ethernet Frame"},
65 {11, "RADIUS Packet"},
66 {12, "GTP-U Message"},
68 {14, "3GPP TS 33.108 EpsIRIContent"},
70 {16, "3GPP Unstructured PDU"},
74 static const value_string payload_dir_vals
[] = {
75 {0, "Reserved for Keepalive"},
76 {1, "The direction of the intercepted data or event is not known to the POI"},
77 {2, "The intercepted data or event was sent to (i.e. received by) the target"},
78 {3, "The intercepted data or event was sent from the target"},
79 {4, "The intercepted data or event is a result of intercepted data or events in more than one direction"},
80 {5, "The concept of direction is not applicable to this intercepted data or event"},
84 static const value_string attribute_type_vals
[] = {
85 { 1, "ETSI TS 102 232-1 Defined Attribute"},
86 { 2, "3GPP TS 33.128 Defined Attribute"},
87 { 3, "3GPP TS 33.108 Defined Attribute"},
88 { 4, "Proprietary Attribute"},
89 { 5, "Domain ID (DID)"},
90 { 6, "Network Function ID (NFID)"},
91 { 7, "Interception Point ID (IPID)"},
92 { 8, "Sequence Number"},
94 {10, "Source IPv4 Address"},
95 {11, "Destination IPv4 Address"},
96 {12, "Source IPv6 Address"},
97 {13, "Destination IPv6 Address"},
99 {15, "Destination Port"},
101 {17, "Matched Target Identifier"},
102 {18, "Other Target Identifier"},
103 {19, "MIME Content Type"},
104 {20, "MIME Content Transfer Encoding"},
105 {21, "Additional XID Related Information"},
106 {22, "SDP Session Description"},
111 // NOLINTNEXTLINE(misc-no-recursion)
112 dissect_li5g(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
114 proto_tree
*li5g_tree
, *attr_tree
, *parent
=NULL
;
115 proto_item
*ti
, *attr_ti
;
116 tvbuff_t
*payload_tvb
;
117 int offset
= LI_5G_HEADER_LEN_MIN
, hf_attr
= -1;
118 uint32_t headerLen
, payloadLen
, pduType
;
119 uint16_t payloadFormat
, attrType
, attrLen
;
127 headerLen
= tvb_get_ntohl(tvb
, 4);
128 payloadLen
= tvb_get_ntohl(tvb
, 8);
129 payloadFormat
= tvb_get_ntohs(tvb
, 12);
131 ti
= proto_tree_add_item(tree
, proto_li5g
, tvb
, 0, headerLen
+payloadLen
, ENC_NA
);
132 li5g_tree
= proto_item_add_subtree(ti
, ett_li5g
);
133 proto_tree_add_item(li5g_tree
, hf_li5g_version
, tvb
, 0, 2, ENC_BIG_ENDIAN
);
134 proto_tree_add_item_ret_uint(li5g_tree
, hf_li5g_pduType
, tvb
, 2, 2, ENC_BIG_ENDIAN
, &pduType
);
135 proto_tree_add_item(li5g_tree
, hf_li5g_headerLen
, tvb
, 4, 4, ENC_BIG_ENDIAN
);
136 proto_tree_add_item(li5g_tree
, hf_li5g_payloadLen
, tvb
, 8, 4, ENC_BIG_ENDIAN
);
137 proto_tree_add_item(li5g_tree
, hf_li5g_payloadFormat
, tvb
, 12, 2, ENC_BIG_ENDIAN
);
138 proto_tree_add_item(li5g_tree
, hf_li5g_payloadDirection
, tvb
, 14, 2, ENC_BIG_ENDIAN
);
139 proto_tree_add_item(li5g_tree
, hf_li5g_xid
, tvb
, 16, 16, ENC_NA
);
140 proto_tree_add_item(li5g_tree
, hf_li5g_cid
, tvb
, 32, 8, ENC_NA
);
142 /* Get the Conditional Attribute */
143 while(headerLen
- offset
> 0){
144 attrType
= tvb_get_ntohs(tvb
, offset
);
145 attrLen
= tvb_get_ntohs(tvb
, offset
+2);
146 if (attrType
< LI_5G_ATTR_TYPE_MAX
){
147 hf_attr
= hf_li5g_attrContents
[attrType
];
149 attr_ti
= proto_tree_add_item(li5g_tree
, hf_attr
, tvb
, offset
+4, attrLen
, ENC_NA
);
150 attr_tree
= proto_item_add_subtree(attr_ti
, ett_attrContents
[attrType
]);
151 proto_tree_add_item(attr_tree
, hf_li5g_attrType
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
152 proto_tree_add_item(attr_tree
, hf_li5g_attrLen
, tvb
, offset
+2, 2, ENC_BIG_ENDIAN
);
153 if (attrType
== 17 || attrType
== 18) {
154 proto_tree_add_item(attr_tree
, hf_attr
, tvb
, offset
+4, attrLen
, ENC_UTF_8
| ENC_NA
);
156 proto_tree_add_item(attr_tree
, hf_attr
, tvb
, offset
+4, attrLen
, ENC_BIG_ENDIAN
);
160 offset
= offset
+ 4 + attrLen
;
163 proto_tree_add_item(li5g_tree
, hf_li5g_pld
, tvb
, headerLen
, payloadLen
, ENC_NA
);
165 /* the key is address+port+frame_num for reassemble list, the address/port can be changed in pinfo because of the inner TCP protocol */
166 copy_address_shallow(&src_addr
, &pinfo
->src
);
167 copy_address_shallow(&dst_addr
, &pinfo
->dst
);
168 src_port
= pinfo
->srcport
;
169 dst_port
= pinfo
->destport
;
171 /* to make all the sub protocol(such as DNS) under li5g*/
172 if (li5g_tree
&& li5g_tree
->parent
){
173 parent
=li5g_tree
->parent
;
174 li5g_tree
->parent
=NULL
;
177 payload_tvb
= tvb_new_subset_length(tvb
, offset
, payloadLen
);
178 if (!dissector_try_uint(li5g_subdissector_table
, payloadFormat
, payload_tvb
, pinfo
, li5g_tree
)) {
179 call_data_dissector(payload_tvb
, pinfo
, li5g_tree
);
183 li5g_tree
->parent
=parent
;
185 /* have another li5g in the same packet? */
186 if (tvb_captured_length(tvb
)>offset
+payloadLen
) {
187 increment_dissection_depth(pinfo
);
188 dissect_li5g(tvb_new_subset_remaining(tvb
, offset
+payloadLen
), pinfo
, tree
, NULL
);
189 decrement_dissection_depth(pinfo
);
192 /* set these info at the end*/
193 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LI5G");
194 col_clear_fence(pinfo
->cinfo
, COL_INFO
);
195 col_clear(pinfo
->cinfo
, COL_INFO
);
196 info
= try_val_to_str(pduType
, pdu_type_vals
);
198 col_set_str(pinfo
->cinfo
, COL_INFO
, info
);
201 /* copy back to the original value when return from innner protocol */
202 copy_address_shallow(&pinfo
->src
, &src_addr
);
203 copy_address_shallow(&pinfo
->dst
, &dst_addr
);
204 pinfo
->srcport
= src_port
;
205 pinfo
->destport
= dst_port
;
207 return tvb_captured_length(tvb
);
211 dissect_li5g_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
213 struct tlsinfo
* tlsinfo
= (struct tlsinfo
*)data
;
214 if (tvb_captured_length(tvb
) < LI_5G_HEADER_LEN_MIN
)
216 /* the version should be 1 */
217 if (tvb_get_ntohs(tvb
, 0) != 1)
219 /* only 4 types supported*/
220 if(tvb_get_ntohs(tvb
, 2) < 1 || tvb_get_ntohs(tvb
, 2) > 4)
223 /* TLS can hold it, no need to find the dissector every time */
224 *(tlsinfo
->app_handle
) = li5g_handle
;
225 dissect_li5g(tvb
, pinfo
, tree
, data
);
231 proto_register_li5g(void)
233 static hf_register_info hf
[] = {
234 { &hf_li5g_version
, { "Version", "li5g.ver", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
235 { &hf_li5g_pduType
, { "PDU Type", "li5g.type", FT_UINT16
, BASE_DEC
, VALS(pdu_type_vals
), 0x0, NULL
, HFILL
}},
236 { &hf_li5g_headerLen
, { "Header Length", "li5g.hl", FT_UINT32
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_octet_octets
), 0x0, NULL
, HFILL
}},
237 { &hf_li5g_payloadLen
, { "Payload Length", "li5g.pl", FT_UINT32
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_octet_octets
), 0x0, NULL
, HFILL
}},
238 { &hf_li5g_payloadFormat
, { "Payload Format", "li5g.pf", FT_UINT16
, BASE_DEC
, VALS(payload_format_vals
), 0x0, NULL
, HFILL
}},
239 { &hf_li5g_payloadDirection
, { "Payload Direction", "li5g.pd", FT_UINT16
, BASE_DEC
, VALS(payload_dir_vals
), 0x0, NULL
, HFILL
}},
240 { &hf_li5g_xid
, { "XID", "li5g.xid", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
241 { &hf_li5g_cid
, { "Correlation ID", "li5g.cid", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
243 { &hf_li5g_attrType
, { "Attribute Type", "li5g.attrType", FT_UINT16
, BASE_DEC
, VALS(attribute_type_vals
), 0x0, NULL
, HFILL
}},
244 { &hf_li5g_attrLen
, { "Attribute Length", "li5g.attrLen", FT_UINT16
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_octet_octets
), 0x0, NULL
, HFILL
}},
245 { &hf_li5g_attrContents
[1], { "ETSI TS 102 232-1 Defined Attribute", "li5g.102_232_1_attr", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
246 { &hf_li5g_attrContents
[2], { "3GPP TS 33.128 Defined Attribute", "li5g.33_128_attr", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
247 { &hf_li5g_attrContents
[3], { "3GPP TS 33.108 Defined Attribute", "li5g.33_108_attr", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
248 { &hf_li5g_attrContents
[4], { "Proprietary Attribute", "li5g.proprietary_attr", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
249 { &hf_li5g_attrContents
[5], { "Domain ID", "li5g.did", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
250 { &hf_li5g_attrContents
[6], { "Network Function ID", "li5g.nfid", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
251 { &hf_li5g_attrContents
[7], { "Interception Point ID", "li5g.ipid", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
252 { &hf_li5g_attrContents
[8], { "Sequence Number", "li5g.sq", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
253 { &hf_li5g_attrContents
[9], { "Timestamp", "li5g.ts", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_UTC
, NULL
, 0x0, NULL
, HFILL
}},
254 { &hf_li5g_attrContents
[10], { "Source IPv4 address", "li5g.srcip", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
255 { &hf_li5g_attrContents
[11], { "Destination IPv4 address", "li5g.dstip", FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
256 { &hf_li5g_attrContents
[12], { "Source IPv6 address", "li5g.srcipv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
257 { &hf_li5g_attrContents
[13], { "Destination IPv6 address", "li5g.dstipv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
258 { &hf_li5g_attrContents
[14], { "Source Port", "li5g.srcport", FT_UINT16
, BASE_PT_TCP
, NULL
, 0x0, NULL
, HFILL
}},
259 { &hf_li5g_attrContents
[15], { "Destination Port", "li5g.dstport", FT_UINT16
, BASE_PT_TCP
, NULL
, 0x0, NULL
, HFILL
}},
260 { &hf_li5g_attrContents
[16], { "IP Protocol", "li5g.ipproto", FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &ipproto_val_ext
, 0x0, NULL
, HFILL
}},
261 { &hf_li5g_attrContents
[17], { "Matched Target Identifier", "li5g.mti", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
262 { &hf_li5g_attrContents
[18], { "Other Target Identifier", "li5g.oti", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
263 { &hf_li5g_attrContents
[19], { "MIME Content Type", "li5g.mime_content_type", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
264 { &hf_li5g_attrContents
[20], { "MIME Content Transfer Encoding", "li5g.mime_transfer_type_encoding", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
265 { &hf_li5g_attrContents
[21], { "Additional XID Related Information", "li5g.additional_xid", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
266 { &hf_li5g_attrContents
[22], { "SDP Session Description", "li5g.sdp", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
268 { &hf_li5g_pld
, { "Payload", "li5g.pld", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
271 static int *ett
[] = {
273 &ett_attrContents
[1],
274 &ett_attrContents
[2],
275 &ett_attrContents
[3],
276 &ett_attrContents
[4],
277 &ett_attrContents
[5],
278 &ett_attrContents
[6],
279 &ett_attrContents
[7],
280 &ett_attrContents
[8],
281 &ett_attrContents
[9],
282 &ett_attrContents
[10],
283 &ett_attrContents
[11],
284 &ett_attrContents
[12],
285 &ett_attrContents
[13],
286 &ett_attrContents
[14],
287 &ett_attrContents
[15],
288 &ett_attrContents
[16],
289 &ett_attrContents
[17],
290 &ett_attrContents
[18],
291 &ett_attrContents
[19],
292 &ett_attrContents
[20],
293 &ett_attrContents
[21],
294 &ett_attrContents
[22],
297 proto_li5g
= proto_register_protocol("Lawful Interception 5G", "LI5G", "li5g");
299 li5g_handle
= register_dissector("li5g", dissect_li5g
, proto_li5g
);
301 li5g_subdissector_table
= register_dissector_table("li5g.payload", "LI5G Payload Format", proto_li5g
, FT_UINT16
, BASE_DEC
);
303 proto_register_field_array(proto_li5g
, hf
, array_length(hf
));
304 proto_register_subtree_array(ett
, array_length(ett
));
308 proto_reg_handoff_li5g(void)
310 dissector_add_uint("li5g.payload", 2, find_dissector_add_dependency("xiri", proto_li5g
));
311 dissector_add_uint("li5g.payload", 5, find_dissector("ip"));
312 dissector_add_uint("li5g.payload", 6, find_dissector("ipv6"));
313 dissector_add_uint("li5g.payload", 7, find_dissector("eth_maybefcs"));
314 dissector_add_uint("li5g.payload", 8, find_dissector("rtp"));
315 dissector_add_uint("li5g.payload", 9, find_dissector("sip"));
316 dissector_add_uint("li5g.payload", 10, find_dissector("dhcp"));
317 dissector_add_uint("li5g.payload", 11, find_dissector("radius"));
318 dissector_add_uint("li5g.payload", 12, find_dissector("gtp"));
319 dissector_add_uint("li5g.payload", 13, find_dissector("msrp"));
320 dissector_add_uint("li5g.payload", 14, find_dissector("HI2Operations"));
322 dissector_add_uint_range_with_preference("tcp.port", "", li5g_handle
);
323 dissector_add_uint_range_with_preference("udp.port", "", li5g_handle
);
324 heur_dissector_add("tls", dissect_li5g_heur
, "5G LI over TLS", "li5g_tls", proto_li5g
, HEURISTIC_ENABLE
);