mirror of https://gerrit.osmocom.org/pysim
pySim-trace: Add support for reading GSMTAP from pcap files
So far we supported * GSMTAP live traces via a UDP socket * RSPRO traces from pcap files (or live) We were lacking support for reading GSMTAP stored in pcap, which is what this patch implements. Change-Id: I46d42774b39a2735500ff5804206ddcfa545568cchanges/38/30438/2
parent
284ac104af
commit
c95f6e2124
|
@ -18,6 +18,7 @@ from pySim.transport import LinkBase
|
|||
|
||||
from pySim.apdu_source.gsmtap import GsmtapApduSource
|
||||
from pySim.apdu_source.pyshark_rspro import PysharkRsproPcap, PysharkRsproLive
|
||||
from pySim.apdu_source.pyshark_gsmtap import PysharkGsmtapPcap
|
||||
|
||||
from pySim.apdu.ts_102_221 import UiccSelect, UiccStatus
|
||||
|
||||
|
@ -130,6 +131,11 @@ parser_gsmtap.add_argument('-i', '--bind-ip', default='127.0.0.1',
|
|||
parser_gsmtap.add_argument('-p', '--bind-port', default=4729,
|
||||
help='Local UDP port')
|
||||
|
||||
parser_gsmtap_pyshark_pcap = subparsers.add_parser('gsmtap-pyshark-pcap', help="""
|
||||
PCAP file containing GSMTAP (SIM APDU) communication; processed via pyshark.""")
|
||||
parser_gsmtap_pyshark_pcap.add_argument('-f', '--pcap-file', required=True,
|
||||
help='Name of the PCAP[ng] file to be read')
|
||||
|
||||
parser_rspro_pyshark_pcap = subparsers.add_parser('rspro-pyshark-pcap', help="""
|
||||
PCAP file containing RSPRO (osmo-remsim) communication; processed via pyshark.
|
||||
REQUIRES OSMOCOM PATCHED WIRESHARK!""")
|
||||
|
@ -153,6 +159,8 @@ if __name__ == '__main__':
|
|||
s = PysharkRsproPcap(opts.pcap_file)
|
||||
elif opts.source == 'rspro-pyshark-live':
|
||||
s = PysharkRsproLive(opts.interface)
|
||||
elif opts.source == 'gsmtap-pyshark-pcap':
|
||||
s = PysharkGsmtapPcap(opts.pcap_file)
|
||||
|
||||
tracer = Tracer(source=s, suppress_status=opts.suppress_status, suppress_select=opts.suppress_select)
|
||||
logger.info('Entering main loop...')
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
# coding=utf-8
|
||||
|
||||
# (C) 2022 by Harald Welte <laforge@osmocom.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from pprint import pprint as pp
|
||||
from typing import Tuple
|
||||
import pyshark
|
||||
|
||||
from pySim.utils import h2b, b2h
|
||||
from pySim.apdu import Tpdu
|
||||
from pySim.gsmtap import GsmtapMessage
|
||||
from . import ApduSource, PacketType, CardReset
|
||||
|
||||
from pySim.apdu.ts_102_221 import ApduCommands as UiccApduCommands
|
||||
from pySim.apdu.ts_31_102 import ApduCommands as UsimApduCommands
|
||||
from pySim.apdu.global_platform import ApduCommands as GpApduCommands
|
||||
ApduCommands = UiccApduCommands + UsimApduCommands + GpApduCommands
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class _PysharkGsmtap(ApduSource):
|
||||
"""APDU Source [provider] base class for reading GSMTAP SIM APDU via tshark."""
|
||||
|
||||
def __init__(self, pyshark_inst):
|
||||
self.pyshark = pyshark_inst
|
||||
self.bank_id = None
|
||||
self.bank_slot = None
|
||||
self.cmd_tpdu = None
|
||||
super().__init__()
|
||||
|
||||
def read_packet(self) -> PacketType:
|
||||
p = self.pyshark.next()
|
||||
return self._parse_packet(p)
|
||||
|
||||
def _set_or_verify_bank_slot(self, bsl: Tuple[int, int]):
|
||||
"""Keep track of the bank:slot to make sure we don't mix traces of multiple cards"""
|
||||
if not self.bank_id:
|
||||
self.bank_id = bsl[0]
|
||||
self.bank_slot = bsl[1]
|
||||
else:
|
||||
if self.bank_id != bsl[0] or self.bank_slot != bsl[1]:
|
||||
raise ValueError('Received data for unexpected B(%u:%u)' % (bsl[0], bsl[1]))
|
||||
|
||||
def _parse_packet(self, p) -> PacketType:
|
||||
udp_layer = p['udp']
|
||||
udp_payload_hex = udp_layer.get_field('payload').replace(':','')
|
||||
gsmtap = GsmtapMessage(h2b(udp_payload_hex))
|
||||
gsmtap_msg = gsmtap.decode()
|
||||
if gsmtap_msg['type'] != 'sim':
|
||||
raise ValueError('Unsupported GSMTAP type %s' % gsmtap_msg['type'])
|
||||
sub_type = gsmtap_msg['sub_type']
|
||||
if sub_type == 'apdu':
|
||||
return ApduCommands.parse_cmd_bytes(gsmtap_msg['body'])
|
||||
elif sub_type == 'atr':
|
||||
# card has been reset
|
||||
return CardReset()
|
||||
elif sub_type in ['pps_req', 'pps_rsp']:
|
||||
# simply ignore for now
|
||||
pass
|
||||
else:
|
||||
raise ValueError('Unsupported GSMTAP-SIM sub-type %s' % sub_type)
|
||||
|
||||
class PysharkGsmtapPcap(_PysharkGsmtap):
|
||||
"""APDU Source [provider] class for reading GSMTAP from a PCAP
|
||||
file via pyshark, which in turn uses tshark (part of wireshark).
|
||||
"""
|
||||
def __init__(self, pcap_filename):
|
||||
"""
|
||||
Args:
|
||||
pcap_filename: File name of the pcap file to be opened
|
||||
"""
|
||||
pyshark_inst = pyshark.FileCapture(pcap_filename, display_filter='gsm_sim', use_json=True, keep_packets=False)
|
||||
super().__init__(pyshark_inst)
|
||||
|
Loading…
Reference in New Issue