Python Protocol Simulator Wiki
multiple protocol simulator written in python
Status: Beta
Brought to you by:
ssrepfler
Python portable Protocol Simulator
- fully supported protocols): RADIUS, DIAMETER
- partially supported (python2 code only): DHCP, LDAP, DNS
- tested with python 2/3
- client examples included
- py2 code uses simplified dictionary.
- py3 code uses wireshark dictionary
- EAP: calculate keys (SIM, AKA, AKA')
- EAP: calculate hmac1, hmac256
- EAP: encode/decode AT_ENCR_DATA to get Pseudonym/Re-auth Identity
- EAP: HSS simulator
- RADIUS: encrypt/decrypt password
- tested on Linux (ARM and x86, x86-64), Solaris 10-x86 and Windows
Creating simple PCRF simulator supporting Gx functionality based on Pyprotosim software
Thanks to Pyprotosim simulator , Python diameter library and provided examples, it is really possible to create your own PCRF simulator on your Windows or Linux machine for tests or study.
This indeed can be useful for testers who want to check Gx functionality, and also for everyone who wants to study PCRF's Gx protocol on practice.
Python 2.7, python-ldap module , PCRF simulator and LDAP server and PCEF client can all be installed on the same Windows or Linux machines (tested with RedHat 6.2 and Windows XP).
What this small PCRF simulator can basically do? :)
1) It accepts connections from PCEF client, check CCR-I(U) messages, query LDAP server with msisdn as a filter, checks user profile and sends reply back to PCEF with enforced policy charging rules. It also updates sessionid from CCR-I(U) and store it into LDAP subscriber profile - this is needed further to create push RAR-T(U) requests to PCEF via script.
You configure PCC rules manually in LDAP's user's profile or using provisioning scripts.
2) When session is established from PCEF, it is also possible to send push RAR messages from PCRF to PCEF using scripts.
The PCRF simulator server complies with 3GPP TS 29.212 and supports CER,DWR,DPR,CCR-I,CCR-U,CCR-T,RAR-U,RAR-T messages. It listens 3868 and 3869 ports (which can be changed by user in the PCRF simulator server python file).
It is assumed that PCEF knows already ip address of the user’s identity (identity is msisdn or imsi), for the case when IP-CAN session is being established. Within initial CCR-I request PCEF will provide msisdn and imsi to PCRF simulator, and msisdn from CCR request will be used as a filter for ldap query to subscriber database (ldap) and will return user profile entries, like PCC rules.
However, if the user's identity is not known and PCEF sends CCR-I request with Framed-IP-Address ( IP of the UE) only, the PCRF simulator code can also be modified (ldap search filter only) without re-building LDAP schema.
For LDAP connectivity, OpenLDAP is used to create /modify user's profile. You can install OpenLDAP for Windows or for Linux, use some ldap browser software to modify PCC rules for users
One note about receiving TCP traffic (when you have multiple messages or high load)
In my examples data stream is read in chunks (predefined buffer size) regardless of packet size, which might lead to losing data if you have more than one packet in queue.
Proper solution is to read header (full or partial) first, decode packet len from it and then read rest of the packet (leaving other messages in the queue)
As I always preferred example to a pure theory - I'll stick to that:
This is my usual code (read all data in the queue)
but it will do stupid things if you have multiple messages.
Better way is to do something like (example is Diameter specific)
But even this is not correct. When I tested this on a big packets (64K+, actually it started arround 25K), it failed. So, the correct solution is
Last edit: Sergej Srepfler 2015-03-28
The practical example of testing Gx functionality by using PCRF simulator on basis of portable pyprotosim software.
Example is given for Linux Ubuntu, python 2.7 is installed.
./PCRF_SIMULATOR_GX_SERVER_WITH_SPR.py
To stop it, run CTRL+C
*Optionally, if you want to start PCRF simulator as a daemon, you can install and use zdaemon utility:
a) sudo apt-get install python-zdaemon
b) START pcrf simulator as daemon:
zdaemon -p "python PCRF_SIMULATOR_GX_SERVER_WITH_SPR.py" -d start
daemon process started, pid=4641
c) verify that it is running as a daemon:
ps -efl | grep PCRF_SIMULATOR_GX_SERVER_WITH_SPR.py
1 S pcef 4639 1 0 80 0 - 5645 poll_s 15:31 ? 00:00:00 /usr/bin/python /usr/bin/zdaemon -S schema.xml -b 10 -s zdsock -m 022 -x 0,2 python PCRF_SIMULATOR_GX_SERVER_WITH_SPR.py
0 S pcef 4641 4639 0 80 0 - 6176 poll_s 15:31 ? 00:00:00 python PCRF_SIMULATOR_GX_SERVER_WITH_SPR.py
0 S pcef 4649 2189 0 80 0 - 1097 pipe_w 15:31 pts/1 00:00:00 grep --color=auto PCRF_SIMULATOR_GX_SERVER_WITH_SPR.py
c) TO STOP pcrf simulator, run command:
zdaemon -p "python PCRF_SIMULATOR_GX_SERVER_WITH_SPR.py" -d stop
4) verify that it is stopped:
ps -efl | grep PCRF_SIMULATOR_GX_SERVER
0 S pcef 4617 2189 0 80 0 - 1097 pipe_w 15:17 pts/1 00:00:00 grep --color=auto PCRF_SIMULATOR_GX_SERVER
RUNNING TEST:
In your PCRF_sim directory:
sudo tcpdump -i any -vvv -w /tmp/diam.cap port 3868 or port 3869
Test scenario:
Capabilities exchange between hosts:
1) PCEF ---> CER -----> PCRF
2) PCEF <--- CEA <----- PCRF
PCEF sends CCR Initial request to PCRF, PCRF checks if user identity is valid in SPR DB . (The SPR DB is implemented as python dictionary with key of user's identity).
PCRF reply with PCC Charging-Install Rule and QoS profile settings 'basic' for this user.
3) PCEF ---> CCR-I ---> PCRF
4) PCRF ---> SPR
5) PCEF <--- CCA-I <-- PCRF <--- SPR (PCC rule)
Now PCRF will send to PCEF RAR-U (Update) (Push operation) by using script called test_push_RAR-U.py (manually on Windows) (or you can send it automatically by uncommenting subprocess.call("./test_push_RAR-U.py" string in script)) with PCC-Charging-Remove old rule 'basic' and installs new PCC Charging-Install Rule and QoS profile settings 'highspeed' for this user. PCEF will reply with RAA 2001 OK reply and should enforce this policy (install new settings for this user).
6) PCEF <--- RAR-U <--- PCRF
7) PCEF ---> RAA ---> PCRF
In terminal , you will see the following decoded AVP entries for Re-Auth Request:
Decoded AVP (u'Charging-Rule-Remove', [(u'Charging-Rule-Base-Name', u'basic')])
Decoded AVP (u'Charging-Rule-Install', [(u'Charging-Rule-Base-Name', u'highspeed')])
Now user is logged off and PCEF informs PCRF by sending CCR-T (Terminate) to it, PCRF will terminate user session and reply with 2001 Success.
8) PCEF ---> CCR-T ---> PCRF
9) PCEF <--- CCA <--- PCRF
Disconnect Pear Request to PCRF and 2001 Success Answer and close peer. ( PCRF simulator just reply with 2001 OK)
10) PCEF ---> DPR ----> PCRF
11) PCEF <--- DPA <---- PCRF
The tcpdump capture communication details:
pcef@pcef:~$ tshark -r /tmp/diam.cap -R 'diameter'
CER/CEA
4 0.014687 127.0.0.1 -> 127.0.0.1 DIAMETER 224 cmd=Capabilities-ExchangeRequest(257) flags=R--- appl=Diameter Common Messages(0) h2h=53511f9a e2e=fcd0000
6 0.033021 127.0.0.1 -> 127.0.0.1 DIAMETER 228 cmd=Capabilities-ExchangeAnswer(257) flags=---- appl=Diameter Common Messages(0) h2h=53511f9a e2e=fcd0000
CCR-I/CCA-I
8 0.082948 127.0.0.1 -> 127.0.0.1 DIAMETER 364 cmd=Credit-ControlRequest(272) flags=RP-- appl=3GPP Gx(16777238) h2h=53511f9b e2e=fcd0001
10 0.242987 127.0.0.1 -> 127.0.0.1 DIAMETER 532 cmd=Credit-ControlAnswer(272) flags=---- appl=3GPP Gx(16777238) h2h=53511f9b e2e=fcd0001
RAR-U/RAA-U
17 0.646213 127.0.0.1 -> 127.0.0.1 DIAMETER 632 cmd=Re-AuthRequest(258) flags=RP-- appl=3GPP Gx(16777238) h2h=53511f9a e2e=fcd0000
22 1.089809 127.0.0.1 -> 127.0.0.1 DIAMETER 288 cmd=Re-AuthAnswer(258) flags=---- appl=3GPP Gx(16777238) h2h=53511f9a e2e=fcd0000
CCR-T/CCA-T
24 1.115780 127.0.0.1 -> 127.0.0.1 DIAMETER 364 cmd=Credit-ControlRequest(272) flags=RP-- appl=3GPP Gx(16777238) h2h=53511f9c e2e=fcd0002
26 1.195397 127.0.0.1 -> 127.0.0.1 DIAMETER 284 cmd=Credit-ControlAnswer(272) flags=---- appl=3GPP Gx(16777238) h2h=53511f9c e2e=fcd0002
DPR/DPA
28 1.233210 127.0.0.1 -> 127.0.0.1 DIAMETER 152 cmd=Disconnect-PeerRequest(282) flags=R--- appl=Diameter Common Messages(0) h2h=53511f9d e2e=fcd0003
30 1.238829 127.0.0.1 -> 127.0.0.1 DIAMETER 152 cmd=Disconnect-PeerAnswer(282) flags=---- appl=Diameter Common Messages(0) h2h=53511f9d e2e=fcd0003
Some thoughts about using Wireshark dictionary as suggested by Yordan Tsolov and Jarko Asenov.
It makes sense. It even solves some of the issues and confusion I had. And it is confusing to have naming mismatch between wireshark and your code. It did not bother me, but some users seemed to be stunned.
But offered solution is not ideal. If we use wireshark dictionary, then we also must introduce methods to override some values (e.g if MandatoryFlag is defined as MAY, then we must be able to set it to desired value for that AVP)
So I'm really inclined to use offered solution, but after some redesign and internal cleanup.
Unfortunately, it seems that it might break compatibility (at least with the current idea I'm having).
So - wish me enough free time to start working on it.
Last edit: Sergej Srepfler 2015-03-28
Directly using wireshark dictionary seems less and less a possibility.
For example, you encounter stuff like
which is perfectly OK for decoding, but NOT for encoding
As I said - whoever allowed duplicate names in dictionary should be shot!
And wireshark does not use hierarchical structure with dictionary per application-id, but one flat table (loaded from several files)
Team i am trying to use Protocal Simulator for EAP-AKA testing using wx inerface, however TCP session is coming up between Radius and Simulator when i connect a mobile client its getting error out with the below logs.
INFO:root:('Single AVP', 'L', 12, 12, 'D', '0000010a4000000c000028af')
INFO:root:('Single AVP', 'L', 12, 12, 'D', '000001024000000c01000031')
INFO:root:('Decoded as', u'Vendor-Id', 10415)
INFO:root:('Decoded as', u'Auth-Application-Id', 16777265)
INFO:root:('Decoded as', u'Vendor-Specific-Application-Id', [(u'Vendor-Id', 10415), (u'Auth-Application-Id', 16777265)])
Traceback (most recent call last):
File "HSS_simulator_single.py", line 391, in <module>
if handle_HSS(r)==ERROR:
File "HSS_simulator_single.py", line 43, in handle_HSS
ret=process_request(data.encode("hex"))
File "HSS_simulator_single.py", line 288, in process_request
return create_MAA(H)
File "HSS_simulator_single.py", line 233, in create_MAA
Auth_Method=findAVP("Authentication-Method",Auth_Data)
File "../libDiameter.py", line 669, in findAVP
for avp in list:
TypeError: 'int' object is not iterable
Portal-Server HSS_sim #
Portal-Server HSS_sim #
Portal-Server HSS_sim # python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Can some plese tell me wats the issue here.
Something is wrong here. Easiest way is to send me snoop+source whatever
you are testing, so I can reproduce it.
On the first look (always hard without context) it seems that your MAR Request over Wx interface does not contain required AVP (Authentication-Method).
To confirm it, make network capture of incoming diameter packet.
Last edit: Sergej Srepfler 2015-10-19
Can you please find the attached Capture at HSS_SIM, here i am uisng version pyprotosim-0.3.2
Can you please tell me whats the Authentication-Method we are expecting so that we can use static value to bypass this error,
here i am testing EAP-AKA using Mobile clients.
Last edit: Ajay Mare 2015-10-19
OK. Let me state clearly how I undestood your issue:
You have a RADIUS client.
Radius client connect to <something> (port 1812 as expected)
<something> then should connect to HSS_SIM over Wx interface and exchange MAR/MAA?
But I do not see it in snoop (Capture_at_HSS_SIM.pcap). All I see is SSH encrypted traffic
As next step, <something> sends challenge to a Radius client (using Protected EAP (EAP-PEAP code 25, which my EAP library does not support yet))
Did I get it right? Is this the scenario you are testing?
In that case, you have several issues:
- EAP-PEAP is NOT supported yet. Yes, it can be done, but current version does not support it.
- If you are using PEAP, then you should use MSCHAPv2 (another protocol currently not supported).
- If you plan to test EAP-AKA, then you need to figure out why <something> is sending wrong EAP protocol.
Getting authentication vector over Wx is rather simple:
For EAP-SIM Multimedia-Auth Request looks like this:
MAR 303, ApplicationId= 16777219
(u'Session-Id', u'1316636797;449;137219838')
(u'Vendor-Specific-Application-Id', [(u'Vendor-Id', 10415), (u'Auth-Application-Id', 16777219)])
(u'Auth-Session-State', 1)
(u'User-Name', u'734043000257998')
(u'3GPP-SIP-Number-Auth-Items', 3)
(u'3GPP-SIP-Auth-Data-Item',
(u'Authentication-Method', 0))
(u'NAS-Port-Type', 5)
(u'Origin-Host', 'aaa.test.lab')
(u'Origin-Realm', 'test.lab')
(u'Destination-Realm', 'remote.lab')
For EAP-AKA:
MAR 303, ApplicationId= 16777265
(u'Session-Id', u'1316636797;449;137219838')
(u'RAT-Type', 0)
(u'ANID', u'HRPD')
(u'Destination-Host', 'hss.remote.lab')
(u'Destination-Realm', 'remote.lab')
(u'Vendor-Specific-Application-Id',
(u'Vendor-Id', 10415),
(u'Auth-Application-Id', 16777265))
(u'User-Name', u'123423803567005')
(u'3GPP-SIP-Number-Auth-Items', 1)
(u'3GPP-SIP-Auth-Data-Item', [(u'3GPP-SIP-Authentication-Scheme', u'EAP-AKA')])
(u'Auth-Session-State', 1)
(u'Origin-Host', 'aaa.test.lab')
Decoded AVP (u'Origin-Realm', 'test.lab')
HSS simulator has response hardcoded: it will ALWAYS return the same vectors for ANY username.
If you want - please let's move this into private discussion. Use my email directly for faster issue resolution.
Last edit: Sergej Srepfler 2015-10-19
Trying to run on python 3.6.8 and getting error. Any one tried diameter_client.py in version 3.6 > ?
Old python2 code is not directly compatible with new python 3 code
Supported python is clearly marked by folder name in latest release (py2, py3)
For a working py3 diameter client, take a look at the source code folder
https://sourceforge.net/p/pyprotosim/code-0/ci/default/tree/py3/sample/
For Python3 version, Is there a tool_EAP_decode.py ?
It seems to be missing from the repo. I need to check for it on my dev
machine.
Within a few days, I'll upload the new one (I'll wrote new one if this one
does not work)
Thanks for finding this problem for me.
Last edit: Sergej Srepfler 2021-04-14
Appreciate if you could upload the EAP decode tool. Thanks!
New version with included tool is there.
Anyone having issue compiling the eapcalc? I am getting error, I install python-devel .
./py3/src_cEap/cEap.c:13:10: fatal error: Python.h: No such file or directory
Last edit: Naseem Rahman 2021-04-27
Are you compiling for linux on windows?
Please make sure that you include correct path to python.h in build script (compile.sh)
Path is hardcoded for my machine, Change it to match your setup
Also check that you have all required programs/packages installed (listed in comments)
I'll assume that you work on linux
In script, I use python 3.6, so if you use newer python, please adjust path from
CFLAGS3="-O2 -Wall -fPIC -I/usr/include/python3.6 -shared"
to something matching your setup
Anyone has any script that calculate EAP SIM in pythonv3?
See test_eap in py3/test folder
If you are still stuck, explain exactly what you are trying to do (or
better yet, send me what you got so far so I can make your test code
working)
I added the EAP-AKA client demo (EAP-SIM was not needed by OP).
Last edit: Sergej Srepfler 2021-11-07
Hi Sergej,
I am trying to add Emergency-Services AVP ( msg.add("Emergncy-Services", 1) but getting error :
Exception: ('Unable to find AVP', 'Emergncy-Services', 'None'). Do I need to update my Wireshark?
Please check in wireshark dictionary folder if that AVP exist. If not -
then you need to add it yourself or update
In my dictionary (...wireshark/diameter/dictionary.xml) it is
<avp name="Emergency-Services" code="1538" mandatory="mustnot" may-encrypt="no" vendor-bit="must" vendor-id="TGPP">
So you might need to add vendor to the line
msg.add("Emergency-Services", 1, "TGPP")
or
msg.add("Emergency-Services", 1, vendor="TGPP")</avp>
Note:
AVP is named "Emergency-Services" in my dict (not "Emergncy-Services").
No spaces allowed in vendor="TGPP" (python named parameter syntax)
Last edit: Sergej Srepfler 2022-01-09