├── .gitignore ├── AUTHORS ├── LICENSE ├── README.md ├── VM ├── 00-header ├── README.md ├── diameterclient.service ├── diameterfw.service ├── diameterserver.service ├── line_curl.sh ├── mapping_template.sh ├── ss7client.service ├── ss7fw.service ├── ss7server.service ├── tshark_to_ek.service ├── tshark_to_ek.sh ├── tshark_to_ss7fw.service └── tshark_to_ss7fw.sh ├── docs ├── running_from_netbeans.gif ├── us-17-Kacer-SS7-Attacker-Heaven-Turns-Into-Riot-How-To-Make-Nation-State-And-Intelligence-Attackers-Lives-Much-Harder-On-Mobile-Networks-wp.pdf └── us-17-Kacer-SS7-Attacker-Heaven-Turns-Into-Riot-How-To-Make-Nation-State-And-Intelligence-Attackers-Lives-Much-Harder-On-Mobile-Networks.pdf └── sigfw ├── sigfw.sigfw ├── .gitignore ├── TCAPStack_management.xml ├── diameterfw.json ├── diameterfw_1.json ├── diameterfw_2.json ├── diameterfw_junit.json ├── diameterfw_keystore ├── keystore ├── maplog.txt ├── nb-configuration.xml ├── nbactions-Default.xml ├── nbactions.xml ├── pom.xml ├── realm.properties ├── src │ ├── main │ │ ├── java │ │ │ ├── diameterfw │ │ │ │ ├── DatagramOverDiameterPacket.java │ │ │ │ ├── DiameterClient.java │ │ │ │ ├── DiameterClientLiveInput.java │ │ │ │ ├── DiameterFirewall.java │ │ │ │ ├── DiameterFirewallAPI_V1_0.java │ │ │ │ ├── DiameterFirewallConfig.java │ │ │ │ ├── DiameterFirewallFirstInstance.java │ │ │ │ ├── DiameterFirewallPerformanceTests.java │ │ │ │ ├── DiameterFirewallSecondInstance.java │ │ │ │ └── DiameterServer.java │ │ │ ├── sigfw │ │ │ │ ├── common │ │ │ │ │ ├── AvpImpl.java │ │ │ │ │ ├── AvpSetImpl.java │ │ │ │ │ ├── Crypto.java │ │ │ │ │ ├── ExternalFirewallRules.java │ │ │ │ │ └── Utils.java │ │ │ │ ├── connectorIDS │ │ │ │ │ ├── ConnectorIDS.java │ │ │ │ │ ├── ConnectorIDSModuleInterface.java │ │ │ │ │ └── ConnectorIDSModuleRest.java │ │ │ │ ├── connectorMThreat │ │ │ │ │ ├── ConnectorMThreat.java │ │ │ │ │ ├── ConnectorMThreatModuleInterface.java │ │ │ │ │ └── ConnectorMThreatModuleRest.java │ │ │ │ └── tests │ │ │ │ │ ├── DTLSOverDatagram.java │ │ │ │ │ ├── EncryptionTest.java │ │ │ │ │ ├── ExtensionLoaderTest.java │ │ │ │ │ └── RestClientTest.java │ │ │ └── ss7fw │ │ │ │ ├── AbstractSctpBase.java │ │ │ │ ├── DatagramOverSS7Packet.java │ │ │ │ ├── SS7Client.java │ │ │ │ ├── SS7ClientANSI.java │ │ │ │ ├── SS7ClientLiveInput.java │ │ │ │ ├── SS7Firewall.java │ │ │ │ ├── SS7FirewallAPI_V1_0.java │ │ │ │ ├── SS7FirewallConfig.java │ │ │ │ ├── SS7FirewallFirstInstance.java │ │ │ │ ├── SS7FirewallPerformanceTests.java │ │ │ │ ├── SS7FirewallSecondInstance.java │ │ │ │ ├── SS7Honeypot.java │ │ │ │ └── SS7Server.java │ │ └── resources │ │ │ ├── client-jdiameter-config.xml │ │ │ ├── dictionary.xml │ │ │ ├── log4j.properties │ │ │ └── server-jdiameter-config.xml │ └── test │ │ ├── java │ │ └── sigfw │ │ │ └── tests │ │ │ ├── TestNg_Placeholder.java │ │ │ ├── Test_DiameterFirewall.java │ │ │ └── Test_SS7Firewall.java │ │ └── resources │ │ └── log4j.properties ├── ss7fw.json ├── ss7fw_1.json ├── ss7fw_2.json ├── ss7fw_junit.json ├── ss7fw_keystore ├── truststore └── wireshark_diameter_custom.xml └── sigfw_interface ├── .gitignore ├── pom.xml └── src └── main └── java └── com └── p1sec └── sigfw └── SigFW_interface ├── CryptoInterface.java └── FirewallRulesInterface.java /.gitignore: -------------------------------------------------------------------------------- 1 | sigfw/sigfw.sigfw/input 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Original Authors 2 | -------- ------- 3 | Martin Kacer 4 | Philippe Langlois 5 | 6 | Special thanks to 7 | ----------------- 8 | Telestax - jSS7, jDiameter opensource project 9 | 10 | 11 | Contributors 12 | ------------ 13 | Ewout Pronk { 14 | GSMA DESS group collaboration 15 | } 16 | Fredrik Soderlund { 17 | GSMA DESS group collaboration 18 | } 19 | Xiaolei Li { 20 | DiameterFW PoC and IOT tests 21 | } 22 | Chaoyi Zhang { 23 | DiameterFW PoC and IOT tests 24 | } 25 | 26 | 27 | Acknowledgements 28 | ---------------- 29 | The work is copyrighted also with all right by the original authors: 30 | Martin Kacer 31 | Philippe Langlois 32 | 33 | P1 Security grants to H21 lab the transferable, irrevocable, perpetual, 34 | royalty-free right to use, modify, copy, sell, and distribute 35 | the Original work and Contributions under the terms of any OSI 36 | recognized Open Source License or any commercial use license. 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SigFW 2 | Open Source SS7/Diameter firewall 3 | 4 | ## SigFW introduction 5 | * [SigFW BlackHat USA 2017 Presentation](https://github.com/P1sec/SigFW/blob/master/docs/us-17-Kacer-SS7-Attacker-Heaven-Turns-Into-Riot-How-To-Make-Nation-State-And-Intelligence-Attackers-Lives-Much-Harder-On-Mobile-Networks.pdf) 6 | * [SigFW BlackHat USA 2017 Whitepaper](https://github.com/P1sec/SigFW/blob/master/docs/us-17-Kacer-SS7-Attacker-Heaven-Turns-Into-Riot-How-To-Make-Nation-State-And-Intelligence-Attackers-Lives-Much-Harder-On-Mobile-Networks-wp.pdf) 7 | * [SigFW BlackHat USA 2017 Talk (youtube)](https://www.youtube.com/watch?v=XiKq2fJBUJI) 8 | 9 | ## Build instructions 10 | For more detailed installation and build instructions refer to this [page](https://github.com/P1sec/SigFW/wiki/Installation-and-Build-Instructions). 11 | 12 | ### Prerequisities 13 | Install Maven 14 | (Optional) Netbeans IDE for developers 15 | 16 | ### Clone source code 17 | git clone https://github.com/P1Sec/SigFW 18 | 19 | ### Build SigFW project 20 | ```bash 21 | cd ./SigFW/sigfw/sigfw.sigfw 22 | mvn clean install -Dmaven.test.skip=true 23 | ``` 24 | 25 | ### Run SS7FW 26 | ```bash 27 | mvn exec:java -Dexec.mainClass="ss7fw.SS7Firewall" 28 | mvn exec:java -Dexec.mainClass="ss7fw.SS7ClientLiveInput" 29 | mvn exec:java -Dexec.mainClass="ss7fw.SS7Server" 30 | ``` 31 | 32 | ### Replay traffic from pcap 33 | ```bash 34 | cd ./input 35 | mkfifo pipe 36 | tshark -T ek -x -j "" -r ./input/sigtran.pcap > sigtran.json 37 | cat ./input/sigtran.json > pipe 38 | ``` 39 | 40 | ![](https://github.com/P1sec/SigFW/blob/master/docs/running_from_netbeans.gif) 41 | 42 | 43 | ### Run DiameterFW 44 | ```bash 45 | mvn exec:java -Dexec.mainClass="diameterfw.DiameterFirewall" 46 | mvn exec:java -Dexec.mainClass="diameterfw.DiameterClientLiveInput" 47 | mvn exec:java -Dexec.mainClass="diameterfw.DiameterServer" 48 | ``` 49 | 50 | ### Replay traffic from pcap 51 | ```bash 52 | cd ./input 53 | mkfifo pipe 54 | tshark -T ek -x -j "" -r ./input/diameter.pcap > diameter.json 55 | cat ./input/diameter.json > pipe 56 | ``` 57 | 58 | ### Security 59 | For both SS7FW and DiameterFW before using. 60 | 61 | realm.properties: Change the username, password for firewall API 62 | 63 | sigfw.json: Generate new Public, Private Keys. Change the mThreat salt 64 | 65 | Jetty: Change the certificate 66 | 67 | ### To test the encryption, signatures 68 | Instead of SS7Firewall run SS7FirewallFirstInstance and SS7FirewallSecondInstance 69 | 70 | Instead of DiameterFirewall run DiameterFirewallFirstInstance and DiameterFirewallSecondInstance 71 | 72 | ## Limitations 73 | Program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. 74 | 75 | ## License 76 | SigFW is licensed under dual license policy. The default license is the Free Open Source GNU Affero GPL v3.0. Alternatively a commercial license can be obtained from P1 Security S.A.S. 77 | 78 | ## Attribution 79 | For the list of contributors, see the AUTHORS file. 80 | 81 | Original work was created by Martin Kacer, Philippe Langlois 82 | 83 | Copyright 2020, P1 Security S.A.S and individual contributors 84 | 85 | We would like to thanks for everyone supporting this project. 86 | 87 | -------------------------------------------------------------------------------- /VM/00-header: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # 00-header - create the header of the MOTD 4 | # Copyright (C) 2009-2010 Canonical Ltd. 5 | # 6 | # Authors: Dustin Kirkland 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License along 19 | # with this program; if not, write to the Free Software Foundation, Inc., 20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | 22 | [ -r /etc/lsb-release ] && . /etc/lsb-release 23 | 24 | if [ -z "$DISTRIB_DESCRIPTION" ] && [ -x /usr/bin/lsb_release ]; then 25 | # Fall back to using the very slow lsb_release utility 26 | DISTRIB_DESCRIPTION=$(lsb_release -s -d) 27 | fi 28 | 29 | #printf "Welcome to %s (%s %s %s)\n" "$DISTRIB_DESCRIPTION" "$(uname -o)" "$(uname -r)" "$(uname -m)" 30 | 31 | printf "SigFW\n" 32 | printf "Open Source SS7/Diameter firewall\n" 33 | printf "Original work was created by Martin Kacer, Philippe Langlois\n" 34 | printf "Copyright 2017, P1 Security S.A.S and individual contributors\n" 35 | printf "See the AUTHORS in the distribution for a full listing of individual contributors.\n" 36 | printf "\n" 37 | printf "SigFW is licensed under dual license policy. The default license is\n" 38 | printf "the Free Open Source GNU Affero GPL v3.0.\n" 39 | printf "\n" 40 | printf "\n" 41 | printf "Interfaces:\n" 42 | printf " enp0s3 - management (SSH, Web)\n" 43 | printf " enp0s8 - signalling (SigFW could be reconfigured here)\n" 44 | printf " enp0s9 - passive signalling (port-mirrored traffic)\n" 45 | printf "\n" 46 | printf "To access Kibana:\n" 47 | printf " http://:5601/\n" 48 | printf "\n" 49 | printf "To access API\n" 50 | printf " https://:8443/ss7fw_api/1.0/get_status\n" 51 | printf "\n" 52 | printf "To check if services are running:\n" 53 | printf " sudo service tshark_to_ss7fw status\n" 54 | printf " sudo service tshark_to_ek status\n" 55 | printf " sudo service ss7fw status\n" 56 | printf " sudo service ss7server status\n" 57 | printf " sudo service ss7client status\n" 58 | printf "\n" 59 | printf "To replay the pcap on passive interface:\n" 60 | printf " sudo tcpreplay --intf1=enp0s9 sigtran.pcap\n" 61 | printf "\n" 62 | printf "Description:\n" 63 | printf " By default only SS7FW is enabled. The SS7FW is in passive mode.\n" 64 | printf " DiameterFW code is present but configured as service system service.\n" 65 | printf " Tshark is capturing traffic on enp0s9 and pushing into ElasticSearch.\n" 66 | printf " Second instance of tshark is pushing capture into named pipe of SS7FW.\n" 67 | printf " The SS7FW consist of ss7client, ss7firewall, ss7server. ss7client replay\n" 68 | printf " the captured traffic from enp0s9 towards ss7firewall and ss7server on\n" 69 | printf " localhost.\n" 70 | printf "\n" 71 | printf " SS7FW and DiameterFW are located in /opt/SigFW/sigfw/\n" 72 | printf "\n" 73 | printf " Before first run or if the IP has changed, modify /etc/kibana/kibana.yml" 74 | printf "\n" 75 | printf "\n" 76 | printf "To access logs:\n" 77 | printf " tail -f /opt/SigFW/sigfw/sigfw.sigfw/sigfw.log\n" 78 | -------------------------------------------------------------------------------- /VM/README.md: -------------------------------------------------------------------------------- 1 | Ubuntu pre-built VM can be obtained from contact@p1sec.com 2 | 3 | VM is packaged including the following: 4 | * SS7FW 5 | * tshark + Elasticsearch 6 | 7 | The SSH banner in the VM includes the quick instruction how to use the VM: 8 | ``` 9 | SigFW 10 | Open Source SS7/Diameter firewall 11 | Original work was created by Martin Kacer, Philippe Langlois 12 | Copyright 2017, P1 Security S.A.S and individual contributors 13 | See the AUTHORS in the distribution for a full listing of authors and contributors. 14 | 15 | SigFW is licensed under dual license policy. The default license is 16 | the Free Open Source GNU Affero GPL v3.0. 17 | 18 | 19 | Interfaces: 20 | enp0s3 - management (SSH, Web) 21 | enp0s8 - signalling (SigFW could be reconfigured here) 22 | enp0s9 - passive signalling (port-mirrored traffic) 23 | 24 | To access Kibana: 25 | http://:5601/ 26 | 27 | To access API 28 | https://:8443/ss7fw_api/1.0/get_status 29 | 30 | To check if services are running: 31 | sudo service tshark_to_ss7fw status 32 | sudo service tshark_to_ek status 33 | sudo service ss7fw status 34 | sudo service ss7server status 35 | sudo service ss7client status 36 | 37 | To replay the pcap on passive interface: 38 | sudo tcpreplay --intf1=enp0s9 sigtran.pcap 39 | 40 | Description: 41 | By default only SS7FW is enabled. The SS7FW is in passive mode. 42 | DiameterFW code is present but configured as service system service. 43 | Tshark is capturing traffic on enp0s9 and pushing into ElasticSearch. 44 | Second instance of tshark is pushing capture into named pipe of SS7FW. 45 | The SS7FW consist of ss7client, ss7firewall, ss7server. ss7client replay 46 | the captured traffic from enp0s9 towards ss7firewall and ss7server on 47 | localhost. 48 | 49 | SS7FW and DiameterFW are located in /opt/SigFW/sigfw/ 50 | 51 | Before first run or if the IP has changed, modify /etc/kibana/kibana.yml 52 | 53 | To access logs: 54 | tail -f /opt/SigFW/sigfw/sigfw.sigfw/sigfw.log 55 | ``` 56 | -------------------------------------------------------------------------------- /VM/diameterclient.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=DiameterFW client service 3 | 4 | [Service] 5 | User=p1sec 6 | Group=p1sec 7 | WorkingDirectory=/opt/SigFW/sigfw/sigfw.sigfw 8 | ExecStart=/usr/bin/mvn exec:java -Dexec.mainClass="diameterfw.DiameterClientLiveInput" 9 | #Restart=always 10 | StandardOutput=null 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /VM/diameterfw.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=DiameterFW service 3 | 4 | [Service] 5 | User=p1sec 6 | Group=p1sec 7 | WorkingDirectory=/opt/SigFW/sigfw/sigfw.sigfw 8 | ExecStart=/usr/bin/mvn exec:java -Dexec.mainClass="diameterfw.DiameterFirewall" 9 | #Restart=always 10 | StandardOutput=null 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /VM/diameterserver.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=DiameterFW server service 3 | 4 | [Service] 5 | User=p1sec 6 | Group=p1sec 7 | WorkingDirectory=/opt/SigFW/sigfw/sigfw.sigfw 8 | ExecStart=/usr/bin/mvn exec:java -Dexec.mainClass="diameterfw.DiameterServer" 9 | #Restart=always 10 | StandardOutput=null 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /VM/line_curl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash - 2 | i=0 3 | while read line; do 4 | # process only non empty lines because of older tshark release 5 | if [ ! -z "$line" ]; then 6 | c=$(printf '%s\n%s\n' "$c" "$line") 7 | i=$((i+1)) 8 | 9 | # curl only every X seconds 10 | # the better solution is to use logstash or multithreaded client 11 | if !((i % 2)) && !((SECONDS % 10)) && [[ -v c ]]; then 12 | #printf '%s\n' "$c" 13 | printf '%s\n' "$c" | curl -o /dev/null --silent -XPUT http://localhost:9200/_bulk --data-binary @- & 14 | c= 15 | i=0 16 | fi 17 | fi 18 | done 19 | 20 | #echo $c 21 | if [[ -v c ]]; then 22 | # #printf '%s\n' "$c" 23 | printf '%s\n' "$c" | curl -o /dev/null --silent -XPUT http://localhost:9200/_bulk --data-binary @- & 24 | fi 25 | -------------------------------------------------------------------------------- /VM/mapping_template.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ $# -ne 1 ]] ; then 4 | echo "usage: template.sh node" 5 | exit 6 | fi 7 | 8 | curl -XPUT 'http://'$1'/_template/packets-template' -d ' 9 | { 10 | "template": "packets-*", 11 | "mappings": { 12 | "_default_": { 13 | "dynamic": "true", 14 | "dynamic_date_formats" : [ 15 | "yyyy-MM-dd HH:mm:SS" 16 | ], 17 | "dynamic_templates": [ 18 | { 19 | "string_fields": { 20 | "match": "*", 21 | "match_mapping_type": "string", 22 | "mapping": { 23 | "index": "not_analyzed", 24 | "omit_norms": true, 25 | "type": "string" 26 | } 27 | } 28 | } 29 | ], 30 | "properties": { 31 | "@version": { 32 | "type": "string", 33 | "index": "not_analyzed" 34 | } 35 | } 36 | }, 37 | "my_mapping": { 38 | "numeric_detection": true, 39 | "dynamic": "true", 40 | "properties": { 41 | "timestamp": { 42 | "type": "date" 43 | }, 44 | "layers": { 45 | "properties": { 46 | "tcap": { 47 | "properties": { 48 | "tcap_opCode_tcap_localValue": { 49 | "type": "integer" 50 | } 51 | } 52 | }, 53 | "gsm_map": { 54 | "properties": { 55 | "gsm_old_opCode_gsm_old_localValue": { 56 | "type": "integer" 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | 65 | } 66 | }' 67 | 68 | echo 69 | -------------------------------------------------------------------------------- /VM/ss7client.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SS7FW client service 3 | 4 | [Service] 5 | User=p1sec 6 | Group=p1sec 7 | WorkingDirectory=/opt/SigFW/sigfw/sigfw.sigfw 8 | ExecStart=/usr/bin/mvn exec:java -Dexec.mainClass="ss7fw.SS7ClientLiveInput" 9 | #Restart=always 10 | StandardOutput=null 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /VM/ss7fw.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SS7FW service 3 | 4 | [Service] 5 | User=p1sec 6 | Group=p1sec 7 | WorkingDirectory=/opt/SigFW/sigfw/sigfw.sigfw 8 | ExecStart=/usr/bin/mvn exec:java -Dexec.mainClass="ss7fw.SS7Firewall" 9 | #Restart=always 10 | StandardOutput=null 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /VM/ss7server.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SS7FW server service 3 | 4 | [Service] 5 | User=p1sec 6 | Group=p1sec 7 | WorkingDirectory=/opt/SigFW/sigfw/sigfw.sigfw 8 | ExecStart=/usr/bin/mvn exec:java -Dexec.mainClass="ss7fw.SS7Server" 9 | #Restart=always 10 | StandardOutput=null 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /VM/tshark_to_ek.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=tshark to elasticsearch 3 | 4 | [Service] 5 | User=p1sec 6 | Group=p1sec 7 | WorkingDirectory=/opt/SigFW/VM/ 8 | ExecStart=/opt/SigFW/VM/tshark_to_ek.sh 9 | #Restart=always 10 | StandardOutput=null 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /VM/tshark_to_ek.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash - 2 | tshark -i enp0s9 -T ek -l | /opt/SigFW/VM/line_curl.sh 3 | -------------------------------------------------------------------------------- /VM/tshark_to_ss7fw.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=tshark to SS7FW 3 | 4 | [Service] 5 | User=p1sec 6 | Group=p1sec 7 | WorkingDirectory=/opt/SigFW/VM/ 8 | ExecStart=/opt/SigFW/VM/tshark_to_ss7fw.sh 9 | #Restart=always 10 | StandardOutput=null 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /VM/tshark_to_ss7fw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash - 2 | tshark -i enp0s9 -T ek -x -j " " -l > /opt/SigFW/sigfw/sigfw.sigfw/input/pipe 3 | -------------------------------------------------------------------------------- /docs/running_from_netbeans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P1sec/SigFW/5942c557696b1351963727812fc35cc315ebcce4/docs/running_from_netbeans.gif -------------------------------------------------------------------------------- /docs/us-17-Kacer-SS7-Attacker-Heaven-Turns-Into-Riot-How-To-Make-Nation-State-And-Intelligence-Attackers-Lives-Much-Harder-On-Mobile-Networks-wp.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P1sec/SigFW/5942c557696b1351963727812fc35cc315ebcce4/docs/us-17-Kacer-SS7-Attacker-Heaven-Turns-Into-Riot-How-To-Make-Nation-State-And-Intelligence-Attackers-Lives-Much-Harder-On-Mobile-Networks-wp.pdf -------------------------------------------------------------------------------- /docs/us-17-Kacer-SS7-Attacker-Heaven-Turns-Into-Riot-How-To-Make-Nation-State-And-Intelligence-Attackers-Lives-Much-Harder-On-Mobile-Networks.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P1sec/SigFW/5942c557696b1351963727812fc35cc315ebcce4/docs/us-17-Kacer-SS7-Attacker-Heaven-Turns-Into-Riot-How-To-Make-Nation-State-And-Intelligence-Attackers-Lives-Much-Harder-On-Mobile-Networks.pdf -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | XmlSctpClientLiveInput/ 3 | XmlSctpFirewall/ 4 | XmlSctpServer/ 5 | XmlDiameterFirewall/ 6 | *.log 7 | *.log.* 8 | *.last 9 | Sctp*.xml 10 | server-management*.xml 11 | 127.0.0.1.*.xml 12 | input/ 13 | src/main/resources/SigFW_extension-1.0.jar 14 | nbactions-release-profile.xml 15 | 16 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/TCAPStack_management.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/diameterfw.json: -------------------------------------------------------------------------------- 1 | { 2 | "operator_configuration": { 3 | 4 | "Home_IMSI_prefixes_comment": "# Identification Home IMSI range for HPLMN network, used to identify home subscribers", 5 | "Home_IMSI_prefixes": [ 6 | "111111" 7 | ], 8 | "Home_Diameter_Realm_list_comment": "Operator Diameter Internal Realm list, used to identify incoming and outgoing traffic of HPLMN", 9 | "Home_Diameter_Realm_list": [ 10 | "exchange.example.org" 11 | ] 12 | }, 13 | "sigfw_configuration": { 14 | "sctp": { 15 | "sctp_management_name": "sctp_mgmt", 16 | "sctp_max_in_streams": "32", 17 | "sctp_max_out_streams": "32", 18 | "sctp_server": [ 19 | { 20 | "server_name": "sctp_server", 21 | "host_address": "127.0.0.1", 22 | "port": "3869", 23 | "accept_anonymous_associations_comment": "# set true if the FW accepts SCTP associations from random source port", 24 | "accept_anonymous_associations": "false" 25 | } 26 | ], 27 | "sctp_server_association": [ 28 | { 29 | "peer_address": "127.0.0.1", 30 | "peer_port": "13868", 31 | "server_name": "sctp_server", 32 | "assoc_name": "sctp_from_client_to_firewall" 33 | } 34 | ], 35 | "sctp_association": [ 36 | { 37 | "host_address": "127.0.0.1", 38 | "host_port": "13869", 39 | "peer_address": "127.0.0.1", 40 | "peer_port": "3868", 41 | "assoc_name": "sctp_from_firewall_to_server" 42 | } 43 | ] 44 | }, 45 | "firewall_rules": { 46 | "firewall_rules_comment": "# Firewall filtering rules configuration", 47 | 48 | "firewall_policy_comment": "# Allowed value is one from: DROP_SILENTLY, DROP_WITH_DIAMETER_ERROR, DNAT_TO_HONEYPOT, ALLOW", 49 | "firewall_policy": "DROP_SILENTLY", 50 | 51 | "diameter": { 52 | "origin_realm_blacklist": [ 53 | "blacklisted.example.org" 54 | ], 55 | "application_id_whitelist": [ 56 | "0", 57 | "16777360", 58 | "16777251" 59 | ], 60 | "command_code_blacklist": [ 61 | "8388620", 62 | "8388622" 63 | ], 64 | "cat2_command_code_blacklist": [ 65 | "317", 66 | "319", 67 | "329" 68 | ] 69 | }, 70 | 71 | "lua": { 72 | "lua_comment": "# LUA Blacklist firewall rules. Currently supported LUA variables are: diameter_orig_host, diameter_orig_realm, diameter_dest_host, diameter_dest_realm, diameter_cc, diameter_ai, diameter_imsi, diameter_msisdn", 73 | "blacklist_rules": [ 74 | "diameter_orig_realm == 'exchangeClientA.example.org'", 75 | "diameter_orig_realm == 'exchangeClientB.example.org'" 76 | ] 77 | }, 78 | 79 | "ids": { 80 | "ids_comment": "# IDS API. After evaluating internal firewall rules, the external IDS system can be used to check message (e.g. Cat3). If not required remove this ids json block from config.", 81 | 82 | "ids_api_type_comment": "# Type of connector. Currently supported only REST", 83 | "ids_api_type": "REST", 84 | "ids_servers": [ 85 | { 86 | "host": "https://localhost:8443/diameterfw_api/1.0/eval_diameter_message_in_ids", 87 | "username": "user", 88 | "password": "password" 89 | } 90 | ] 91 | }, 92 | 93 | "mthreat": { 94 | "mthreat_comment": "# mThreat API. If the message matches internal firewall or IDS rules, then the firewall can report the event in anonymized way to mThreat. If not required remove this mthreat json block from config.", 95 | 96 | "mthreat_api_type_comment": "# Type of connector. Currently supported only REST", 97 | "mthreat_api_type": "REST", 98 | "mthreat_salt_comment": "# Change the salt value for unique anonymization", 99 | "mthreat_salt": "XVm4AoKrkicsgEcx", 100 | "mthreat_servers": [ 101 | { 102 | "host": "https://127.0.0.1:8444/mthreat_api/1.0/send_diameter_alert_to_mthreat", 103 | "username": "user", 104 | "password": "pass" 105 | } 106 | ] 107 | }, 108 | 109 | "honeypot": { 110 | "honeypot_comment": "# Honeypot configuration. Only used if firewall policy is DNAT_TO_HONEYPOT", 111 | 112 | "diameter_host_comment": "# The firewall after detecting the message will perform DNAT to the following Diameter address.", 113 | "diameter_host": "127.0.0.1", 114 | "diameter_realm": "honeypot.example.org", 115 | 116 | "dnat_session_expiration_timeout_comment": "# After matching the firewall or IDS rules, the firewall will apply DNAT for Diameter address for the defined number of seconds", 117 | "dnat_session_expiration_timeout": "30" 118 | } 119 | }, 120 | "encryption_rules": { 121 | "destination_realm_encryption": [ 122 | ], 123 | "destination_realm_decryption": [ 124 | { 125 | "destination_realm": "exchange.example.org", 126 | "public_key_type": "RSA", 127 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 128 | "private_key_type": "RSA", 129 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 130 | } 131 | ], 132 | "autodiscovery_comment": "# If enabled, then the special diameter command code is used to retrieve the foreign SigFW encryption public key.", 133 | "autodiscovery": "true", 134 | "dtls_encryption_comment": "# If dtls_encryption is enabled, than the autodiscovery is not used anymore. DTLS handshake in Diameter protocol is used instead. For DTLS handshake the trustore and keystore is used. After successful handshake the DTLS encryption is used. Signature_rules, can be still used together with DTLS, however DTLS provides also integrity protection so they are not mandatory.", 135 | "dtls_encryption": "true" 136 | }, 137 | "signature_rules": { 138 | "origin_realm_verify": [ 139 | { 140 | "origin_realm": "exchange.example.org", 141 | "signing_realm_comment": "Subject name which is issuing signature", 142 | "signing_realm": "exchange.example.org", 143 | "public_key_type": "RSA", 144 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB" 145 | } 146 | ], 147 | "origin_realm_signing": [ 148 | 149 | ] 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/diameterfw_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "operator_configuration": { 3 | 4 | "Home_IMSI_prefixes_comment": "# Identification Home IMSI range for HPLMN network, used to identify home subscribers", 5 | "Home_IMSI_prefixes": [ 6 | "111111" 7 | ], 8 | "Home_Diameter_Realm_list_comment": "Operator Diameter Internal Realm list, used to identify incoming and outgoing traffic of HPLMN", 9 | "Home_Diameter_Realm_list": [ 10 | "exchangeClient.example.org" 11 | ] 12 | }, 13 | "sigfw_configuration": { 14 | "sctp": { 15 | "sctp_management_name": "sctp_mgmt", 16 | "sctp_max_in_streams": "32", 17 | "sctp_max_out_streams": "32", 18 | "sctp_server": [ 19 | { 20 | "server_name": "sctp_server", 21 | "host_address": "127.0.0.1", 22 | "port": "3869" 23 | } 24 | ], 25 | "sctp_server_association": [ 26 | { 27 | "peer_address": "127.0.0.1", 28 | "peer_port": "13868", 29 | "server_name": "sctp_server", 30 | "assoc_name": "sctp_from_client_to_firewall" 31 | } 32 | ], 33 | "sctp_association": [ 34 | { 35 | "host_address": "127.0.0.1", 36 | "host_port": "13870", 37 | "peer_address": "127.0.0.1", 38 | "peer_port": "3870", 39 | "assoc_name": "sctp_from_firewall_to_server" 40 | } 41 | ] 42 | }, 43 | "firewall_rules": { 44 | 45 | "firewall_policy_comment": "# Allowed value is one from: DROP_SILENTLY, DROP_WITH_DIAMETER_ERROR, DNAT_TO_HONEYPOT, ALLOW", 46 | "firewall_policy": "DROP_SILENTLY", 47 | 48 | "diameter": { 49 | "origin_realm_blacklist": [ 50 | "blacklisted.example.org" 51 | ], 52 | "application_id_whitelist": [ 53 | "0", 54 | "16777360", 55 | "16777251" 56 | ], 57 | "command_code_blacklist": [ 58 | "8388620", 59 | "8388622" 60 | ], 61 | "cat2_command_code_blacklist": [ 62 | "317", 63 | "319", 64 | "329" 65 | ] 66 | }, 67 | 68 | "lua": { 69 | "lua_comment": "# LUA Blacklist firewall rules. Currently supported LUA variables are: diameter_orig_host, diameter_orig_realm, diameter_dest_host, diameter_dest_realm, diameter_cc, diameter_ai, diameter_imsi, diameter_msisdn", 70 | "blacklist_rules": [ 71 | "diameter_orig_realm == 'exchangeTestA.example.org'", 72 | "diameter_orig_realm == 'exchangeTestB.example.org'" 73 | ] 74 | }, 75 | 76 | "ids": { 77 | "ids_comment": "# IDS API. After evaluating internal firewall rules, the external IDS system can be used to check message (e.g. Cat3). If not required remove this ids json block from config.", 78 | 79 | "ids_api_type_comment": "# Type of connector. Currently supported only REST", 80 | "ids_api_type": "REST", 81 | "ids_servers": [ 82 | { 83 | "host": "https://localhost:8443/diameterfw_api/1.0/eval_diameter_message_in_ids", 84 | "username": "user", 85 | "password": "password" 86 | } 87 | ] 88 | }, 89 | 90 | "mthreat": { 91 | "mthreat_comment": "# mThreat API. If the message matches internal firewall or IDS rules, then the firewall can report the event in anonymized way to mThreat. If not required remove this mthreat json block from config.", 92 | 93 | "mthreat_api_type_comment": "# Type of connector. Currently supported only REST", 94 | "mthreat_api_type": "REST", 95 | "mthreat_salt_comment": "# Change the salt value for unique anonymization", 96 | "mthreat_salt": "XVm4AoKrkicsgEcx", 97 | "mthreat_servers": [ 98 | { 99 | "host": "https://127.0.0.1:8444/mthreat_api/1.0/send_diameter_alert_to_mthreat", 100 | "username": "user", 101 | "password": "pass" 102 | } 103 | ] 104 | } 105 | }, 106 | "encryption_rules": { 107 | "destination_realm_encryption": [ 108 | { 109 | "destination_realm": "###exchange.example.org", 110 | "public_key_type": "RSA", 111 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB" 112 | } 113 | ], 114 | "destination_realm_decryption": [ 115 | { 116 | "destination_realm": "exchangeClient.example.org", 117 | "public_key_type": "RSA", 118 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 119 | "private_key_type": "RSA", 120 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 121 | } 122 | ], 123 | "autodiscovery_comment": "# If enabled, then the special diameter command code is used to retrieve the foreign SigFW encryption public key.", 124 | "autodiscovery": "true", 125 | "dtls_encryption_comment": "# If dtls_encryption is enabled, than the autodiscovery is not used anymore. DTLS handshake in Diameter protocol is used instead. For DTLS handshake the trustore and keystore is used. After successful handshake the DTLS encryption is used. Signature_rules, can be still used together with DTLS, however DTLS provides also integrity protection so they are not mandatory.", 126 | "dtls_encryption": "true" 127 | }, 128 | "signature_rules": { 129 | "origin_realm_verify": [ 130 | { 131 | "origin_realm": "exchange.example.org", 132 | "signing_realm_comment": "Subject name which is issuing signature", 133 | "signing_realm": "exchange.example.org", 134 | "public_key_type": "RSA", 135 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB" 136 | } 137 | ], 138 | "origin_realm_signing": [ 139 | { 140 | "origin_realm": "exchangeClient.example.org", 141 | "signing_realm_comment": "Subject name which is issuing signature", 142 | "signing_realm": "exchangeClient.example.org", 143 | "public_key_type": "RSA", 144 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 145 | "private_key_type": "RSA", 146 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 147 | } 148 | ] 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/diameterfw_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "operator_configuration": { 3 | 4 | "Home_IMSI_prefixes_comment": "# Identification Home IMSI range for HPLMN network, used to identify home subscribers", 5 | "Home_IMSI_prefixes": [ 6 | "111111" 7 | ], 8 | "Home_Diameter_Realm_list_comment": "Operator Diameter Internal Realm list, used to identify incoming and outgoing traffic of HPLMN", 9 | "Home_Diameter_Realm_list": [ 10 | "exchange.example.org" 11 | ] 12 | }, 13 | "sigfw_configuration": { 14 | "sctp": { 15 | "sctp_management_name": "sctp_mgmt", 16 | "sctp_max_in_streams": "32", 17 | "sctp_max_out_streams": "32", 18 | "sctp_server": [ 19 | { 20 | "server_name": "sctp_server", 21 | "host_address": "127.0.0.1", 22 | "port": "3870" 23 | } 24 | ], 25 | "sctp_server_association": [ 26 | { 27 | "peer_address": "127.0.0.1", 28 | "peer_port": "13870", 29 | "server_name": "sctp_server", 30 | "assoc_name": "sctp_from_client_to_firewall" 31 | } 32 | ], 33 | "sctp_association": [ 34 | { 35 | "host_address": "127.0.0.1", 36 | "host_port": "13869", 37 | "peer_address": "127.0.0.1", 38 | "peer_port": "3868", 39 | "assoc_name": "sctp_from_firewall_to_server" 40 | } 41 | ] 42 | }, 43 | "firewall_rules": { 44 | 45 | "firewall_policy_comment": "# Allowed value is one from: DROP_SILENTLY, DROP_WITH_DIAMETER_ERROR, DNAT_TO_HONEYPOT, ALLOW", 46 | "firewall_policy": "DROP_SILENTLY", 47 | 48 | "diameter": { 49 | "origin_realm_blacklist": [ 50 | "blacklisted.example.org" 51 | ], 52 | "application_id_whitelist": [ 53 | "0", 54 | "16777360", 55 | "16777251" 56 | ], 57 | "command_code_blacklist": [ 58 | "8388620", 59 | "8388622" 60 | ], 61 | "cat2_command_code_blacklist": [ 62 | "317", 63 | "319", 64 | "329" 65 | ] 66 | }, 67 | 68 | "lua": { 69 | "lua_comment": "# LUA Blacklist firewall rules. Currently supported LUA variables are: diameter_orig_host, diameter_orig_realm, diameter_dest_host, diameter_dest_realm, diameter_cc, diameter_ai, diameter_imsi, diameter_msisdn", 70 | "blacklist_rules": [ 71 | "diameter_orig_realm == 'exchangeTestA.example.org'", 72 | "diameter_orig_realm == 'exchangeTestB.example.org'" 73 | ] 74 | }, 75 | 76 | "ids": { 77 | "ids_comment": "# IDS API. After evaluating internal firewall rules, the external IDS system can be used to check message (e.g. Cat3). If not required remove this ids json block from config.", 78 | 79 | "ids_api_type_comment": "# Type of connector. Currently supported only REST", 80 | "ids_api_type": "REST", 81 | "ids_servers": [ 82 | { 83 | "host": "https://localhost:8443/diameterfw_api/1.0/eval_diameter_message_in_ids", 84 | "username": "user", 85 | "password": "password" 86 | } 87 | ] 88 | }, 89 | 90 | "mthreat": { 91 | "mthreat_comment": "# mThreat API. If the message matches internal firewall or IDS rules, then the firewall can report the event in anonymized way to mThreat. If not required remove this mthreat json block from config.", 92 | 93 | "mthreat_api_type_comment": "# Type of connector. Currently supported only REST", 94 | "mthreat_api_type": "REST", 95 | "mthreat_salt_comment": "# Change the salt value for unique anonymization", 96 | "mthreat_salt": "XVm4AoKrkicsgEcx", 97 | "mthreat_servers": [ 98 | { 99 | "host": "https://127.0.0.1:8444/mthreat_api/1.0/send_diameter_alert_to_mthreat", 100 | "username": "user", 101 | "password": "pass" 102 | } 103 | ] 104 | } 105 | }, 106 | "encryption_rules": { 107 | "destination_realm_encryption": [ 108 | { 109 | "destination_realm": "###exchangeClient.example.org", 110 | "public_key_type": "RSA", 111 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB" 112 | } 113 | ], 114 | "destination_realm_decryption": [ 115 | { 116 | "destination_realm": "exchange.example.org", 117 | "public_key_type": "RSA", 118 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 119 | "private_key_type": "RSA", 120 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 121 | } 122 | ], 123 | "autodiscovery_comment": "# If enabled, then the special diameter command code is used to retrieve the foreign SigFW encryption public key.", 124 | "autodiscovery": "true", 125 | "dtls_encryption_comment": "# If dtls_encryption is enabled, than the autodiscovery is not used anymore. DTLS handshake in Diameter protocol is used instead. For DTLS handshake the trustore and keystore is used. After successful handshake the DTLS encryption is used. Signature_rules, can be still used together with DTLS, however DTLS provides also integrity protection so they are not mandatory.", 126 | "dtls_encryption": "true" 127 | }, 128 | "signature_rules": { 129 | "origin_realm_verify": [ 130 | { 131 | "origin_realm": "exchangeClient.example.org", 132 | "signing_realm_comment": "Subject name which is issuing signature", 133 | "signing_realm": "exchangeClient.example.org", 134 | "public_key_type": "RSA", 135 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB" 136 | } 137 | ], 138 | "origin_realm_signing": [ 139 | { 140 | "origin_realm": "exchange.example.org", 141 | "signing_realm_comment": "Subject name which is issuing signature", 142 | "signing_realm": "exchange.example.org", 143 | "public_key_type": "RSA", 144 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 145 | "private_key_type": "RSA", 146 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 147 | } 148 | ] 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/diameterfw_junit.json: -------------------------------------------------------------------------------- 1 | { 2 | "operator_configuration": { 3 | 4 | "Home_IMSI_prefixes_comment": "# Identification Home IMSI range for HPLMN network, used to identify home subscribers", 5 | "Home_IMSI_prefixes": [ 6 | "111111" 7 | ], 8 | "Home_Diameter_Realm_list_comment": "Operator Diameter Internal Realm list, used to identify incoming and outgoing traffic of HPLMN", 9 | "Home_Diameter_Realm_list": [ 10 | "exchange.example.org" 11 | ] 12 | }, 13 | "sigfw_configuration": { 14 | "sctp": { 15 | "sctp_management_name": "sctp_mgmt", 16 | "sctp_max_in_streams": "32", 17 | "sctp_max_out_streams": "32", 18 | "sctp_server": [ 19 | { 20 | "server_name": "sctp_server", 21 | "host_address": "127.0.0.1", 22 | "port": "3869" 23 | } 24 | ], 25 | "sctp_server_association": [ 26 | { 27 | "peer_address": "127.0.0.1", 28 | "peer_port": "13868", 29 | "server_name": "sctp_server", 30 | "assoc_name": "sctp_from_client_to_firewall" 31 | } 32 | ], 33 | "sctp_association": [ 34 | { 35 | "host_address": "127.0.0.1", 36 | "host_port": "13869", 37 | "peer_address": "127.0.0.1", 38 | "peer_port": "3868", 39 | "assoc_name": "sctp_from_firewall_to_server" 40 | } 41 | ] 42 | }, 43 | "firewall_rules": { 44 | "firewall_rules_comment": "# Firewall filtering rules configuration", 45 | 46 | "firewall_policy_comment": "# Allowed value is one from: DROP_SILENTLY, DROP_WITH_DIAMETER_ERROR, DNAT_TO_HONEYPOT, ALLOW", 47 | "firewall_policy": "DNAT_TO_HONEYPOT", 48 | 49 | "diameter": { 50 | "origin_realm_blacklist": [ 51 | "blacklisted.example.org" 52 | ], 53 | "application_id_whitelist": [ 54 | "0", 55 | "16777251" 56 | ], 57 | "command_code_blacklist": [ 58 | "8388620", 59 | "8388622" 60 | ], 61 | "cat2_command_code_blacklist": [ 62 | "317", 63 | "319", 64 | "329" 65 | ] 66 | }, 67 | 68 | "lua": { 69 | "lua_comment": "# LUA Blacklist firewall rules. Currently supported LUA variables are: diameter_orig_host, diameter_orig_realm, diameter_dest_host, diameter_dest_realm, diameter_cc, diameter_ai, diameter_imsi, diameter_msisdn", 70 | "blacklist_rules": [ 71 | "diameter_orig_realm == 'exchangeClient.example.org'", 72 | "diameter_orig_realm == 'exchangeClientB.example.org'" 73 | ] 74 | }, 75 | 76 | "ids": { 77 | "ids_comment": "# IDS API. After evaluating internal firewall rules, the external IDS system can be used to check message (e.g. Cat3). If not required remove this ids json block from config.", 78 | 79 | "ids_api_type_comment": "# Type of connector. Currently supported only REST", 80 | "ids_api_type": "REST", 81 | "ids_servers": [ 82 | { 83 | "host": "https://localhost:8443/diameterfw_api/1.0/eval_diameter_message_in_ids", 84 | "username": "user", 85 | "password": "password" 86 | } 87 | ] 88 | }, 89 | 90 | "mthreat": { 91 | "mthreat_comment": "# mThreat API. If the message matches internal firewall or IDS rules, then the firewall can report the event in anonymized way to mThreat. If not required remove this mthreat json block from config.", 92 | 93 | "mthreat_api_type_comment": "# Type of connector. Currently supported only REST", 94 | "mthreat_api_type": "REST", 95 | "mthreat_salt_comment": "# Change the salt value for unique anonymization", 96 | "mthreat_salt": "XVm4AoKrkicsgEcx", 97 | "mthreat_servers": [ 98 | { 99 | "host": "https://127.0.0.1:8444/mthreat_api/1.0/send_diameter_alert_to_mthreat", 100 | "username": "user", 101 | "password": "pass" 102 | } 103 | ] 104 | }, 105 | 106 | "honeypot": { 107 | "honeypot_comment": "# Honeypot configuration. Only used if firewall policy is DNAT_TO_HONEYPOT", 108 | 109 | "diameter_host_comment": "# The firewall after detecting the message will perform DNAT to the following Diameter address.", 110 | "diameter_host": "127.0.0.1", 111 | "diameter_realm": "honeypot.example.org", 112 | 113 | "dnat_session_expiration_timeout_comment": "# After matching the firewall or IDS rules, the firewall will apply DNAT for Diameter address for the defined number of seconds", 114 | "dnat_session_expiration_timeout": "30" 115 | } 116 | }, 117 | "encryption_rules": { 118 | "destination_realm_encryption": [ 119 | ], 120 | "destination_realm_decryption": [ 121 | { 122 | "destination_realm": "exchange.example.org", 123 | "public_key_type": "RSA", 124 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 125 | "private_key_type": "RSA", 126 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 127 | } 128 | ], 129 | "autodiscovery": "true", 130 | "dtls_encryption": "true" 131 | }, 132 | "signature_rules": { 133 | "origin_realm_verify": [ 134 | { 135 | "origin_realm": "exchange.example.org", 136 | "public_key_type": "RSA", 137 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB" 138 | } 139 | ], 140 | "origin_realm_signing": [ 141 | ] 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/diameterfw_keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P1sec/SigFW/5942c557696b1351963727812fc35cc315ebcce4/sigfw/sigfw.sigfw/diameterfw_keystore -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P1sec/SigFW/5942c557696b1351963727812fc35cc315ebcce4/sigfw/sigfw.sigfw/keystore -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/maplog.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P1sec/SigFW/5942c557696b1351963727812fc35cc315ebcce4/sigfw/sigfw.sigfw/maplog.txt -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/nbactions-Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:1.5.0:exec 11 | 12 | 13 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 14 | java 15 | ${packageClassName} 16 | -Xms256m -Xmx256m 17 | 18 | 19 | 20 | 21 | debug 22 | 23 | jar 24 | 25 | 26 | process-classes 27 | org.codehaus.mojo:exec-maven-plugin:1.5.0:exec 28 | 29 | 30 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 31 | java 32 | true 33 | ${packageClassName} 34 | -Xms256m -Xmx256m -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} 35 | 36 | 37 | 38 | 39 | profile 40 | 41 | jar 42 | 43 | 44 | process-classes 45 | org.codehaus.mojo:exec-maven-plugin:1.5.0:exec 46 | 47 | 48 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 49 | java 50 | ${packageClassName} 51 | -Xms256m -Xmx256m 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | build 5 | 6 | * 7 | 8 | 9 | install 10 | 11 | 12 | true 13 | 14 | 15 | 16 | run 17 | 18 | jar 19 | 20 | 21 | 22 | java 23 | 24 | 25 | 26 | debug 27 | 28 | jar 29 | 30 | 31 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} 32 | java 33 | true 34 | 35 | 36 | 37 | profile 38 | 39 | jar 40 | 41 | 42 | java 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/realm.properties: -------------------------------------------------------------------------------- 1 | # 2 | # This file defines users passwords and roles for a HashUserRealm 3 | # 4 | # The format is 5 | # : [, ...] 6 | # 7 | # Passwords may be clear text, obfuscated or checksummed. The class 8 | # org.eclipse.jetty.util.security.Password should be used to generate obfuscated 9 | # passwords or password checksums 10 | # 11 | # If DIGEST Authentication is used, the password must be in a recoverable 12 | # format, either plain text or OBF:. 13 | # 14 | #jetty: MD5:164c88b302622e17050af52c89945d44,user 15 | #admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin,user 16 | #other: OBF:1xmk1w261u9r1w1c1xmq,user 17 | #plain: plain,user 18 | user: password,user 19 | #digest: MD5:357fe95bdc7fe025c7d2ef9b662422fe,user 20 | #user: OBF:19xe1l101gn41qxo1kff1gez1w8b1t2f1z071sq31d2o1mzk1ke11ndw1t3b1lmj1lj71t2v1nbu1ked1mxq1d3i1snn1z0n1t3r1w9f1ggz1kcz1qw21gn21ky219x8,user 21 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/diameterfw/DatagramOverDiameterPacket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2021, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package diameterfw; 25 | 26 | import java.net.DatagramPacket; 27 | 28 | /** 29 | * 30 | * @author Martin Kacer 31 | */ 32 | public class DatagramOverDiameterPacket { 33 | private String peer_realm; 34 | private DatagramPacket p; 35 | 36 | public DatagramOverDiameterPacket(String peer_realm, DatagramPacket p) { 37 | this.peer_realm = peer_realm; 38 | this.p = p; 39 | } 40 | 41 | public String getPeer_realm() { 42 | return peer_realm; 43 | } 44 | 45 | public DatagramPacket getP() { 46 | return p; 47 | } 48 | 49 | public void setPeer_realm(String peer_realm) { 50 | this.peer_realm = peer_realm; 51 | } 52 | 53 | public void setP(DatagramPacket p) { 54 | this.p = p; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/diameterfw/DiameterFirewallAPI_V1_0.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package diameterfw; 25 | import java.util.SortedMap; 26 | import jakarta.ws.rs.Consumes; 27 | import jakarta.ws.rs.Produces; 28 | import jakarta.ws.rs.GET; 29 | import jakarta.ws.rs.MatrixParam; 30 | import jakarta.ws.rs.POST; 31 | import jakarta.ws.rs.Path; 32 | import jakarta.ws.rs.core.Response; 33 | 34 | /** 35 | * 36 | * @author Martin Kacer 37 | */ 38 | @Path("diameterfw_api/1.0") 39 | public class DiameterFirewallAPI_V1_0 { 40 | 41 | @GET 42 | @Consumes("text/plain") 43 | @Produces("text/plain") 44 | @Path("diameter_origin_realm_blacklist_add") 45 | public String diameter_origin_realm_blacklist_add(@MatrixParam("realm") String realm) { 46 | DiameterFirewallConfig.diameter_origin_realm_blacklist.put(realm, ""); 47 | return "Successful"; 48 | } 49 | 50 | @GET 51 | @Consumes("text/plain") 52 | @Produces("text/plain") 53 | @Path("diameter_origin_realm_blacklist_remove") 54 | public String diameter_origin_realm_blacklist_remove(@MatrixParam("realm") String realm) { 55 | DiameterFirewallConfig.diameter_origin_realm_blacklist.remove(realm); 56 | return "Successful"; 57 | } 58 | 59 | @GET 60 | @Consumes("text/plain") 61 | @Produces("text/plain") 62 | @Path("diameter_origin_realm_blacklist_list") 63 | public String diameter_origin_realm_blacklist_list() { 64 | String s = ""; 65 | for (SortedMap.Entry entry : DiameterFirewallConfig.diameter_origin_realm_blacklist.entrySet()) { 66 | s += entry.getKey() + "\n"; 67 | } 68 | return s; 69 | } 70 | 71 | @GET 72 | @Consumes("text/plain") 73 | @Produces("text/plain") 74 | @Path("diameter_application_id_whitelist_add") 75 | public String diameter_application_id_whitelist_add(@MatrixParam("ai") int ai) { 76 | DiameterFirewallConfig.diameter_application_id_whitelist.put((new Integer(ai)).toString(), ""); 77 | return "Successful"; 78 | } 79 | 80 | @GET 81 | @Consumes("text/plain") 82 | @Produces("text/plain") 83 | @Path("diameter_application_id_whitelist_remove") 84 | public String diameter_application_id_whitelist_remove(@MatrixParam("ai") int ai) { 85 | DiameterFirewallConfig.diameter_application_id_whitelist.remove((new Integer(ai)).toString()); 86 | return "Successful"; 87 | } 88 | 89 | @GET 90 | @Consumes("text/plain") 91 | @Produces("text/plain") 92 | @Path("diameter_application_id_whitelist_list") 93 | public String diameter_application_id_whitelist_list() { 94 | String s = ""; 95 | for (SortedMap.Entry entry : DiameterFirewallConfig.diameter_application_id_whitelist.entrySet()) { 96 | s += entry.getKey() + "\n"; 97 | } 98 | return s; 99 | } 100 | 101 | @GET 102 | @Consumes("text/plain") 103 | @Produces("text/plain") 104 | @Path("diameter_command_code_blacklist_add") 105 | public String diameter_command_code_blacklist_add(@MatrixParam("cc") int cc) { 106 | DiameterFirewallConfig.diameter_command_code_blacklist.put((new Integer(cc)).toString(), ""); 107 | return "Successful"; 108 | } 109 | 110 | @GET 111 | @Consumes("text/plain") 112 | @Produces("text/plain") 113 | @Path("diameter_command_code_blacklist_remove") 114 | public String diameter_command_code_blacklist_remove(@MatrixParam("cc") int cc) { 115 | DiameterFirewallConfig.diameter_command_code_blacklist.remove((new Integer(cc)).toString()); 116 | return "Successful"; 117 | } 118 | 119 | @GET 120 | @Consumes("text/plain") 121 | @Produces("text/plain") 122 | @Path("diameter_command_code_blacklist_list") 123 | public String diameter_command_code_blacklist_list() { 124 | String s = ""; 125 | for (SortedMap.Entry entry : DiameterFirewallConfig.diameter_command_code_blacklist.entrySet()) { 126 | s += entry.getKey() + "\n"; 127 | } 128 | return s; 129 | } 130 | 131 | /*@GET 132 | @Consumes("text/plain") 133 | @Produces("text/plain") 134 | @Path("get_diameter_trace") 135 | public String get_diameter_trace(@MatrixParam("n") int n) { 136 | String s = ""; 137 | int i = n; 138 | while (i > 0 && DiameterFirewall.diameter_fifo.size() > 0 ) { 139 | s += DiameterFirewall.diameter_fifo.pop() + "\n"; 140 | i--; 141 | } 142 | return s; 143 | }*/ 144 | 145 | @GET 146 | @Consumes("text/plain") 147 | @Produces("text/plain") 148 | @Path("get_status") 149 | public String get_status() { 150 | return DiameterFirewall.getStatus(); 151 | } 152 | 153 | // IDS integration API - used only for test purposes on localhost simulating IDS backend 154 | @GET 155 | @Consumes("text/plain") 156 | @Produces("text/plain") 157 | @Path("eval_diameter_message_in_ids") 158 | public String eval_diameter_message_in_ids(@MatrixParam("diameter_raw") String diameter_raw) { 159 | return "1"; 160 | } 161 | 162 | // mThreat integration API - used only for test purposes on localhost simulating mThreat backend 163 | @POST 164 | @Consumes("text/plain") 165 | @Produces("text/plain") 166 | @Path("send_diameter_alert_to_mthreat") 167 | public Response send_diameter_alert_to_mthreat(String alert) { 168 | String output = alert; 169 | return Response.status(200).entity(output).build(); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/diameterfw/DiameterFirewallFirstInstance.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package diameterfw; 25 | 26 | import diameterfw.DiameterFirewall; 27 | /** 28 | * First firewall instance used for testing encryption and signatures. 29 | * 30 | * @author Martin Kacer 31 | * 32 | */ 33 | public class DiameterFirewallFirstInstance { 34 | public static void main(String[] args) throws Exception { 35 | String[] a = new String[1]; 36 | a[0] = "diameterfw_1.json"; 37 | DiameterFirewall.main(a); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/diameterfw/DiameterFirewallSecondInstance.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package diameterfw; 25 | 26 | import diameterfw.DiameterFirewall; 27 | /** 28 | * First firewall instance used for testing encryption and signatures. 29 | * 30 | * @author Martin Kacer 31 | * 32 | */ 33 | public class DiameterFirewallSecondInstance { 34 | public static void main(String[] args) throws Exception { 35 | String[] a = new String[1]; 36 | a[0] = "diameterfw_2.json"; 37 | DiameterFirewall.main(a); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/common/AvpImpl.java: -------------------------------------------------------------------------------- 1 | // workaround because in jDiameter AvpImpl is not public 2 | // TODO submit to jDiameter to make AvpImpl public 3 | 4 | /* 5 | * TeleStax, Open Source Cloud Communications 6 | * Copyright 2011-2016, TeleStax Inc. and individual contributors 7 | * by the @authors tag. 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * under the terms of the GNU Affero General Public License as 11 | * published by the Free Software Foundation; either version 3 of 12 | * the License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Affero General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Affero General Public License 20 | * along with this program. If not, see 21 | * 22 | * This file incorporates work covered by the following copyright and 23 | * permission notice: 24 | * 25 | * JBoss, Home of Professional Open Source 26 | * Copyright 2007-2011, Red Hat, Inc. and individual contributors 27 | * by the @authors tag. See the copyright.txt in the distribution for a 28 | * full listing of individual contributors. 29 | * 30 | * This is free software; you can redistribute it and/or modify it 31 | * under the terms of the GNU Lesser General Public License as 32 | * published by the Free Software Foundation; either version 2.1 of 33 | * the License, or (at your option) any later version. 34 | * 35 | * This software is distributed in the hope that it will be useful, 36 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 38 | * Lesser General Public License for more details. 39 | * 40 | * You should have received a copy of the GNU Lesser General Public 41 | * License along with this software; if not, write to the Free 42 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 43 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 44 | */ 45 | 46 | package sigfw.common; 47 | 48 | import java.net.InetAddress; 49 | import java.net.URISyntaxException; 50 | import java.net.UnknownServiceException; 51 | import java.util.Date; 52 | 53 | import org.jdiameter.api.Avp; 54 | import org.jdiameter.api.AvpDataException; 55 | import org.jdiameter.api.AvpSet; 56 | import org.jdiameter.api.InternalException; 57 | import org.jdiameter.api.URI; 58 | import org.jdiameter.client.impl.parser.ElementParser; 59 | import org.slf4j.Logger; 60 | import org.slf4j.LoggerFactory; 61 | 62 | /** 63 | * 64 | * @author erick.svenson@yahoo.com 65 | * @author Alexandre Mendonca 66 | * @author Bartosz Baranowski 67 | */ 68 | public class AvpImpl implements Avp { 69 | 70 | private static final long serialVersionUID = 1L; 71 | private static final ElementParser parser = new ElementParser(); 72 | int avpCode; 73 | public long vendorID; 74 | 75 | public boolean isMandatory = false; 76 | boolean isEncrypted = false; 77 | boolean isVendorSpecific = false; 78 | 79 | byte[] rawData = new byte[0]; 80 | AvpSet groupedData; 81 | 82 | private static final Logger logger = LoggerFactory.getLogger(AvpImpl.class); 83 | 84 | public AvpImpl(int code, int flags, long vnd, byte[] data) { 85 | avpCode = code; 86 | // 87 | isMandatory = (flags & 0x40) != 0; 88 | isEncrypted = (flags & 0x20) != 0; 89 | isVendorSpecific = (flags & 0x80) != 0; 90 | // 91 | vendorID = vnd; 92 | rawData = data; 93 | } 94 | 95 | AvpImpl(Avp avp) { 96 | avpCode = avp.getCode(); 97 | vendorID = avp.getVendorId(); 98 | isMandatory = avp.isMandatory(); 99 | isEncrypted = avp.isEncrypted(); 100 | isVendorSpecific = avp.isVendorId(); 101 | try { 102 | rawData = avp.getRaw(); 103 | if (rawData == null || rawData.length == 0) { 104 | groupedData = avp.getGrouped(); 105 | } 106 | } 107 | catch (AvpDataException e) { 108 | logger.debug("Can not create Avp", e); 109 | } 110 | } 111 | 112 | AvpImpl (int newCode, Avp avp) { 113 | this(avp); 114 | avpCode = newCode; 115 | } 116 | 117 | @Override 118 | public int getCode() { 119 | return avpCode; 120 | } 121 | 122 | @Override 123 | public boolean isVendorId() { 124 | return isVendorSpecific; 125 | } 126 | 127 | @Override 128 | public boolean isMandatory() { 129 | return isMandatory; 130 | } 131 | 132 | @Override 133 | public boolean isEncrypted() { 134 | return isEncrypted; 135 | } 136 | 137 | @Override 138 | public long getVendorId() { 139 | return vendorID; 140 | } 141 | 142 | @Override 143 | public byte[] getRaw() throws AvpDataException { 144 | return rawData; 145 | } 146 | 147 | @Override 148 | public byte[] getOctetString() throws AvpDataException { 149 | return rawData; 150 | } 151 | 152 | @Override 153 | public String getUTF8String() throws AvpDataException { 154 | try { 155 | return parser.bytesToUtf8String(rawData); 156 | } 157 | catch (Exception e) { 158 | throw new AvpDataException(e, this); 159 | } 160 | } 161 | 162 | @Override 163 | public int getInteger32() throws AvpDataException { 164 | try { 165 | return parser.bytesToInt(rawData); 166 | } 167 | catch (Exception e) { 168 | throw new AvpDataException(e, this); 169 | } 170 | } 171 | 172 | @Override 173 | public long getInteger64() throws AvpDataException { 174 | try { 175 | return parser.bytesToLong(rawData); 176 | } 177 | catch (Exception e) { 178 | throw new AvpDataException(e, this); 179 | } 180 | } 181 | 182 | @Override 183 | public long getUnsigned32() throws AvpDataException { 184 | try { 185 | byte[] u32ext = new byte[8]; 186 | System.arraycopy(rawData, 0, u32ext, 4, 4); 187 | return parser.bytesToLong(u32ext); 188 | } 189 | catch (Exception e) { 190 | throw new AvpDataException(e, this); 191 | } 192 | } 193 | 194 | @Override 195 | public long getUnsigned64() throws AvpDataException { 196 | try { 197 | return parser.bytesToLong(rawData); 198 | } 199 | catch (Exception e) { 200 | throw new AvpDataException(e, this); 201 | } 202 | } 203 | 204 | @Override 205 | public float getFloat32() throws AvpDataException { 206 | try { 207 | return parser.bytesToFloat(rawData); 208 | } 209 | catch (Exception e) { 210 | throw new AvpDataException(e, this); 211 | } 212 | } 213 | 214 | @Override 215 | public double getFloat64() throws AvpDataException { 216 | try { 217 | return parser.bytesToDouble(rawData); 218 | } 219 | catch (Exception e) { 220 | throw new AvpDataException(e, this); 221 | } 222 | } 223 | 224 | @Override 225 | public InetAddress getAddress() throws AvpDataException { 226 | try { 227 | return parser.bytesToAddress(rawData); 228 | } 229 | catch (Exception e) { 230 | throw new AvpDataException(e, this); 231 | } 232 | } 233 | 234 | @Override 235 | public Date getTime() throws AvpDataException { 236 | try { 237 | return parser.bytesToDate(rawData); 238 | } 239 | catch (Exception e) { 240 | throw new AvpDataException(e, this); 241 | } 242 | } 243 | 244 | @Override 245 | public String getDiameterIdentity() throws AvpDataException { 246 | try { 247 | return parser.bytesToOctetString(rawData); 248 | } 249 | catch (Exception e) { 250 | throw new AvpDataException(e, this); 251 | } 252 | } 253 | 254 | @Override 255 | public URI getDiameterURI() throws AvpDataException { 256 | try { 257 | return new URI(parser.bytesToOctetString(rawData)); 258 | } 259 | catch (URISyntaxException e) { 260 | throw new AvpDataException(e, this); 261 | } 262 | catch (UnknownServiceException e) { 263 | throw new AvpDataException(e, this); 264 | } 265 | } 266 | 267 | @Override 268 | public AvpSet getGrouped() throws AvpDataException { 269 | try { 270 | if (groupedData == null) { 271 | groupedData = parser.decodeAvpSet(rawData); 272 | rawData = new byte[0]; 273 | } 274 | return groupedData; 275 | } 276 | catch (Exception e) { 277 | throw new AvpDataException(e, this); 278 | } 279 | } 280 | 281 | @Override 282 | public boolean isWrapperFor(Class aClass) throws InternalException { 283 | return false; 284 | } 285 | 286 | @Override 287 | public T unwrap(Class aClass) throws InternalException { 288 | return null; 289 | } 290 | 291 | @Override 292 | public byte[] getRawData() { 293 | return (rawData == null || rawData.length == 0) ? parser.encodeAvpSet(groupedData) : rawData; 294 | } 295 | 296 | // Caching toString.. Avp shouldn't be modified once created. 297 | private String toString; 298 | 299 | @Override 300 | public String toString() { 301 | if (toString == null) { 302 | this.toString = new StringBuffer("AvpImpl [avpCode=").append(avpCode).append(", vendorID=").append(vendorID).append("]@").append(super.hashCode()). 303 | toString(); 304 | } 305 | 306 | return this.toString; 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/common/ExternalFirewallRules.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | * Modified jSS7 SctpClient.java example 24 | */ 25 | package sigfw.common; 26 | 27 | import java.io.InputStream; 28 | import java.util.Properties; 29 | import org.apache.log4j.Logger; 30 | import org.apache.log4j.PropertyConfigurator; 31 | import org.mobicents.protocols.api.Association; 32 | import org.mobicents.protocols.api.PayloadData; 33 | import org.mobicents.protocols.ss7.sccp.message.SccpDataMessage; 34 | import com.p1sec.sigfw.SigFW_interface.FirewallRulesInterface; 35 | 36 | /** 37 | * 38 | * @author Martin Kacer 39 | */ 40 | public class ExternalFirewallRules implements FirewallRulesInterface { 41 | protected static final Logger logger = Logger.getLogger(ExternalFirewallRules.class); 42 | static { 43 | configLog4j(); 44 | } 45 | 46 | protected static void configLog4j() { 47 | InputStream inStreamLog4j = ExternalFirewallRules.class.getClassLoader().getResourceAsStream("log4j.properties"); 48 | Properties propertiesLog4j = new Properties(); 49 | try { 50 | propertiesLog4j.load(inStreamLog4j); 51 | PropertyConfigurator.configure(propertiesLog4j); 52 | } catch (Exception e) { 53 | e.printStackTrace(); 54 | } 55 | 56 | logger.debug("log4j configured"); 57 | 58 | } 59 | 60 | public boolean ss7FirewallRules(SccpDataMessage message) { 61 | logger.debug("ExternalFirewallRules::ss7FirewallRules"); 62 | 63 | return true; 64 | } 65 | 66 | public boolean diameterFirewallRules(Association asctn, PayloadData pd) { 67 | logger.debug("ExternalFirewallRules::diameterFirewallRules"); 68 | 69 | return true; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/common/Utils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | * Modified jSS7 SctpClient.java example 24 | */ 25 | package sigfw.common; 26 | 27 | import java.io.ByteArrayInputStream; 28 | import java.io.DataInputStream; 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.util.Arrays; 32 | import java.util.Properties; 33 | import org.apache.log4j.Logger; 34 | import org.apache.log4j.PropertyConfigurator; 35 | import org.jdiameter.api.Avp; 36 | import org.jdiameter.api.AvpDataException; 37 | import org.jdiameter.api.AvpSet; 38 | 39 | /** 40 | * 41 | * @author Martin Kacer 42 | */ 43 | public class Utils { 44 | 45 | protected static final Logger logger = Logger.getLogger(Crypto.class); 46 | static { 47 | configLog4j(); 48 | } 49 | 50 | protected static void configLog4j() { 51 | InputStream inStreamLog4j = Utils.class.getClassLoader().getResourceAsStream("log4j.properties"); 52 | Properties propertiesLog4j = new Properties(); 53 | try { 54 | propertiesLog4j.load(inStreamLog4j); 55 | PropertyConfigurator.configure(propertiesLog4j); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | } 59 | 60 | logger.debug("log4j configured"); 61 | } 62 | 63 | /** 64 | * Method to split byte array 65 | * 66 | * @param bytes original byte array 67 | * @param chunkSize chunk size 68 | * @return two dimensional byte array 69 | */ 70 | public static byte[][] splitByteArray(byte[] bytes, int chunkSize) { 71 | int len = bytes.length; 72 | int counter = 0; 73 | 74 | int size = ((bytes.length - 1) / chunkSize) + 1; 75 | byte[][] newArray = new byte[size][]; 76 | 77 | for (int i = 0; i < len - chunkSize + 1; i += chunkSize) { 78 | newArray[counter++] = Arrays.copyOfRange(bytes, i, i + chunkSize); 79 | } 80 | 81 | if (len % chunkSize != 0) { 82 | newArray[counter] = Arrays.copyOfRange(bytes, len - len % chunkSize, len); 83 | } 84 | 85 | return newArray; 86 | } 87 | 88 | /** 89 | * Concatenate two byte arrays 90 | * 91 | * @param bytes first byte array 92 | * @param chunkSize second byte array 93 | * @return concatenated byte array 94 | */ 95 | public static byte[] concatByteArray(byte[] a, byte[] b) { 96 | if (a == null) { 97 | return b; 98 | } 99 | if (b == null) { 100 | return a; 101 | } 102 | 103 | byte[] r = new byte[a.length + b.length]; 104 | 105 | System.arraycopy(a, 0, r, 0, a.length); 106 | 107 | System.arraycopy(b, 0, r, a.length, b.length); 108 | 109 | return r; 110 | } 111 | 112 | // workaround because in jDiameter AvpImpl, AvpSetImpl is not public 113 | // TODO submit to jDiameter to make AvpImpl, AvpSetImpl public 114 | private static final int INT32_SIZE = 4; 115 | 116 | public static byte[] int32ToBytes(int value) { 117 | byte[] bytes = new byte[INT32_SIZE]; 118 | bytes[0] = (byte) (value >> 24 & 0xFF); 119 | bytes[1] = (byte) (value >> 16 & 0xFF); 120 | bytes[2] = (byte) (value >> 8 & 0xFF); 121 | bytes[3] = (byte) (value >> 0 & 0xFF); 122 | return bytes; 123 | } 124 | 125 | public static int bytesToInt32(byte[] bytes) { 126 | return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF); 127 | } 128 | 129 | public static byte[] encodeAvp(Avp avp) { 130 | try { 131 | int payloadSize = avp.getRaw().length; 132 | boolean hasVendorId = avp.getVendorId() != 0; 133 | int origLength = payloadSize + 8 + (hasVendorId ? 4 : 0); 134 | int tmp = payloadSize % 4; 135 | int paddingSize = tmp > 0 ? (4 - tmp) : 0; 136 | 137 | byte[] bCode = Utils.int32ToBytes(avp.getCode()); 138 | int flags = (byte) ((hasVendorId ? 0x80 : 0) 139 | | (avp.isMandatory() ? 0x40 : 0) | (avp.isEncrypted() ? 0x20 : 0)); 140 | byte[] bFlags = Utils.int32ToBytes(((flags << 24) & 0xFF000000) + origLength); 141 | byte[] bVendor = hasVendorId ? Utils.int32ToBytes((int) avp.getVendorId()) : new byte[0]; 142 | return concat(origLength + paddingSize, bCode, bFlags, bVendor, avp.getRaw()); 143 | } catch (Exception e) { 144 | logger.debug("Error during encode avp", e); 145 | return new byte[0]; 146 | } 147 | } 148 | 149 | public static byte[] concat(int length, byte[]... arrays) { 150 | if (length == 0) { 151 | for (byte[] array : arrays) { 152 | length += array.length; 153 | } 154 | } 155 | byte[] result = new byte[length]; 156 | int pos = 0; 157 | for (byte[] array : arrays) { 158 | System.arraycopy(array, 0, result, pos, array.length); 159 | pos += array.length; 160 | } 161 | return result; 162 | } 163 | 164 | protected static class DynamicByteArray { 165 | 166 | private byte[] array; 167 | private int size; 168 | 169 | public DynamicByteArray(int cap) { 170 | array = new byte[cap > 0 ? cap : 256]; 171 | size = 0; 172 | } 173 | 174 | public int get(int pos) { 175 | if (pos >= size) { 176 | throw new ArrayIndexOutOfBoundsException(); 177 | } 178 | return array[pos]; 179 | } 180 | 181 | public void add(byte[] bytes) { 182 | if (size + bytes.length > array.length) { 183 | byte[] newarray = new byte[array.length + bytes.length * 2]; 184 | System.arraycopy(array, 0, newarray, 0, size); 185 | array = newarray; 186 | } 187 | System.arraycopy(bytes, 0, array, size, bytes.length); 188 | size += bytes.length; 189 | } 190 | 191 | public byte[] getResult() { 192 | return Arrays.copyOfRange(array, 0, size); 193 | } 194 | } 195 | 196 | public static byte[] encodeAvpSet(AvpSet avps) { 197 | //ByteArrayOutputStream out = new ByteArrayOutputStream(); 198 | DynamicByteArray dba = new DynamicByteArray(0); 199 | try { 200 | //DataOutputStream data = new DataOutputStream(out); 201 | for (Avp a : avps) { 202 | /*if (a instanceof AvpImpl) { 203 | AvpImpl aImpl = (AvpImpl) a; 204 | if (aImpl.rawData.length == 0 && aImpl.groupedData != null) { 205 | aImpl.rawData = encodeAvpSet(a.getGrouped()); 206 | } 207 | //data.write(newEncodeAvp(aImpl)); 208 | dba.add(encodeAvp(aImpl)); 209 | }*/ 210 | 211 | // workaround because of AvpImpl is not public 212 | boolean hasVendorId = a.getVendorId() != 0; 213 | int flags = (byte) ((hasVendorId ? 0x80 : 0) 214 | | (a.isMandatory() ? 0x40 : 0) | (a.isEncrypted() ? 0x20 : 0)); 215 | AvpImpl aImpl = new AvpImpl(a.getCode(), flags, a.getVendorId(), a.getRawData()); 216 | if (aImpl.rawData.length == 0 && aImpl.groupedData != null) { 217 | aImpl.rawData = encodeAvpSet(a.getGrouped()); 218 | } 219 | dba.add(Utils.encodeAvp(aImpl)); 220 | } 221 | } 222 | catch (Exception e) { 223 | e.printStackTrace(); 224 | logger.debug("Error during encode avps", e); 225 | } 226 | return dba.getResult(); 227 | } 228 | 229 | public static Avp decodeAvp(byte[] in_b ) throws IOException, AvpDataException { 230 | DataInputStream in = new DataInputStream(new ByteArrayInputStream(in_b)); 231 | int code = in.readInt(); 232 | int tmp = in.readInt(); 233 | int counter = 0; 234 | 235 | int flags = (tmp >> 24) & 0xFF; 236 | int length = tmp & 0xFFFFFF; 237 | if (length < 0 || counter + length > in_b.length) { 238 | throw new AvpDataException("Not enough data in buffer!"); 239 | } 240 | long vendor = 0; 241 | boolean hasVendor = false; 242 | if ((flags & 0x80) != 0) { 243 | vendor = in.readInt(); 244 | hasVendor = true; 245 | } 246 | // Determine body L = length - 4(code) -1(flags) -3(length) [-4(vendor)] 247 | byte[] rawData = new byte[length - (8 + (hasVendor ? 4 : 0))]; 248 | in.read(rawData); 249 | // skip remaining. 250 | // TODO: Do we need to padd everything? Or on send stack should properly fill byte[] ... ? 251 | if (length % 4 != 0) { 252 | for (int i; length % 4 != 0; length += i) { 253 | i = (int) in.skip((4 - length % 4)); 254 | } 255 | } 256 | AvpImpl avp = new AvpImpl(code, (short) flags, (int) vendor, rawData); 257 | return avp; 258 | } 259 | 260 | public static AvpSetImpl decodeAvpSet(byte[] buffer, int shift) throws IOException, AvpDataException { 261 | AvpSetImpl avps = new AvpSetImpl(); 262 | int tmp, counter = shift; 263 | DataInputStream in = new DataInputStream(new ByteArrayInputStream(buffer, shift, buffer.length /* - shift ? */)); 264 | 265 | while (counter < buffer.length) { 266 | int code = in.readInt(); 267 | tmp = in.readInt(); 268 | int flags = (tmp >> 24) & 0xFF; 269 | int length = tmp & 0xFFFFFF; 270 | if (length < 0 || counter + length > buffer.length) { 271 | throw new AvpDataException("Not enough data in buffer!"); 272 | } 273 | long vendor = 0; 274 | boolean hasVendor = false; 275 | if ((flags & 0x80) != 0) { 276 | vendor = in.readInt(); 277 | hasVendor = true; 278 | } 279 | // Determine body L = length - 4(code) -1(flags) -3(length) [-4(vendor)] 280 | byte[] rawData = new byte[length - (8 + (hasVendor ? 4 : 0))]; 281 | in.read(rawData); 282 | // skip remaining. 283 | // TODO: Do we need to padd everything? Or on send stack should properly fill byte[] ... ? 284 | if (length % 4 != 0) { 285 | for (int i; length % 4 != 0; length += i) { 286 | i = (int) in.skip((4 - length % 4)); 287 | } 288 | } 289 | AvpImpl avp = new AvpImpl(code, (short) flags, (int) vendor, rawData); 290 | avps.addAvp(avp); 291 | counter += length; 292 | } 293 | return avps; 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/connectorIDS/ConnectorIDS.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package sigfw.connectorIDS; 25 | 26 | /** 27 | * Connector to IDS. The connector class should be protocol independent. 28 | * 29 | * @author Martin Kacer 30 | */ 31 | public class ConnectorIDS implements ConnectorIDSModuleInterface{ 32 | 33 | protected ConnectorIDSModuleInterface module = null; 34 | 35 | /** 36 | * Initialize Connector IDS. 37 | * 38 | * @param cls connector module implementing some protocol 39 | * @return true if successful 40 | */ 41 | public boolean initialize(Class cls) { 42 | if (cls == ConnectorIDSModuleRest.class) { 43 | module = new ConnectorIDSModuleRest(); 44 | return true; 45 | } 46 | return false; 47 | } 48 | 49 | /** 50 | * Add IDS server 51 | * 52 | * @param url url address of IDS server 53 | * @param username username for IDS server 54 | * @param password password for IDS server 55 | * @return true if successful 56 | */ 57 | public boolean addServer(String url, String username, String password) { 58 | if (module == null) { 59 | return false; 60 | } 61 | return module.addServer(url, username, password); 62 | } 63 | 64 | /** 65 | * Remove IDS server 66 | * 67 | * @param url url address of IDS server 68 | * @return true if successful 69 | */ 70 | public boolean removeServer(String url) { 71 | if (module == null) { 72 | return false; 73 | } 74 | return module.removeServer(url); 75 | } 76 | 77 | /** 78 | * Evaluate SCCP message towards IDS server. 79 | * 80 | * @param sccp_raw SCCP hex raw payload of message 81 | * @return true if message is valid and false if message should be filtered 82 | */ 83 | public boolean evalSCCPMessage(String sccp_raw) { 84 | if (module == null) { 85 | return false; 86 | } 87 | return module.evalSCCPMessage(sccp_raw); 88 | } 89 | 90 | /** 91 | * Evaluate Diameter message towards IDS server. 92 | * 93 | * @param diameter_raw Diameter hex raw payload of message 94 | * @return true if message is valid and false if message should be filtered 95 | */ 96 | public boolean evalDiameterMessage(String diameter_raw) { 97 | if (module == null) { 98 | return false; 99 | } 100 | return module.evalDiameterMessage(diameter_raw); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/connectorIDS/ConnectorIDSModuleInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package sigfw.connectorIDS; 25 | 26 | /** 27 | * Connector to IDS interface. 28 | * 29 | * @author Martin Kacer 30 | */ 31 | public interface ConnectorIDSModuleInterface { 32 | 33 | boolean addServer(String url, String username, String password); 34 | 35 | boolean removeServer(String url); 36 | 37 | boolean evalSCCPMessage(String sccp_raw); 38 | 39 | boolean evalDiameterMessage(String diameter_raw); 40 | } 41 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/connectorIDS/ConnectorIDSModuleRest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package sigfw.connectorIDS; 25 | 26 | import java.net.URI; 27 | import java.net.URISyntaxException; 28 | import java.security.SecureRandom; 29 | import java.security.cert.CertificateException; 30 | import java.security.cert.X509Certificate; 31 | import java.util.ArrayList; 32 | import java.util.HashMap; 33 | import java.util.List; 34 | import java.util.Random; 35 | import java.util.logging.Level; 36 | import java.util.logging.Logger; 37 | import javax.net.ssl.HostnameVerifier; 38 | import javax.net.ssl.HttpsURLConnection; 39 | import javax.net.ssl.SSLContext; 40 | import javax.net.ssl.SSLSession; 41 | import javax.net.ssl.TrustManager; 42 | import javax.net.ssl.X509TrustManager; 43 | import jakarta.ws.rs.client.Client; 44 | import jakarta.ws.rs.client.ClientBuilder; 45 | import jakarta.ws.rs.client.WebTarget; 46 | import jakarta.ws.rs.core.Response; 47 | import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; 48 | 49 | 50 | /** 51 | * Connector to IDS module implementing REST. 52 | * 53 | * @author Martin Kacer 54 | */ 55 | public class ConnectorIDSModuleRest implements ConnectorIDSModuleInterface { 56 | private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ConnectorIDSModuleRest.class); 57 | List serverList = new ArrayList(); 58 | List serverTargetsList = new ArrayList(); 59 | HashMap serverBackoffAttempts = new HashMap(); 60 | private static final int SERVER_BACKOFFATTEMPTS = 1000; 61 | Random randomGenerator = new Random(); 62 | 63 | /** 64 | * Create jersey client. 65 | * Used to do not validate certificates or for other SSL/TLS options. 66 | * 67 | */ 68 | protected static Client createClient() { 69 | TrustManager[] certs = new TrustManager[]{ 70 | new X509TrustManager() { 71 | @Override 72 | public X509Certificate[] getAcceptedIssuers() { 73 | return null; 74 | } 75 | 76 | @Override 77 | public void checkServerTrusted(X509Certificate[] chain, String authType) 78 | throws CertificateException { 79 | } 80 | 81 | @Override 82 | public void checkClientTrusted(X509Certificate[] chain, String authType) 83 | throws CertificateException { 84 | } 85 | } 86 | }; 87 | SSLContext ctx = null; 88 | try { 89 | ctx = SSLContext.getInstance("TLS"); 90 | ctx.init(null, certs, new SecureRandom()); 91 | } catch (java.security.GeneralSecurityException ex) { 92 | } 93 | HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory()); 94 | 95 | Client client = ClientBuilder.newBuilder() 96 | .sslContext(ctx) 97 | .hostnameVerifier( 98 | new HostnameVerifier() { 99 | @Override 100 | public boolean verify(String hostname, SSLSession session) { 101 | return true; 102 | } 103 | }) 104 | .build(); 105 | 106 | return client; 107 | } 108 | 109 | /** 110 | * Add IDS server 111 | * 112 | * @param url url address of IDS server 113 | * @param username username for IDS server 114 | * @param password password for IDS server 115 | * @return true if successful 116 | */ 117 | public boolean addServer(String url, String username, String password) { 118 | Client client = createClient(); 119 | serverList.add(client); 120 | 121 | HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic(username, password); 122 | client.register(feature); 123 | 124 | //WebTarget target = client.target(url).path("ss7fw_api/1.0/eval_sccp_message_in_ids"); 125 | WebTarget target = client.target(url); 126 | serverTargetsList.add(target); 127 | 128 | return true; 129 | } 130 | 131 | /** 132 | * Remove IDS server 133 | * 134 | * @param url url address of IDS server 135 | * @return true if successful 136 | */ 137 | public boolean removeServer(String url) { 138 | for (int i = 0; i < serverTargetsList.size(); i++) { 139 | try { 140 | if (serverTargetsList.get(i).getUri().getHost().equals(new URI(url).getHost()) ) { 141 | serverTargetsList.remove(i); 142 | Client client = serverList.get(i); 143 | if (client != null) { 144 | client.close(); 145 | } 146 | serverList.remove(i); 147 | return true; 148 | } 149 | } catch (URISyntaxException ex) { 150 | Logger.getLogger(ConnectorIDSModuleRest.class.getName()).log(Level.SEVERE, null, ex); 151 | return false; 152 | } 153 | } 154 | return false; 155 | } 156 | 157 | /** 158 | * Evaluate SCCP message towards IDS server. 159 | * 160 | * @param sccp_raw SCCP hex raw payload of message 161 | * @return true if message is valid and false if message should be filtered 162 | */ 163 | public boolean evalSCCPMessage(String sccp_raw) { 164 | int attempts = serverList.size(); 165 | 166 | Response response = null; 167 | String output = "1"; 168 | 169 | int i = randomGenerator.nextInt(serverList.size()); 170 | 171 | do { 172 | if (serverBackoffAttempts.get(i) == null || serverBackoffAttempts.get(i).intValue() <= 0) { 173 | try { 174 | WebTarget webResourceWithQueryParam = serverTargetsList.get(i).matrixParam("sccp_raw", sccp_raw); 175 | response = webResourceWithQueryParam.request("text/plain").get(); 176 | if (response.getStatus() == 200) { 177 | output = response.readEntity(String.class); 178 | logger.debug("evalSCCPMessage " + webResourceWithQueryParam + " Response: " + output); 179 | break; 180 | } else { 181 | logger.warn("Connection failed for IDS API: HTTP error code : " + response.getStatus() + " for " + serverTargetsList.get(i)); 182 | } 183 | } catch (Exception e) { 184 | serverBackoffAttempts.put(i, SERVER_BACKOFFATTEMPTS); 185 | logger.warn("Connection failed for IDS API: " + serverTargetsList.get(i) + " " + e.toString()); 186 | } 187 | } else { 188 | if (serverBackoffAttempts.get(i) != null) { 189 | serverBackoffAttempts.put(i, serverBackoffAttempts.get(i).intValue() - 1); 190 | } 191 | i = randomGenerator.nextInt(serverList.size()); 192 | } 193 | attempts--; 194 | } while (attempts > 0); 195 | 196 | 197 | return output.equals("1"); 198 | } 199 | 200 | /** 201 | * Evaluate Diameter message towards IDS server. 202 | * 203 | * @param diameter_raw Diameter hex raw payload of message 204 | * @return true if message is valid and false if message should be filtered 205 | */ 206 | public boolean evalDiameterMessage(String diameter_raw) { 207 | int attempts = serverList.size(); 208 | 209 | Response response = null; 210 | String output = "1"; 211 | 212 | int i = randomGenerator.nextInt(serverList.size()); 213 | 214 | do { 215 | if (serverBackoffAttempts.get(i) == null || serverBackoffAttempts.get(i).intValue() <= 0) { 216 | try { 217 | WebTarget webResourceWithQueryParam = serverTargetsList.get(i).matrixParam("diameter_raw", diameter_raw); 218 | response = webResourceWithQueryParam.request("text/plain").get(); 219 | if (response.getStatus() == 200) { 220 | output = response.readEntity(String.class); 221 | logger.debug("evalDiameterMessage " + webResourceWithQueryParam + " Response: " + output); 222 | break; 223 | } else { 224 | logger.warn("Connection failed for IDS API: HTTP error code : " + response.getStatus() + " for " + serverTargetsList.get(i)); 225 | } 226 | } catch (Exception e) { 227 | serverBackoffAttempts.put(i, SERVER_BACKOFFATTEMPTS); 228 | logger.warn("Connection failed for IDS API: " + serverTargetsList.get(i) + " " + e.toString()); 229 | } 230 | } else { 231 | if (serverBackoffAttempts.get(i) != null) { 232 | serverBackoffAttempts.put(i, serverBackoffAttempts.get(i).intValue() - 1); 233 | } 234 | i = randomGenerator.nextInt(serverList.size()); 235 | } 236 | attempts--; 237 | } while (attempts > 0); 238 | 239 | 240 | return output.equals("1"); 241 | } 242 | 243 | } 244 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/connectorMThreat/ConnectorMThreat.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package sigfw.connectorMThreat; 25 | 26 | import java.util.concurrent.ConcurrentLinkedDeque; 27 | import java.util.concurrent.ExecutorService; 28 | import java.util.concurrent.Executors; 29 | import java.util.logging.Level; 30 | import java.util.logging.Logger; 31 | 32 | /** 33 | * 34 | * @author Martin Kacer 35 | */ 36 | public class ConnectorMThreat implements ConnectorMThreatModuleInterface, Runnable{ 37 | private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ConnectorMThreat.class); 38 | final static int THREADS_NUMBER = 1; 39 | final static int THREADS_SLEEP_TIME = 3000; // in ms 40 | final static int MAX_ALERTS_IN_QUEUE = 10000; 41 | ExecutorService executor = Executors.newFixedThreadPool(THREADS_NUMBER); 42 | boolean isRunning = false; 43 | 44 | protected ConnectorMThreatModuleInterface module = null; 45 | protected static ConcurrentLinkedDeque mThreat_alerts; 46 | 47 | public boolean initialize(Class cls, ConcurrentLinkedDeque alerts) { 48 | mThreat_alerts = alerts; 49 | if (cls == ConnectorMThreatModuleRest.class) { 50 | module = new ConnectorMThreatModuleRest(); 51 | 52 | for (int i = 0; i < THREADS_NUMBER; i++) { 53 | executor.execute(this); 54 | } 55 | isRunning = true; 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | public boolean addServer(String url, String username, String password) { 62 | if (module == null) { 63 | return false; 64 | } 65 | return module.addServer(url, username, password); 66 | } 67 | 68 | public boolean removeServer(String url) { 69 | if (module == null) { 70 | return false; 71 | } 72 | return module.removeServer(url); 73 | } 74 | 75 | public boolean sendAlert(String alert) { 76 | if (module == null) { 77 | return false; 78 | } 79 | return module.sendAlert(alert); 80 | } 81 | 82 | public void run() { 83 | synchronized(this) { 84 | while (isRunning) { 85 | try { 86 | if (mThreat_alerts.size() > 0) { 87 | // send alerts 88 | if(module.sendAlert(mThreat_alerts.getFirst())) { 89 | mThreat_alerts.poll(); 90 | } else { 91 | this.wait(THREADS_SLEEP_TIME); 92 | } 93 | } else { 94 | // remove too much alerts from queue 95 | while (mThreat_alerts.size() > MAX_ALERTS_IN_QUEUE) { 96 | mThreat_alerts.poll(); 97 | } 98 | 99 | this.wait(THREADS_SLEEP_TIME); 100 | } 101 | } catch (InterruptedException ex) { 102 | Logger.getLogger(ConnectorMThreat.class.getName()).log(Level.SEVERE, null, ex); 103 | } 104 | } 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/connectorMThreat/ConnectorMThreatModuleInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package sigfw.connectorMThreat; 25 | 26 | /** 27 | * 28 | * @author Martin Kacer 29 | */ 30 | public interface ConnectorMThreatModuleInterface { 31 | 32 | boolean addServer(String url, String username, String password); 33 | 34 | boolean removeServer(String url); 35 | 36 | boolean sendAlert(String alert); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/connectorMThreat/ConnectorMThreatModuleRest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package sigfw.connectorMThreat; 25 | 26 | import java.net.URI; 27 | import java.net.URISyntaxException; 28 | import java.security.SecureRandom; 29 | import java.security.cert.CertificateException; 30 | import java.security.cert.X509Certificate; 31 | import java.util.ArrayList; 32 | import java.util.HashMap; 33 | import java.util.List; 34 | import java.util.Random; 35 | import java.util.logging.Level; 36 | import java.util.logging.Logger; 37 | import javax.net.ssl.HostnameVerifier; 38 | import javax.net.ssl.HttpsURLConnection; 39 | import javax.net.ssl.SSLContext; 40 | import javax.net.ssl.SSLSession; 41 | import javax.net.ssl.TrustManager; 42 | import javax.net.ssl.X509TrustManager; 43 | import jakarta.ws.rs.client.Client; 44 | import jakarta.ws.rs.client.ClientBuilder; 45 | import jakarta.ws.rs.client.Entity; 46 | import jakarta.ws.rs.client.WebTarget; 47 | import jakarta.ws.rs.core.MediaType; 48 | import jakarta.ws.rs.core.Response; 49 | import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; 50 | 51 | 52 | /** 53 | * 54 | * @author Martin Kacer 55 | */ 56 | public class ConnectorMThreatModuleRest implements ConnectorMThreatModuleInterface { 57 | private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ConnectorMThreatModuleRest.class); 58 | List serverList = new ArrayList(); 59 | List serverTargetsList = new ArrayList(); 60 | HashMap serverBackoffAttempts = new HashMap(); 61 | private static final int SERVER_BACKOFFATTEMPTS = 10; 62 | Random randomGenerator = new Random(); 63 | 64 | protected static Client createClient() { 65 | TrustManager[] certs = new TrustManager[]{ 66 | new X509TrustManager() { 67 | @Override 68 | public X509Certificate[] getAcceptedIssuers() { 69 | return null; 70 | } 71 | 72 | @Override 73 | public void checkServerTrusted(X509Certificate[] chain, String authType) 74 | throws CertificateException { 75 | } 76 | 77 | @Override 78 | public void checkClientTrusted(X509Certificate[] chain, String authType) 79 | throws CertificateException { 80 | } 81 | } 82 | }; 83 | SSLContext ctx = null; 84 | try { 85 | ctx = SSLContext.getInstance("TLS"); 86 | ctx.init(null, certs, new SecureRandom()); 87 | } catch (java.security.GeneralSecurityException ex) { 88 | } 89 | HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory()); 90 | 91 | Client client = ClientBuilder.newBuilder() 92 | .sslContext(ctx) 93 | .hostnameVerifier( 94 | new HostnameVerifier() { 95 | @Override 96 | public boolean verify(String hostname, SSLSession session) { 97 | return true; 98 | } 99 | }) 100 | .build(); 101 | 102 | return client; 103 | } 104 | 105 | public boolean addServer(String url, String username, String password) { 106 | Client client = createClient(); 107 | serverList.add(client); 108 | 109 | HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic(username, password); 110 | client.register(feature); 111 | 112 | WebTarget target = client.target(url); 113 | serverTargetsList.add(target); 114 | 115 | return true; 116 | } 117 | 118 | public boolean removeServer(String url) { 119 | for (int i = 0; i < serverTargetsList.size(); i++) { 120 | try { 121 | if (serverTargetsList.get(i).getUri().getHost().equals(new URI(url).getHost()) ) { 122 | serverTargetsList.remove(i); 123 | Client client = serverList.get(i); 124 | if (client != null) { 125 | client.close(); 126 | } 127 | serverList.remove(i); 128 | return true; 129 | } 130 | } catch (URISyntaxException ex) { 131 | Logger.getLogger(ConnectorMThreatModuleRest.class.getName()).log(Level.SEVERE, null, ex); 132 | return false; 133 | } 134 | } 135 | return false; 136 | } 137 | 138 | public boolean sendAlert(String alert) { 139 | int attempts = serverList.size(); 140 | 141 | Response response = null; 142 | String output = ""; 143 | 144 | int i = randomGenerator.nextInt(serverList.size()); 145 | 146 | do { 147 | if (serverBackoffAttempts.get(i) == null || serverBackoffAttempts.get(i).intValue() <= 0) { 148 | try { 149 | //WebTarget webResourceWithQueryParam = serverTargetsList.get(i).matrixParam("sccp_raw", sccp_raw); 150 | response = serverTargetsList.get(i).request("text/plain").post(Entity.entity(alert, MediaType.TEXT_PLAIN)); 151 | if (response.getStatus() == 200) { 152 | output = response.readEntity(String.class); 153 | logger.debug("sendAlert " + response.toString() + " Response: " + output); 154 | break; 155 | } else { 156 | logger.warn("Connection failed for mThreat API: HTTP error code : " + response.getStatus() + " for " + serverTargetsList.get(i)); 157 | return false; 158 | } 159 | } catch (Exception e) { 160 | serverBackoffAttempts.put(i, SERVER_BACKOFFATTEMPTS); 161 | logger.warn("Connection failed for mThreat API: " + serverTargetsList.get(i) + " " + e.toString()); 162 | return false; 163 | } 164 | } else { 165 | if (serverBackoffAttempts.get(i) != null) { 166 | serverBackoffAttempts.put(i, serverBackoffAttempts.get(i).intValue() - 1); 167 | return false; 168 | } 169 | i = randomGenerator.nextInt(serverList.size()); 170 | } 171 | attempts--; 172 | } while (attempts > 0); 173 | 174 | 175 | return true; 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/tests/ExtensionLoaderTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | * ExtensionLoader is using the work by Scott Robinson, Sep 2013 24 | * http://stackabuse.com/example-loading-a-java-class-at-runtime/ 25 | * 26 | * Modified jSS7 SctpClient.java example 27 | */ 28 | package sigfw.tests; 29 | 30 | import sigfw.common.ExternalFirewallRules; 31 | import java.io.File; 32 | import java.lang.reflect.Constructor; 33 | import java.lang.reflect.InvocationTargetException; 34 | import java.net.MalformedURLException; 35 | import java.net.URL; 36 | import java.net.URLClassLoader; 37 | import java.security.KeyPair; 38 | import java.security.KeyPairGenerator; 39 | import java.util.Arrays; 40 | import java.util.Base64; 41 | import javax.crypto.Cipher; 42 | import javax.crypto.KeyGenerator; 43 | import com.p1sec.sigfw.SigFW_interface.FirewallRulesInterface; 44 | 45 | public class ExtensionLoaderTest { 46 | 47 | public static void main(String[] args) throws Exception { 48 | 49 | try { 50 | // Constructing a URL form the path to JAR 51 | URL u = new URL("file://" + System.getProperty("user.dir") + "/src/main/resources/SigFW_extension-1.0.jar"); 52 | System.out.println("file://" + System.getProperty("user.dir") + "/src/main/resources/SigFW_extension-1.0.jar"); 53 | 54 | // Creating an instance of URLClassloader using the above URL and parent classloader 55 | ClassLoader loader = URLClassLoader.newInstance(new URL[]{u}, ExternalFirewallRules.class.getClassLoader()); 56 | 57 | // Returns the class object 58 | Class yourMainClass = Class.forName("com.p1sec.sigfw.SigFW_extension.rules.ExtendedExternalFirewallRules", true, loader); 59 | 60 | FirewallRulesInterface object1 = (FirewallRulesInterface) yourMainClass.getDeclaredConstructor().newInstance(); 61 | System.out.println(object1.ss7FirewallRules(null)); 62 | } catch (Exception e) { 63 | System.out.println(e.toString()); 64 | 65 | FirewallRulesInterface object1 = (FirewallRulesInterface)new ExternalFirewallRules(); 66 | System.out.println(object1.ss7FirewallRules(null)); 67 | } 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/sigfw/tests/RestClientTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package sigfw.tests; 25 | 26 | 27 | import java.security.SecureRandom; 28 | import java.security.cert.CertificateException; 29 | import java.security.cert.X509Certificate; 30 | import javax.net.ssl.HostnameVerifier; 31 | import javax.net.ssl.HttpsURLConnection; 32 | import javax.net.ssl.SSLContext; 33 | import javax.net.ssl.SSLSession; 34 | import javax.net.ssl.TrustManager; 35 | import javax.net.ssl.X509TrustManager; 36 | import jakarta.ws.rs.client.Client; 37 | import jakarta.ws.rs.client.ClientBuilder; 38 | import jakarta.ws.rs.client.WebTarget; 39 | import jakarta.ws.rs.core.Response; 40 | import org.glassfish.jersey.client.ClientConfig; 41 | import org.glassfish.jersey.client.ClientProperties; 42 | import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; 43 | 44 | 45 | /** 46 | * Class to perform REST API tests. 47 | * 48 | * @author Martin Kacer 49 | */ 50 | public class RestClientTest { 51 | 52 | public static Client configureClient() { 53 | TrustManager[] certs = new TrustManager[]{ 54 | new X509TrustManager() { 55 | @Override 56 | public X509Certificate[] getAcceptedIssuers() { 57 | return null; 58 | } 59 | 60 | @Override 61 | public void checkServerTrusted(X509Certificate[] chain, String authType) 62 | throws CertificateException { 63 | } 64 | 65 | @Override 66 | public void checkClientTrusted(X509Certificate[] chain, String authType) 67 | throws CertificateException { 68 | } 69 | } 70 | }; 71 | SSLContext ctx = null; 72 | try { 73 | ctx = SSLContext.getInstance("TLS"); 74 | ctx.init(null, certs, new SecureRandom()); 75 | } catch (java.security.GeneralSecurityException ex) { 76 | } 77 | HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory()); 78 | 79 | //ClientConfig config = new ClientConfig(); 80 | /*try { 81 | config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties( 82 | new HostnameVerifier() { 83 | @Override 84 | public boolean verify(String hostname, SSLSession session) { 85 | return true; 86 | } 87 | }, 88 | ctx 89 | )); 90 | } catch (Exception e) { 91 | }*/ 92 | 93 | Client client = ClientBuilder.newBuilder() 94 | .sslContext(ctx) 95 | .hostnameVerifier( 96 | new HostnameVerifier() { 97 | @Override 98 | public boolean verify(String hostname, SSLSession session) { 99 | return true; 100 | } 101 | }) 102 | .build(); 103 | 104 | return client; 105 | } 106 | 107 | public static Client createClient() { 108 | return configureClient(); 109 | } 110 | 111 | public static void main(String[] args) throws Exception { 112 | 113 | try { 114 | //Client client = Client.create(); 115 | // Accept self-signed certificates 116 | Client client = createClient(); 117 | 118 | String username = "user"; 119 | String password = "password"; 120 | //client.addFilter(new HTTPBasicAuthFilter(username, password)); 121 | HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic(username, password); 122 | client.register(feature); 123 | 124 | WebTarget webResource = client.target("https://localhost:8443"); 125 | WebTarget webResourceWithPath = webResource.path("ss7fw_api/1.0/eval_sccp_message_in_ids"); 126 | WebTarget webResourceWithQueryParam = webResourceWithPath.matrixParam("sccp_raw", "12345"); 127 | 128 | System.out.println(webResourceWithQueryParam); 129 | 130 | //ClientResponse response = webResourceWithQueryParam.accept("text/plain").get(ClientResponse.class); 131 | Response response = webResourceWithQueryParam.request("text/plain").get(); 132 | 133 | if (response.getStatus() != 200) { 134 | throw new RuntimeException("Failed : HTTP error code : " + response.getStatus()); 135 | } 136 | 137 | String output = response.readEntity(String.class); 138 | 139 | System.out.println("Output from Server .... \n"); 140 | System.out.println(output); 141 | 142 | } catch (Exception e) { 143 | e.printStackTrace(); 144 | } 145 | 146 | } 147 | 148 | } 149 | 150 | 151 | 152 | /* 153 | import com.emc.rest.smart.Host; 154 | import com.emc.rest.smart.SmartClientFactory; 155 | import com.emc.rest.smart.SmartConfig; 156 | import com.sun.jersey.api.client.Client; 157 | import com.sun.jersey.api.client.ClientResponse; 158 | import com.sun.jersey.api.client.WebResource; 159 | import com.sun.jersey.api.client.config.ClientConfig; 160 | import com.sun.jersey.client.urlconnection.HTTPSProperties; 161 | import java.net.URI; 162 | import java.security.SecureRandom; 163 | import java.security.cert.CertificateException; 164 | import java.security.cert.X509Certificate; 165 | import java.util.ArrayList; 166 | import java.util.List; 167 | import javax.net.ssl.HostnameVerifier; 168 | import javax.net.ssl.HttpsURLConnection; 169 | import javax.net.ssl.SSLContext; 170 | import javax.net.ssl.SSLSession; 171 | import javax.net.ssl.TrustManager; 172 | import javax.net.ssl.X509TrustManager; 173 | import org.eclipse.jetty.util.ssl.SslContextFactory; 174 | import org.glassfish.jersey.server.model.Parameter; 175 | 176 | public class RestClientTest { 177 | 178 | public static void main(String[] args) throws Exception { 179 | 180 | SslContextFactory sslContextFactory = new SslContextFactory(); 181 | sslContextFactory.setKeyStorePath("ss7fw_keystore"); 182 | 183 | //for localhost testing only 184 | javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier( 185 | new javax.net.ssl.HostnameVerifier(){ 186 | 187 | public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { 188 | //if (hostname.equals("localhost")) { 189 | return true; 190 | //} 191 | //return false; 192 | } 193 | } 194 | ); 195 | 196 | 197 | 198 | System.setProperty("javax.net.ssl.trustStore", "ss7fw_keystore"); 199 | 200 | List initialHosts = new ArrayList(); 201 | initialHosts.add(new Host(new URI("https://127.0.0.1:8443").getHost())); 202 | 203 | SmartConfig smartConfig = new SmartConfig(initialHosts); 204 | 205 | 206 | 207 | TrustManager[] certs = new TrustManager[]{ 208 | new X509TrustManager() { 209 | @Override 210 | public X509Certificate[] getAcceptedIssuers() { 211 | return null; 212 | } 213 | 214 | @Override 215 | public void checkServerTrusted(X509Certificate[] chain, String authType) 216 | throws CertificateException { 217 | } 218 | 219 | @Override 220 | public void checkClientTrusted(X509Certificate[] chain, String authType) 221 | throws CertificateException { 222 | } 223 | } 224 | }; 225 | SSLContext ctx = null; 226 | try { 227 | ctx = SSLContext.getInstance("TLS"); 228 | ctx.init(null, certs, new SecureRandom()); 229 | } catch (java.security.GeneralSecurityException ex) { 230 | } 231 | HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory()); 232 | 233 | try { 234 | smartConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties( 235 | new HostnameVerifier() { 236 | @Override 237 | public boolean verify(String hostname, SSLSession session) { 238 | return true; 239 | } 240 | }, 241 | ctx 242 | )); 243 | } catch (Exception e) { 244 | } 245 | 246 | smartConfig.getClasses().add(SizeOverrideWriter.InputStream.class); 247 | 248 | 249 | //for (String propName : smartConfig.getProperties().keySet()) { 250 | // clientConfig.getProperties().put(propName, smartConfig.getProperty(propName)); 251 | //} 252 | 253 | 254 | 255 | final Client client = SmartClientFactory.createSmartClient(smartConfig); 256 | 257 | System.out.println(client.getProperties()); 258 | 259 | 260 | String path = "/rest/service"; 261 | 262 | WebResource.Builder request = client.resource("https://127.0.0.1:8443").path(path).getRequestBuilder(); 263 | 264 | ClientResponse response = request.get(ClientResponse.class); 265 | 266 | if (response.getStatus() > 299) throw new RuntimeException("error response: " + response.getStatus()); 267 | 268 | String responseStr = response.getEntity(String.class); 269 | if (!responseStr.contains("Atmos")) throw new RuntimeException("unrecognized response string: " + responseStr); 270 | } 271 | }*/ 272 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/ss7fw/AbstractSctpBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | * 24 | * Modified jSS7 AbstractSctpBase.java example 25 | */ 26 | package ss7fw; 27 | 28 | import java.io.FileNotFoundException; 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.util.Properties; 32 | 33 | import org.apache.log4j.BasicConfigurator; 34 | import org.apache.log4j.FileAppender; 35 | import org.apache.log4j.Logger; 36 | import org.apache.log4j.PropertyConfigurator; 37 | import org.apache.log4j.SimpleLayout; 38 | import org.mobicents.protocols.ss7.map.api.MAPDialogListener; 39 | import org.mobicents.protocols.ss7.m3ua.impl.parameter.ParameterFactoryImpl; 40 | 41 | /** 42 | * Reused from jSS7 SctpClient and SctpServer example 43 | * @author Martin Kacer 44 | * original author amit bhayani in jSS7 SctpClient.java example 45 | */ 46 | public abstract class AbstractSctpBase/*, MAPServiceSupplementaryListener*/ { 47 | 48 | private static final Logger logger = Logger.getLogger("map.test"); 49 | 50 | protected static final String LOG_FILE_NAME = "log.file.name"; 51 | protected static String logFileName = "maplog.txt"; 52 | 53 | // MTP Details 54 | protected int minOpc = 0; 55 | protected int maxOpc = 100000; 56 | 57 | protected final int CLIENT_SPC = 1; 58 | protected final int SERVER_SPC = 2; 59 | protected final int NETWORK_INDICATOR = 0; 60 | protected final int SERVICE_INIDCATOR = 3; // SCCP 61 | protected final int SSN = 8; 62 | 63 | // M3UA details 64 | // protected final String CLIENT_IP = "172.31.96.40"; 65 | protected final String CLIENT_IP = "127.0.0.1"; 66 | protected final int CLIENT_PORT = 2345; 67 | 68 | // protected final String SERVER_IP = "172.31.96.41"; 69 | protected final String SERVER_IP = "127.0.0.1"; 70 | protected final int SERVER_PORT = 3434; 71 | 72 | protected final int ROUTING_CONTEXT = 100; 73 | 74 | protected final String SERVER_ASSOCIATION_NAME = "serverAssociation"; 75 | protected final String CLIENT_ASSOCIATION_NAME = "clientAssociation"; 76 | 77 | protected final String SERVER_NAME = "testserver"; 78 | 79 | //protected final SccpAddress SCCP_CLIENT_ADDRESS = new SccpAddress(RoutingIndicator.ROUTING_BASED_ON_DPC_AND_SSN, 80 | // CLIENT_SPC, null, SSN); 81 | //protected final SccpAddress SCCP_SERVER_ADDRESS = new SccpAddress(RoutingIndicator.ROUTING_BASED_ON_DPC_AND_SSN, 82 | // SERVET_SPC, null, SSN); 83 | protected final ParameterFactoryImpl factory = new ParameterFactoryImpl(); 84 | 85 | protected AbstractSctpBase() { 86 | init(); 87 | } 88 | 89 | public void init() { 90 | try { 91 | Properties tckProperties = new Properties(); 92 | 93 | InputStream inStreamLog4j = AbstractSctpBase.class.getResourceAsStream("/log4j.properties"); 94 | 95 | System.out.println("Input Stream = " + inStreamLog4j); 96 | 97 | Properties propertiesLog4j = new Properties(); 98 | try { 99 | propertiesLog4j.load(inStreamLog4j); 100 | PropertyConfigurator.configure(propertiesLog4j); 101 | } catch (IOException e) { 102 | e.printStackTrace(); 103 | BasicConfigurator.configure(); 104 | } 105 | 106 | logger.debug("log4j configured"); 107 | 108 | String lf = System.getProperties().getProperty(LOG_FILE_NAME); 109 | if (lf != null) { 110 | logFileName = lf; 111 | } 112 | 113 | // If already created a print writer then just use it. 114 | try { 115 | logger.addAppender(new FileAppender(new SimpleLayout(), logFileName)); 116 | } catch (FileNotFoundException fnfe) { 117 | 118 | } 119 | } catch (Exception ex) { 120 | ex.printStackTrace(); 121 | throw new RuntimeException(ex); 122 | } 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/ss7fw/DatagramOverSS7Packet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2021, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package ss7fw; 25 | 26 | import diameterfw.*; 27 | import java.net.DatagramPacket; 28 | 29 | /** 30 | * 31 | * @author Martin Kacer 32 | */ 33 | public class DatagramOverSS7Packet { 34 | private String peer_gt; 35 | private DatagramPacket p; 36 | 37 | public DatagramOverSS7Packet(String peer_gt, DatagramPacket p) { 38 | this.peer_gt = peer_gt; 39 | this.p = p; 40 | } 41 | 42 | public String getPeer_gt() { 43 | return peer_gt; 44 | } 45 | 46 | public DatagramPacket getP() { 47 | return p; 48 | } 49 | 50 | public void setPeer_gt(String peer_gt) { 51 | this.peer_gt = peer_gt; 52 | } 53 | 54 | public void setP(DatagramPacket p) { 55 | this.p = p; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/ss7fw/SS7FirewallAPI_V1_0.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package ss7fw; 25 | import java.util.SortedMap; 26 | import jakarta.ws.rs.Consumes; 27 | import jakarta.ws.rs.Produces; 28 | import jakarta.ws.rs.GET; 29 | import jakarta.ws.rs.MatrixParam; 30 | import jakarta.ws.rs.POST; 31 | import jakarta.ws.rs.Path; 32 | import jakarta.ws.rs.core.Response; 33 | 34 | /** 35 | * Firewall REST API implementation. 36 | * 37 | * @author Martin Kacer 38 | */ 39 | @Path("ss7fw_api/1.0") 40 | public class SS7FirewallAPI_V1_0 { 41 | 42 | @GET 43 | @Consumes("text/plain") 44 | @Produces("text/plain") 45 | @Path("sccp_calling_gt_blacklist_add") 46 | public String sccp_calling_gt_blacklist_add(@MatrixParam("gt") String gt) { 47 | SS7FirewallConfig.sccp_calling_gt_blacklist.put(gt, ""); 48 | return "Successful"; 49 | } 50 | 51 | @GET 52 | @Consumes("text/plain") 53 | @Produces("text/plain") 54 | @Path("sccp_calling_gt_blacklist_remove") 55 | public String sccp_calling_gt_blacklist_remove(@MatrixParam("gt") String gt) { 56 | SS7FirewallConfig.sccp_calling_gt_blacklist.remove(gt); 57 | return "Successful"; 58 | } 59 | 60 | @GET 61 | @Consumes("text/plain") 62 | @Produces("text/plain") 63 | @Path("sccp_calling_gt_blacklist_list") 64 | public String sccp_calling_gt_blacklist_list() { 65 | String s = ""; 66 | for (SortedMap.Entry entry : SS7FirewallConfig.sccp_calling_gt_blacklist.entrySet()) { 67 | s += entry.getKey() + "\n"; 68 | } 69 | return s; 70 | } 71 | 72 | @GET 73 | @Consumes("text/plain") 74 | @Produces("text/plain") 75 | @Path("tcap_oc_blacklist_add") 76 | public String tcap_oc_blacklist_add(@MatrixParam("oc") int oc) { 77 | SS7FirewallConfig.tcap_oc_blacklist.put((new Integer(oc)).toString(), ""); 78 | return "Successful"; 79 | } 80 | 81 | @GET 82 | @Consumes("text/plain") 83 | @Produces("text/plain") 84 | @Path("tcap_oc_blacklist_remove") 85 | public String tcap_oc_blacklist_remove(@MatrixParam("oc") int oc) { 86 | SS7FirewallConfig.tcap_oc_blacklist.remove((new Integer(oc)).toString()); 87 | return "Successful"; 88 | } 89 | 90 | @GET 91 | @Consumes("text/plain") 92 | @Produces("text/plain") 93 | @Path("tcap_oc_blacklist_list") 94 | public String tcap_oc_blacklist_list() { 95 | String s = ""; 96 | for (SortedMap.Entry entry : SS7FirewallConfig.tcap_oc_blacklist.entrySet()) { 97 | s += entry.getKey() + "\n"; 98 | } 99 | return s; 100 | } 101 | 102 | @GET 103 | @Consumes("text/plain") 104 | @Produces("text/plain") 105 | @Path("map_cat2_oc_blacklist_add") 106 | public String map_cat2_oc_blacklist_add(@MatrixParam("oc") int oc) { 107 | SS7FirewallConfig.map_cat2_oc_blacklist.put((new Integer(oc)).toString(), ""); 108 | return "Successful"; 109 | } 110 | 111 | @GET 112 | @Consumes("text/plain") 113 | @Produces("text/plain") 114 | @Path("map_cat2_oc_blacklist_remove") 115 | public String map_cat2_oc_blacklist_remove(@MatrixParam("oc") int oc) { 116 | SS7FirewallConfig.map_cat2_oc_blacklist.remove((new Integer(oc)).toString()); 117 | return "Successful"; 118 | } 119 | 120 | @GET 121 | @Consumes("text/plain") 122 | @Produces("text/plain") 123 | @Path("map_cat2_oc_blacklist_list") 124 | public String map_cat2_oc_blacklist_list() { 125 | String s = ""; 126 | for (SortedMap.Entry entry : SS7FirewallConfig.map_cat2_oc_blacklist.entrySet()) { 127 | s += entry.getKey() + "\n"; 128 | } 129 | return s; 130 | } 131 | 132 | /* 133 | // M3UA FIFO 134 | @GET 135 | @Consumes("text/plain") 136 | @Produces("text/plain") 137 | @Path("get_m3ua_trace") 138 | public String get_m3ua_trace(@MatrixParam("n") int n) { 139 | String s = ""; 140 | int i = n; 141 | while (i > 0 && SS7Firewall.m3ua_fifo.size() > 0 ) { 142 | s += SS7Firewall.m3ua_fifo.pop() + "\n"; 143 | i--; 144 | } 145 | return s; 146 | }*/ 147 | 148 | @GET 149 | @Consumes("text/plain") 150 | @Produces("text/plain") 151 | @Path("get_status") 152 | public String get_status() { 153 | return SS7Firewall.getStatus(); 154 | } 155 | 156 | // IDS integration API - used only for test purposes on localhost simulating IDS backend 157 | @GET 158 | @Consumes("text/plain") 159 | @Produces("text/plain") 160 | @Path("eval_sccp_message_in_ids") 161 | public String eval_sccp_message_in_ids(@MatrixParam("sccp_raw") String sccp_raw) { 162 | return "1"; 163 | } 164 | 165 | // mThreat integration API - used only for test purposes on localhost simulating mThreat backend 166 | @POST 167 | @Consumes("text/plain") 168 | @Produces("text/plain") 169 | @Path("send_ss7_alert_to_mthreat") 170 | public Response send_ss7_alert_to_mthreat(String alert) { 171 | String output = alert; 172 | return Response.status(200).entity(output).build(); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/ss7fw/SS7FirewallFirstInstance.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package ss7fw; 25 | 26 | import ss7fw.SS7Firewall; 27 | /** 28 | * First firewall instance used for testing encryption and signatures. 29 | * 30 | * @author Martin Kacer 31 | * 32 | */ 33 | public class SS7FirewallFirstInstance { 34 | public static void main(String[] args) throws Exception { 35 | String[] a = new String[1]; 36 | a[0] = "ss7fw_1.json"; 37 | SS7Firewall.main(a); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/java/ss7fw/SS7FirewallSecondInstance.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | package ss7fw; 25 | 26 | import ss7fw.SS7Firewall; 27 | /** 28 | * Second firewall instance used to decrypt encryption and validate signatures. 29 | * 30 | * @author Martin Kacer 31 | * 32 | */ 33 | public class SS7FirewallSecondInstance { 34 | public static void main(String[] args) throws Exception { 35 | String[] a = new String[1]; 36 | a[0] = "ss7fw_2.json"; 37 | SS7Firewall.main(a); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/resources/client-jdiameter-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Set root logger level to DEBUG and its only appender to A1. 2 | log4j.rootLogger=INFO, A1, R 3 | 4 | # A1 is set to be a ConsoleAppender. 5 | log4j.appender.A1=org.apache.log4j.ConsoleAppender 6 | 7 | # File 8 | log4j.appender.R=org.apache.log4j.RollingFileAppender 9 | #log4j.appender.R.File=${log.file.name} 10 | log4j.appender.R.File=sigfw.log 11 | 12 | # Archive log files (one backup file here) 13 | log4j.appender.R.MaxBackupIndex=1 14 | 15 | log4j.appender.R.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.R.layout.ConversionPattern=[%d{ISO8601}]%5p%6.6r[%t]%x - %C.%M(%F:%L) - %m%n 17 | 18 | # A1 uses PatternLayout. 19 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout 20 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 21 | 22 | log4j.logger.org.mobicents.protocols.ss7.map.load=WARN 23 | log4j.logger.org.mobicents.protocols.ss7.map=WARN 24 | 25 | log4j.logger.org.mobicents.tests.diameter=INFO 26 | log4j.logger.org.jdiameter=INFO 27 | log4j.logger.jdiameter=OFF 28 | log4j.logger.org.jdiameter.common.impl.validation=OFF 29 | 30 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/main/resources/server-jdiameter-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/test/java/sigfw/tests/TestNg_Placeholder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * TestNG class example 3 | * 4 | * SigFW 5 | * Open Source SS7/Diameter firewall 6 | * By Martin Kacer, Philippe Langlois 7 | * Copyright 2017, P1 Security S.A.S and individual contributors 8 | * 9 | * See the AUTHORS in the distribution for a 10 | * full listing of individual contributors. 11 | * 12 | * This is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU Affero General Public License as 14 | * published by the Free Software Foundation, either version 3 of the 15 | * License, or (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU Affero General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Affero General Public License 23 | * along with this program. If not, see . 24 | */ 25 | package sigfw.tests; 26 | 27 | import org.testng.Assert; 28 | import org.testng.annotations.Test; 29 | 30 | public class TestNg_Placeholder { 31 | /*@Test 32 | public void testPrintMessage() { 33 | Assert.assertEquals("test", "test"); 34 | }*/ 35 | } 36 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/test/java/sigfw/tests/Test_DiameterFirewall.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JUNIT DiameterFirewall class 3 | * 4 | * SigFW 5 | * Open Source SS7/Diameter firewall 6 | * By Martin Kacer, Philippe Langlois 7 | * Copyright 2017, P1 Security S.A.S and individual contributors 8 | * 9 | * See the AUTHORS in the distribution for a 10 | * full listing of individual contributors. 11 | * 12 | * This is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU Affero General Public License as 14 | * published by the Free Software Foundation, either version 3 of the 15 | * License, or (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU Affero General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Affero General Public License 23 | * along with this program. If not, see . 24 | */ 25 | package sigfw.tests; 26 | 27 | import diameterfw.DiameterClientLiveInput; 28 | import java.util.logging.Level; 29 | import org.junit.Assert; 30 | import org.junit.Test; 31 | import org.mobicents.protocols.api.IpChannelType; 32 | import diameterfw.DiameterFirewall; 33 | import diameterfw.DiameterFirewallConfig; 34 | import java.io.InputStream; 35 | import java.nio.ByteBuffer; 36 | import java.util.Properties; 37 | import java.util.logging.Logger; 38 | import org.apache.log4j.PropertyConfigurator; 39 | import org.jdiameter.api.AvpDataException; 40 | import org.jdiameter.api.Message; 41 | import org.jdiameter.client.api.IMessage; 42 | import org.jdiameter.client.api.parser.ParseException; 43 | import org.junit.BeforeClass; 44 | import org.mobicents.protocols.api.PayloadData; 45 | 46 | public class Test_DiameterFirewall { 47 | 48 | private static DiameterFirewall sigfw = null; 49 | 50 | private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(Test_DiameterFirewall.class); 51 | 52 | private static void configLog4j() { 53 | 54 | InputStream inStreamLog4j = DiameterFirewall.class.getClassLoader().getResourceAsStream("log4j.properties"); 55 | Properties propertiesLog4j = new Properties(); 56 | try { 57 | propertiesLog4j.load(inStreamLog4j); 58 | PropertyConfigurator.configure(propertiesLog4j); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | 63 | logger.debug("log4j configured"); 64 | } 65 | 66 | private static void initializeDiameterFirewall() { 67 | configLog4j(); 68 | 69 | try { 70 | // Use last config 71 | DiameterFirewallConfig.loadConfigFromFile("diameterfw_junit.json"); 72 | // TODO use the following directive instead to do not use .last configs 73 | //SS7FirewallConfig.loadConfigFromFile(configName); 74 | } catch (Exception ex) { 75 | java.util.logging.Logger.getLogger(DiameterFirewallConfig.class.getName()).log(Level.SEVERE, null, ex); 76 | } 77 | 78 | sigfw = new DiameterFirewall(); 79 | sigfw.unitTesting = true; 80 | 81 | try { 82 | sigfw.initStack(IpChannelType.SCTP); 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | } 86 | 87 | } 88 | 89 | @BeforeClass 90 | public static void testDiameterFirewallInit() { 91 | initializeDiameterFirewall(); 92 | } 93 | 94 | @Test 95 | public void testULR() { 96 | 97 | logger.info("[[[[[[[[[[ ULR ]]]]]]]]]]"); 98 | 99 | // ULR 100 | sigfw.resetUnitTestingFlags(); 101 | 102 | ByteBuffer buf = ByteBuffer.wrap(DiameterClientLiveInput.hexStringToByteArray("010000f88000013c010000230bbb735b3b4000020000010740000037426164437573746f6d53657373696f6e49643b596573576543616e5061737349643b3135303737333033363031323400000001024000000c010000230000011b4000001c65786368616e67652e6578616d706c652e6f726700000108400000113132372e302e302e31000000000001284000002265786368616e6765436c69656e742e6578616d706c652e6f7267000000000001400000183131313131313131313131313131313100000378c00000100001046a00000000000003e7c00000230001046a492077616e7420746f20676574203320616e737765727300")); 103 | Message msg; 104 | try { 105 | msg = sigfw.parser.createMessage(buf); 106 | ByteBuffer byteBuffer; 107 | byteBuffer = sigfw.parser.encodeMessage((IMessage)msg); 108 | PayloadData payloadData = new PayloadData(byteBuffer.array().length, byteBuffer.array(), true, false, 0, 0); 109 | sigfw.onPayload(null, payloadData); 110 | } catch (AvpDataException ex) { 111 | Logger.getLogger(Test_DiameterFirewall.class.getName()).log(Level.SEVERE, null, ex); 112 | } catch (ParseException ex) { 113 | Logger.getLogger(Test_DiameterFirewall.class.getName()).log(Level.SEVERE, null, ex); 114 | } catch (Exception ex) { 115 | Logger.getLogger(Test_DiameterFirewall.class.getName()).log(Level.SEVERE, null, ex); 116 | } 117 | 118 | try { 119 | Thread.currentThread().sleep(100); 120 | } catch (InterruptedException ex) { 121 | Logger.getLogger(Test_SS7Firewall.class.getName()).log(Level.SEVERE, null, ex); 122 | } 123 | Assert.assertTrue("This ULR message (CommandCode 316, Request) should be allowed by LUA rules diameter_orig_realm", !sigfw.unitTestingFlags_sendDiameterMessage); 124 | 125 | 126 | } 127 | 128 | 129 | } 130 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/test/java/sigfw/tests/Test_SS7Firewall.java: -------------------------------------------------------------------------------- 1 | /** 2 | * JUNIT SS7Firewall class 3 | * 4 | * SigFW 5 | * Open Source SS7/Diameter firewall 6 | * By Martin Kacer, Philippe Langlois 7 | * Copyright 2017, P1 Security S.A.S and individual contributors 8 | * 9 | * See the AUTHORS in the distribution for a 10 | * full listing of individual contributors. 11 | * 12 | * This is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU Affero General Public License as 14 | * published by the Free Software Foundation, either version 3 of the 15 | * License, or (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU Affero General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Affero General Public License 23 | * along with this program. If not, see . 24 | */ 25 | package sigfw.tests; 26 | 27 | import java.util.logging.Level; 28 | import java.util.logging.Logger; 29 | import org.junit.Assert; 30 | import org.junit.BeforeClass; 31 | import org.junit.Test; 32 | import org.mobicents.protocols.api.IpChannelType; 33 | import org.mobicents.protocols.ss7.indicator.NatureOfAddress; 34 | import org.mobicents.protocols.ss7.indicator.RoutingIndicator; 35 | import org.mobicents.protocols.ss7.sccp.message.SccpDataMessage; 36 | import org.mobicents.protocols.ss7.sccp.parameter.GlobalTitle; 37 | import org.mobicents.protocols.ss7.sccp.parameter.SccpAddress; 38 | import static ss7fw.SS7Client.hexStringToByteArray; 39 | import ss7fw.SS7Firewall; 40 | import ss7fw.SS7FirewallConfig; 41 | 42 | public class Test_SS7Firewall { 43 | 44 | private static SS7Firewall sigfw = null; 45 | private static SccpAddress callingParty; 46 | private static SccpAddress calledParty; 47 | 48 | private static void initializeSS7Firewall() { 49 | try { 50 | // Use last config 51 | SS7FirewallConfig.loadConfigFromFile("ss7fw_junit.json"); 52 | // TODO use the following directive instead to do not use .last configs 53 | //SS7FirewallConfig.loadConfigFromFile(configName); 54 | } catch (Exception ex) { 55 | java.util.logging.Logger.getLogger(SS7FirewallConfig.class.getName()).log(Level.SEVERE, null, ex); 56 | } 57 | 58 | sigfw = new SS7Firewall(); 59 | sigfw.unitTesting = true; 60 | 61 | try { 62 | sigfw.initializeStack(IpChannelType.SCTP); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | 67 | // set the calling and called GT for unittests 68 | GlobalTitle callingGT = sigfw.sccpStack.getSccpProvider().getParameterFactory().createGlobalTitle("111111111111", 0, org.mobicents.protocols.ss7.indicator.NumberingPlan.ISDN_MOBILE, null, NatureOfAddress.INTERNATIONAL); 69 | GlobalTitle calledGT = sigfw.sccpStack.getSccpProvider().getParameterFactory().createGlobalTitle("000000000000", 0, org.mobicents.protocols.ss7.indicator.NumberingPlan.ISDN_MOBILE, null, NatureOfAddress.INTERNATIONAL); 70 | callingParty = sigfw.sccpStack.getSccpProvider().getParameterFactory().createSccpAddress(RoutingIndicator.ROUTING_BASED_ON_GLOBAL_TITLE, callingGT, 1, 8); 71 | calledParty = sigfw.sccpStack.getSccpProvider().getParameterFactory().createSccpAddress(RoutingIndicator.ROUTING_BASED_ON_GLOBAL_TITLE, calledGT, 2, 8); 72 | } 73 | 74 | @BeforeClass 75 | public static void testSS7FirewallInit() { 76 | initializeSS7Firewall(); 77 | } 78 | 79 | @Test 80 | public void testATI() { 81 | // anyTimeInterrogation 82 | sigfw.resetUnitTestingFlags(); 83 | SccpDataMessage sccpDataMessage = sigfw.sccpStack.getSccpProvider().getMessageFactory().createDataMessageClass0(calledParty, callingParty, hexStringToByteArray("627e4804000000026b432841060700118605010101a036603480020780a109060704000001001d03be232821060704000001010101a016a01480099611111111111111f18107961111111111f16c31a12f0201000201473027a009800711111111111111a10f80008100830084010086008500870083099611111111111111f1"), 0, true, null, null); 84 | sigfw.onMessage(sccpDataMessage); 85 | 86 | try { 87 | Thread.currentThread().sleep(100); 88 | } catch (InterruptedException ex) { 89 | Logger.getLogger(Test_SS7Firewall.class.getName()).log(Level.SEVERE, null, ex); 90 | } 91 | Assert.assertTrue("anyTimeInterrogation message (opCode 71, TCAP Begin) should be blocked by Cat1", !sigfw.unitTestingFlags_sendSccpMessage); 92 | } 93 | 94 | @Test 95 | public void testPSL() { 96 | // provideSubscriberLocation 97 | sigfw.resetUnitTestingFlags(); 98 | SccpDataMessage sccpDataMessage = sigfw.sccpStack.getSccpProvider().getMessageFactory().createDataMessageClass0(calledParty, callingParty, hexStringToByteArray("62454804000000536b1a2818060700118605010101a00d600ba1090607040000010026036c21a11f020101020153301730038001010407911111111111118307111111111111f1"), 0, true, null, null); 99 | sigfw.onMessage(sccpDataMessage); 100 | 101 | try { 102 | Thread.currentThread().sleep(100); 103 | } catch (InterruptedException ex) { 104 | Logger.getLogger(Test_SS7Firewall.class.getName()).log(Level.SEVERE, null, ex); 105 | } 106 | Assert.assertTrue("provideSubscriberLocation message (opCode 83, TCAP Begin) should be blocked by Cat1", !sigfw.unitTestingFlags_sendSccpMessage); 107 | } 108 | 109 | @Test 110 | public void testSAI() { 111 | // sendAuthenticationInfo 112 | sigfw.resetUnitTestingFlags(); 113 | SccpDataMessage sccpDataMessage = sigfw.sccpStack.getSccpProvider().getMessageFactory().createDataMessageClass0(calledParty, callingParty, hexStringToByteArray("6516480433119839490402035ea26c08a106020102020138"), 0, true, null, null); 114 | sigfw.onMessage(sccpDataMessage); 115 | 116 | try { 117 | Thread.currentThread().sleep(100); 118 | } catch (InterruptedException ex) { 119 | Logger.getLogger(Test_SS7Firewall.class.getName()).log(Level.SEVERE, null, ex); 120 | } 121 | Assert.assertTrue("sendAuthenticationInfo message (opCode 56, TCAP Continue) should be allowed", sigfw.unitTestingFlags_sendSccpMessage); 122 | } 123 | 124 | @Test 125 | public void testUSSD() { 126 | // processUnstructuredSSRequest 127 | sigfw.resetUnitTestingFlags(); 128 | SccpDataMessage sccpDataMessage = sigfw.sccpStack.getSccpProvider().getMessageFactory().createDataMessageClass0(calledParty, callingParty, hexStringToByteArray("62754804000000016b432841060700118605010101a036603480020780a109060704000001001302be232821060704000001010101a016a01480099611111111111111f18107961111111111f16c28a12602010002013b301e04010f0410aa582ca65ac562b1582c168bc562b1118007911111111111f1"), 0, true, null, null); 129 | sigfw.onMessage(sccpDataMessage); 130 | 131 | try { 132 | Thread.currentThread().sleep(100); 133 | } catch (InterruptedException ex) { 134 | Logger.getLogger(Test_SS7Firewall.class.getName()).log(Level.SEVERE, null, ex); 135 | } 136 | Assert.assertTrue("processUnstructuredSSRequest message (opCode 59, TCAP Begin) should be allowed", sigfw.unitTestingFlags_sendSccpMessage); 137 | } 138 | 139 | @Test 140 | public void testCL() { 141 | // cancelLocation 142 | sigfw.resetUnitTestingFlags(); 143 | SccpDataMessage sccpDataMessage = sigfw.sccpStack.getSccpProvider().getMessageFactory().createDataMessageClass0(calledParty, callingParty, hexStringToByteArray("623b4804000000036b1a2818060700118605010101a00d600ba1090607040000010002036c17a115020101020103a30d040811111111111111f10a0100"), 0, true, null, null); 144 | sigfw.onMessage(sccpDataMessage); 145 | 146 | try { 147 | Thread.currentThread().sleep(100); 148 | } catch (InterruptedException ex) { 149 | Logger.getLogger(Test_SS7Firewall.class.getName()).log(Level.SEVERE, null, ex); 150 | } 151 | Assert.assertTrue("cancelLocation message (opCode 3, TCAP Begin) should be blocked by Cat2", !sigfw.unitTestingFlags_sendSccpMessage); 152 | } 153 | 154 | @Test 155 | public void testPSI() { 156 | // Provide Subscriber Info 157 | sigfw.resetUnitTestingFlags(); 158 | SccpDataMessage sccpDataMessage = sigfw.sccpStack.getSccpProvider().getMessageFactory().createDataMessageClass0(calledParty, callingParty, hexStringToByteArray("623e4804000000466b1a2818060700118605010101a00d600ba109060704000001001c036c1aa1180201010201463010800811111111111111f1a20480008300"), 0, true, null, null); 159 | sigfw.onMessage(sccpDataMessage); 160 | 161 | try { 162 | Thread.currentThread().sleep(100); 163 | } catch (InterruptedException ex) { 164 | Logger.getLogger(Test_SS7Firewall.class.getName()).log(Level.SEVERE, null, ex); 165 | } 166 | Assert.assertTrue("provideSubscriberInfo message (opCode 70, TCAP Begin) should be blocked by Cat2", !sigfw.unitTestingFlags_sendSccpMessage); 167 | } 168 | 169 | @Test 170 | public void testPRN() { 171 | // provideRoamingNumber 172 | sigfw.resetUnitTestingFlags(); 173 | SccpDataMessage sccpDataMessage = sigfw.sccpStack.getSccpProvider().getMessageFactory().createDataMessageClass0(calledParty, callingParty, hexStringToByteArray("625d4804000000046b1a2818060700118605010101a00d600ba1090607040000010003026c39a137020101020104302f800811111111111111f18107111111111111f18207111111111111f1a5080a010104030401a0880791111111111111"), 0, true, null, null); 174 | sigfw.onMessage(sccpDataMessage); 175 | 176 | try { 177 | Thread.currentThread().sleep(100); 178 | } catch (InterruptedException ex) { 179 | Logger.getLogger(Test_SS7Firewall.class.getName()).log(Level.SEVERE, null, ex); 180 | } 181 | Assert.assertTrue("provideRoamingNumber message (opCode 4, TCAP Begin) should be blocked by Cat2", !sigfw.unitTestingFlags_sendSccpMessage); 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Set root logger level to DEBUG and its only appender to A1. 2 | log4j.rootLogger=DEBUG, A1, R 3 | 4 | # A1 is set to be a ConsoleAppender. 5 | log4j.appender.A1=org.apache.log4j.ConsoleAppender 6 | 7 | # File 8 | log4j.appender.R=org.apache.log4j.RollingFileAppender 9 | #log4j.appender.R.File=${log.file.name} 10 | log4j.appender.R.File=sigfw.log 11 | 12 | # Archive log files (one backup file here) 13 | log4j.appender.R.MaxBackupIndex=1 14 | 15 | log4j.appender.R.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.R.layout.ConversionPattern=[%d{ISO8601}]%5p%6.6r[%t]%x - %C.%M(%F:%L) - %m%n 17 | 18 | # A1 uses PatternLayout. 19 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout 20 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 21 | 22 | log4j.logger.org.mobicents.protocols.ss7.map.load=WARN 23 | log4j.logger.org.mobicents.protocols.ss7.map=WARN 24 | 25 | log4j.logger.org.mobicents.tests.diameter=INFO 26 | log4j.logger.org.jdiameter=INFO 27 | log4j.logger.jdiameter=OFF 28 | log4j.logger.org.jdiameter.common.impl.validation=OFF 29 | 30 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/ss7fw.json: -------------------------------------------------------------------------------- 1 | { 2 | "operator_configuration": { 3 | "Home_GT_prefixes_comment": "# Identification of HPLMN network, used to identify incoming and outgoing traffic of HPLMN", 4 | "Home_GT_prefixes": [ 5 | "0" 6 | ], 7 | "FW_GT_comment": "# FW GT used as calling GT to initiate messages (e.g. in DTLS handshake)", 8 | "FW_GT": [ 9 | "000000000010" 10 | ], 11 | "Home_IMSI_prefixes_comment": "# Identification Home IMSI range for HPLMN network, used to identify home subscribers", 12 | "Home_IMSI_prefixes": [ 13 | "111111" 14 | ] 15 | }, 16 | "sigfw_configuration": { 17 | "ss7fw_configuration_comment": "# Signalling Firewall configuration. Because of dynamic updates, the sigfw.json.last is periodically created on filesystem.", 18 | 19 | "sctp_comment": "# SCTP configuration part of Signalling Firewall", 20 | "sctp": { 21 | "sctp_management_name": "sctp_mgmt", 22 | "sctp_max_in_streams": "32", 23 | "sctp_max_out_streams": "32", 24 | "sctp_server": [ 25 | { 26 | "server_name": "sctp_server", 27 | "host_address": "127.0.0.1", 28 | "port": "3433" 29 | } 30 | ], 31 | "sctp_server_association": [ 32 | { 33 | "peer_address": "127.0.0.1", 34 | "peer_port": "2345", 35 | "server_name": "sctp_server", 36 | "assoc_name": "sctp_from_client_to_firewall" 37 | } 38 | ], 39 | "sctp_association": [ 40 | { 41 | "host_address": "127.0.0.1", 42 | "host_port": "2344", 43 | "peer_address": "127.0.0.1", 44 | "peer_port": "3434", 45 | "assoc_name": "sctp_from_firewall_to_server" 46 | } 47 | ] 48 | }, 49 | 50 | "m3ua": { 51 | "m3ua_comment": "# M3UA configuration part of Signalling Firewall", 52 | 53 | "m3ua_server": { 54 | "m3ua_management_name": "m3ua_server_mgmt", 55 | "as_name": "RAS1", 56 | "asp_name": "RASP1", 57 | "sctp_assoc_name": "sctp_from_client_to_firewall", 58 | "remote_pc": ["1"] 59 | }, 60 | "m3ua_client": { 61 | "m3ua_management_name": "m3ua_client_mgmt", 62 | "as_name": "AS1", 63 | "asp_name": "ASP1", 64 | "sctp_assoc_name": "sctp_from_firewall_to_server", 65 | "remote_pc": ["2"] 66 | } 67 | }, 68 | 69 | "firewall_rules": { 70 | "firewall_rules_comment": "# Firewall filtering rules configuration", 71 | 72 | "firewall_policy_comment": "# Allowed value is one from: DROP_SILENTLY, DROP_WITH_SCCP_ERROR, DNAT_TO_HONEYPOT, ALLOW", 73 | "firewall_policy": "DROP_WITH_SCCP_ERROR", 74 | 75 | "sccp": { 76 | "sccp_comment": "# SCCP firewall rules", 77 | "calling_gt_whitelist": [ 78 | "4*" 79 | ], 80 | "calling_gt_blacklist": [ 81 | "10000000000", 82 | "222*" 83 | ] 84 | }, 85 | 86 | "tcap": { 87 | "tcap_comment": "# TCAP Cat1 firewall rules", 88 | "oc_blacklist": [ 89 | "5", 90 | "6", 91 | "9", 92 | "16", 93 | "20", 94 | "21", 95 | "22", 96 | "24", 97 | "25", 98 | "26", 99 | "27", 100 | "28", 101 | "29", 102 | "30", 103 | "31", 104 | "32", 105 | "33", 106 | "34", 107 | "35", 108 | "39", 109 | "40", 110 | "41", 111 | "42", 112 | "43", 113 | "50", 114 | "51", 115 | "52", 116 | "55", 117 | "58", 118 | "62", 119 | "65", 120 | "68", 121 | "69", 122 | "71", 123 | "72", 124 | "76", 125 | "77", 126 | "78", 127 | "79", 128 | "80", 129 | "81", 130 | "82", 131 | "83", 132 | "84", 133 | "85", 134 | "86", 135 | "109", 136 | "110", 137 | "111", 138 | "112", 139 | "113", 140 | "114", 141 | "115", 142 | "116", 143 | "117", 144 | "118", 145 | "119", 146 | "120", 147 | "121", 148 | "122", 149 | "123", 150 | "124", 151 | "125", 152 | "126" 153 | ] 154 | }, 155 | 156 | "map": { 157 | "map_comment": "# MAP Cat2 firewall rules", 158 | "cat2_oc_blacklist": [ 159 | "3", 160 | "4", 161 | "7", 162 | "8", 163 | "70" 164 | ] 165 | }, 166 | 167 | "lua": { 168 | "lua_comment": "# LUA Blacklist firewall rules. Currently supported LUA variables are: sccp_calling_gt, sccp_called_gt, tcap_oc, tcap_ac, tcap_tag, map_imsi, map_msisdn", 169 | "blacklist_rules": [ 170 | "sccp_called_gt == '22222222222'", 171 | "sccp_calling_gt == '11111111111' and tcap_oc == '59'" 172 | ] 173 | }, 174 | 175 | "ids": { 176 | "ids_comment": "# IDS API. After evaluating internal firewall rules, the external IDS system can be used to check message (e.g. Cat3). If not required remove this ids json block from config.", 177 | 178 | "ids_api_type_comment": "# Type of connector. Currently supported only REST", 179 | "ids_api_type": "REST", 180 | "ids_servers": [ 181 | { 182 | "host": "https://localhost:8443/ss7fw_api/1.0/eval_sccp_message_in_ids", 183 | "username": "user", 184 | "password": "password" 185 | } 186 | ] 187 | }, 188 | 189 | "mthreat": { 190 | "mthreat_comment": "# mThreat API. If the message matches internal firewall or IDS rules, then the firewall can report the event in anonymized way to mThreat. If not required remove this mthreat json block from config.", 191 | 192 | "mthreat_api_type_comment": "# Type of connector. Currently supported only REST", 193 | "mthreat_api_type": "REST", 194 | "mthreat_salt_comment": "# Change the salt value for unique anonymization", 195 | "mthreat_salt": "XVm4AoKrkicsgEcx", 196 | "mthreat_servers": [ 197 | { 198 | "host": "https://127.0.0.1:8444/mthreat_api/1.0/send_ss7_alert_to_mthreat", 199 | "username": "user", 200 | "password": "pass" 201 | } 202 | ] 203 | }, 204 | 205 | "honeypot": { 206 | "honeypot_comment": "# Honeypot configuration. Only used if firewall policy is DNAT_TO_HONEYPOT", 207 | 208 | "sccp_gt_comment": "# The firewall after detecting the message will perform DNAT to the following GT.", 209 | "sccp_gt": "33333333333", 210 | 211 | "dnat_session_expiration_timeout_comment": "# After matching the firewall or IDS rules, the firewall will apply DNAT for calling GT for the defined number of seconds", 212 | "dnat_session_expiration_timeout": "30" 213 | } 214 | }, 215 | 216 | "encryption_rules": { 217 | "encryption_rules_comment": "# TCAP encryption. NTP synchronization of FW instance is required to work this properly. If autodiscovery is enabled the public keys are added dynamically. Public and private keys are Base64 encoded.", 218 | 219 | "called_gt_encryption_comment": "# Should include json block with {called_gt, public_key}. For example of config see sigfw_1.json or sigfw_2.json.", 220 | "called_gt_encryption": [ 221 | ], 222 | "called_gt_decryption_comment": "# Should include json block with {called_gt, public_key, private}. For example of config see sigfw_1.json or sigfw_2.json.", 223 | "called_gt_decryption": [ 224 | ], 225 | "autodiscovery_comment": "# When enabled the Firewall will try to retrieve public key for unknown destinations by sending MAP Invoke with OpCode 99.", 226 | "autodiscovery": "true", 227 | "dtls_encryption_comment": "# If dtls_encryption is enabled, than the autodiscovery is not used anymore. DTLS handshake in SS7 protocol is used instead. For DTLS handshake the trustore and keystore is used. After successful handshake the DTLS encryption is used. Signature_rules, can be still used together with DTLS, however DTLS provides also integrity protection so they are not mandatory.", 228 | "dtls_encryption": "true" 229 | }, 230 | 231 | "signature_rules": { 232 | "signature_rules_comment": "# TCAP signing. NTP synchronization of FW instance is required to work this properly. Public and private keys are Base64 encoded.", 233 | 234 | "calling_gt_verify_comment": "# Should include json block with {calling_gt, public_key}. For example of config see sigfw_1.json or sigfw_2.json.", 235 | "calling_gt_verify": [ 236 | ], 237 | "calling_gt_signing_comment": "# Should include json block with {calling_gt, public_key, private_key}. For example of config see sigfw_1.json or sigfw_2.json.", 238 | "calling_gt_signing": [ 239 | ] 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/ss7fw_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "operator_configuration": { 3 | "Home_GT_prefixes_comment": "# Identification of HPLMN network, used to identify incoming and outgoing traffic of HPLMN", 4 | "Home_GT_prefixes": [ 5 | "1" 6 | ], 7 | "FW_GT_comment": "# FW GT used as calling GT to initiate messages (e.g. in DTLS handshake)", 8 | "FW_GT": [ 9 | "111111111110" 10 | ], 11 | "Home_IMSI_prefixes_comment": "# Identification Home IMSI range for HPLMN network, used to identify home subscribers", 12 | "Home_IMSI_prefixes": [ 13 | "111111" 14 | ] 15 | }, 16 | "sigfw_configuration": { 17 | "sctp": { 18 | "sctp_management_name": "sctp_mgmt", 19 | "sctp_max_in_streams": "32", 20 | "sctp_max_out_streams": "32", 21 | "sctp_server": [ 22 | { 23 | "server_name": "sctp_server", 24 | "host_address": "127.0.0.1", 25 | "port": "3433" 26 | } 27 | ], 28 | "sctp_server_association": [ 29 | { 30 | "peer_address": "127.0.0.1", 31 | "peer_port": "2345", 32 | "server_name": "sctp_server", 33 | "assoc_name": "sctp_from_client_to_firewall" 34 | } 35 | ], 36 | "sctp_association": [ 37 | { 38 | "host_address": "127.0.0.1", 39 | "host_port": "2349", 40 | "peer_address": "127.0.0.1", 41 | "peer_port": "3439", 42 | "assoc_name": "sctp_from_firewall_to_server" 43 | } 44 | ] 45 | }, 46 | "m3ua": { 47 | "m3ua_server": { 48 | "m3ua_management_name": "m3ua_server_mgmt", 49 | "as_name": "RAS1", 50 | "asp_name": "RASP1", 51 | "sctp_assoc_name": "sctp_from_client_to_firewall", 52 | "remote_pc": ["1"] 53 | }, 54 | "m3ua_client": { 55 | "m3ua_management_name": "m3ua_client_mgmt", 56 | "as_name": "AS1", 57 | "asp_name": "ASP1", 58 | "sctp_assoc_name": "sctp_from_firewall_to_server", 59 | "remote_pc": ["2"] 60 | } 61 | }, 62 | "firewall_rules": { 63 | "firewall_policy": "DROP_SILENTLY", 64 | 65 | "sccp": { 66 | "calling_gt_whitelist": [ 67 | ], 68 | "calling_gt_blacklist": [ 69 | "100000000000", 70 | "222*" 71 | ] 72 | }, 73 | "tcap": { 74 | "oc_blacklist": [ 75 | "5", 76 | "6", 77 | "9", 78 | "16", 79 | "20", 80 | "21", 81 | "22", 82 | "24", 83 | "25", 84 | "26", 85 | "27", 86 | "28", 87 | "29", 88 | "30", 89 | "31", 90 | "32", 91 | "33", 92 | "34", 93 | "35", 94 | "39", 95 | "40", 96 | "41", 97 | "42", 98 | "43", 99 | "50", 100 | "51", 101 | "52", 102 | "55", 103 | "58", 104 | "62", 105 | "65", 106 | "68", 107 | "69", 108 | "71", 109 | "72", 110 | "76", 111 | "77", 112 | "78", 113 | "79", 114 | "80", 115 | "81", 116 | "82", 117 | "83", 118 | "84", 119 | "85", 120 | "86", 121 | "109", 122 | "110", 123 | "111", 124 | "112", 125 | "113", 126 | "114", 127 | "115", 128 | "116", 129 | "117", 130 | "118", 131 | "119", 132 | "120", 133 | "121", 134 | "122", 135 | "123", 136 | "124", 137 | "125", 138 | "126" 139 | ] 140 | }, 141 | "map": { 142 | "cat2_oc_blacklist": [ 143 | "3", 144 | "4", 145 | "7", 146 | "8", 147 | "70" 148 | ] 149 | }, 150 | "lua": { 151 | "blacklist_rules": [ 152 | ] 153 | } 154 | }, 155 | "encryption_rules": { 156 | "called_gt_encryption": [ 157 | 158 | ], 159 | "called_gt_decryption": [ 160 | { 161 | "called_gt": "1*", 162 | "public_key_type": "RSA", 163 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 164 | "private_key_type": "RSA", 165 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 166 | } 167 | ], 168 | "autodiscovery_comment": "# When enabled the Firewall will try to retrieve public key for unknown destinations by sending MAP Invoke with OpCode 99.", 169 | "autodiscovery": "true", 170 | "dtls_encryption_comment": "# If dtls_encryption is enabled, than the autodiscovery is not used anymore. DTLS handshake in SS7 protocol is used instead. For DTLS handshake the trustore and keystore is used. After successful handshake the DTLS encryption is used. Signature_rules, can be still used together with DTLS, however DTLS provides also integrity protection so they are not mandatory.", 171 | "dtls_encryption": "true" 172 | }, 173 | "signature_rules": { 174 | "calling_gt_verify": [ 175 | 176 | ], 177 | "calling_gt_signing": [ 178 | { 179 | "calling_gt": "1*", 180 | "public_key_type": "RSA", 181 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 182 | "private_key_type": "RSA", 183 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 184 | } 185 | ] 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/ss7fw_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "operator_configuration": { 3 | "Home_GT_prefixes_comment": "# Identification of HPLMN network, used to identify incoming and outgoing traffic of HPLMN", 4 | "Home_GT_prefixes": [ 5 | "0" 6 | ], 7 | "FW_GT_comment": "# FW GT used as calling GT to initiate messages (e.g. in DTLS handshake)", 8 | "FW_GT": [ 9 | "000000000010" 10 | ], 11 | "Home_IMSI_prefixes_comment": "# Identification Home IMSI range for HPLMN network, used to identify home subscribers", 12 | "Home_IMSI_prefixes": [ 13 | "111111" 14 | ] 15 | }, 16 | "sigfw_configuration": { 17 | "sctp": { 18 | "sctp_management_name": "sctp_mgmt", 19 | "sctp_max_in_streams": "32", 20 | "sctp_max_out_streams": "32", 21 | "sctp_server": [ 22 | { 23 | "server_name": "sctp_server", 24 | "host_address": "127.0.0.1", 25 | "port": "3439" 26 | } 27 | ], 28 | "sctp_server_association": [ 29 | { 30 | "peer_address": "127.0.0.1", 31 | "peer_port": "2349", 32 | "server_name": "sctp_server", 33 | "assoc_name": "sctp_from_client_to_firewall" 34 | } 35 | ], 36 | "sctp_association": [ 37 | { 38 | "host_address": "127.0.0.1", 39 | "host_port": "2344", 40 | "peer_address": "127.0.0.1", 41 | "peer_port": "3434", 42 | "assoc_name": "sctp_from_firewall_to_server" 43 | } 44 | ] 45 | }, 46 | "m3ua": { 47 | "m3ua_server": { 48 | "m3ua_management_name": "m3ua_server_mgmt", 49 | "as_name": "RAS1", 50 | "asp_name": "RASP1", 51 | "sctp_assoc_name": "sctp_from_client_to_firewall", 52 | "remote_pc": ["1"] 53 | }, 54 | "m3ua_client": { 55 | "m3ua_management_name": "m3ua_client_mgmt", 56 | "as_name": "AS1", 57 | "asp_name": "ASP1", 58 | "sctp_assoc_name": "sctp_from_firewall_to_server", 59 | "remote_pc": ["2"] 60 | } 61 | }, 62 | "firewall_rules": { 63 | "firewall_policy": "DROP_SILENTLY", 64 | 65 | "sccp": { 66 | "calling_gt_whitelist": [ 67 | ], 68 | "calling_gt_blacklist": [ 69 | "100000000000", 70 | "222*" 71 | ] 72 | }, 73 | "tcap": { 74 | "oc_blacklist": [ 75 | "5", 76 | "6", 77 | "9", 78 | "16", 79 | "20", 80 | "21", 81 | "22", 82 | "24", 83 | "25", 84 | "26", 85 | "27", 86 | "28", 87 | "29", 88 | "30", 89 | "31", 90 | "32", 91 | "33", 92 | "34", 93 | "35", 94 | "39", 95 | "40", 96 | "41", 97 | "42", 98 | "43", 99 | "50", 100 | "51", 101 | "52", 102 | "55", 103 | "58", 104 | "62", 105 | "65", 106 | "68", 107 | "69", 108 | "71", 109 | "72", 110 | "76", 111 | "77", 112 | "78", 113 | "79", 114 | "80", 115 | "81", 116 | "82", 117 | "83", 118 | "84", 119 | "85", 120 | "86", 121 | "109", 122 | "110", 123 | "111", 124 | "112", 125 | "113", 126 | "114", 127 | "115", 128 | "116", 129 | "117", 130 | "118", 131 | "119", 132 | "120", 133 | "121", 134 | "122", 135 | "123", 136 | "124", 137 | "125", 138 | "126" 139 | ] 140 | }, 141 | "map": { 142 | "cat2_oc_blacklist": [ 143 | "3", 144 | "4", 145 | "7", 146 | "8", 147 | "70" 148 | ] 149 | }, 150 | "lua": { 151 | "blacklist_rules": [ 152 | ] 153 | } 154 | }, 155 | "encryption_rules": { 156 | "called_gt_encryption": [ 157 | 158 | ], 159 | "called_gt_decryption": [ 160 | { 161 | "called_gt": "0*", 162 | "public_key_type": "RSA", 163 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 164 | "private_key_type": "RSA", 165 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 166 | } 167 | ], 168 | "autodiscovery_comment": "# When enabled the Firewall will try to retrieve public key for unknown destinations by sending MAP Invoke with OpCode 99.", 169 | "autodiscovery": "true", 170 | "dtls_encryption_comment": "# If dtls_encryption is enabled, than the autodiscovery is not used anymore. DTLS handshake in SS7 protocol is used instead. For DTLS handshake the trustore and keystore is used. After successful handshake the DTLS encryption is used. Signature_rules, can be still used together with DTLS, however DTLS provides also integrity protection so they are not mandatory.", 171 | "dtls_encryption": "true" 172 | }, 173 | "signature_rules": { 174 | "calling_gt_verify": [ 175 | 176 | ], 177 | "calling_gt_signing": [ 178 | { 179 | "calling_gt": "0*", 180 | "public_key_type": "RSA", 181 | "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm/PAsXOj7cjirJsQsiIeHauFNLwBIuM1brkUm3aVXeraDIeJ2BWXmWlKMmX/FRZh4Qhe9mUy6YgwTO8PndWdMDRWMw8vvXJFI7HPJpsNfcBykefSqhr5X4h6HyQr73V8O0U5PtgCBuVoyuOFIj87WFwaLuajHiQgps7NOloeH1wIDAQAB", 182 | "private_key_type": "RSA", 183 | "private_key": "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKb88Cxc6PtyOKsmxCyIh4dq4U0vAEi4zVuuRSbdpVd6toMh4nYFZeZaUoyZf8VFmHhCF72ZTLpiDBM7w+d1Z0wNFYzDy+9ckUjsc8mmw19wHKR59KqGvlfiHofJCvvdXw7RTk+2AIG5WjK44UiPztYXBou5qMeJCCmzs06Wh4fXAgMBAAECgYBwNrkOlsDZd8AtAzgA1R5+GYydWWBPfiBB47IElB1v076iEDsmJCp9yWR/pwb9ge8boQ5jEolFFm4W3qqe934ZvBkJaL38zqI3rjZJJ7c9uJwr3ldmREFZa5U8l9tnvlck1b9QW0KDvjt+1Q547+eFlgQaqY5QfY+9D3rpdkZYwQJBAO/2PyNrYlHmVGZOt6foJLv3w4uMkTuleVH9Qu9TOQiv5wyCPTmMDMzW3AwPlFNaZI6YqqYYPUpyI1T0vWVpfS0CQQCyJhtwb5Xxg+b9NGuGmMqJ9GVzYwDPufhMDp7CDDaRKwV3q7eOtsasEGZX64ZkuVRL9xssKLunoqiT5c9z5aOTAkEApf060692hZzEiTiuhjFpJ7VNyPxlglMGxxZf9NkmvMGhG+ADpgkg2ZlPAfDM85O1t4YXlWlzDEpD8oKReNMtyQJAQZN9bjnk++4NzQ7KtdTwWS+5WGwNFGnkWDrZfZx5SZ6IeLCg9Mua/iNbSOnNoq4FtaDUQ8EKsn5Rh3+EiajyOQJAB/dZABQVKyvDAN4s3rXWsrGSuMzGoNCBf1Min1cnWhW2ndE7XC9szNsDGn7sCXmpjwdb7SA6iuh7yrH0YAiOgQ==" 184 | } 185 | ] 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/ss7fw_junit.json: -------------------------------------------------------------------------------- 1 | { 2 | "operator_configuration": { 3 | "Home_GT_prefixes_comment": "# Identification of HPLMN network, used to identify incoming and outgoing traffic of HPLMN", 4 | "Home_GT_prefixes": [ 5 | "0" 6 | ], 7 | "FW_GT_comment": "# FW GT used as calling GT to initiate messages (e.g. in DTLS handshake)", 8 | "FW_GT": [ 9 | "000000000010" 10 | ], 11 | "Home_IMSI_prefixes_comment": "# Identification Home IMSI range for HPLMN network, used to identify home subscribers", 12 | "Home_IMSI_prefixes": [ 13 | "111111" 14 | ] 15 | }, 16 | "sigfw_configuration": { 17 | "ss7fw_configuration_comment": "# Signalling Firewall configuration. Because of dynamic updates, the sigfw.json.last is periodically created on filesystem.", 18 | 19 | "sctp_comment": "# SCTP configuration part of Signalling Firewall", 20 | "sctp": { 21 | "sctp_management_name": "sctp_mgmt", 22 | "sctp_max_in_streams": "32", 23 | "sctp_max_out_streams": "32", 24 | "sctp_server": [ 25 | { 26 | "server_name": "sctp_server", 27 | "host_address": "127.0.0.1", 28 | "port": "3433" 29 | } 30 | ], 31 | "sctp_server_association": [ 32 | { 33 | "peer_address": "127.0.0.1", 34 | "peer_port": "2345", 35 | "server_name": "sctp_server", 36 | "assoc_name": "sctp_from_client_to_firewall" 37 | } 38 | ], 39 | "sctp_association": [ 40 | { 41 | "host_address": "127.0.0.1", 42 | "host_port": "2344", 43 | "peer_address": "127.0.0.1", 44 | "peer_port": "3434", 45 | "assoc_name": "sctp_from_firewall_to_server" 46 | } 47 | ] 48 | }, 49 | 50 | "m3ua": { 51 | "m3ua_comment": "# M3UA configuration part of Signalling Firewall", 52 | 53 | "m3ua_server": { 54 | "m3ua_management_name": "m3ua_server_mgmt", 55 | "as_name": "RAS1", 56 | "asp_name": "RASP1", 57 | "sctp_assoc_name": "sctp_from_client_to_firewall", 58 | "remote_pc": ["1"] 59 | }, 60 | "m3ua_client": { 61 | "m3ua_management_name": "m3ua_client_mgmt", 62 | "as_name": "AS1", 63 | "asp_name": "ASP1", 64 | "sctp_assoc_name": "sctp_from_firewall_to_server", 65 | "remote_pc": ["2"] 66 | } 67 | }, 68 | 69 | "firewall_rules": { 70 | "firewall_rules_comment": "# Firewall filtering rules configuration", 71 | 72 | "firewall_policy_comment": "# Allowed value is one from: DROP_SILENTLY, DROP_WITH_SCCP_ERROR, DNAT_TO_HONEYPOT, ALLOW", 73 | "firewall_policy": "DROP_WITH_SCCP_ERROR", 74 | 75 | "sccp": { 76 | "sccp_comment": "# SCCP firewall rules", 77 | "calling_gt_whitelist": [ 78 | "4*" 79 | ], 80 | "calling_gt_blacklist": [ 81 | "10000000000", 82 | "222*" 83 | ] 84 | }, 85 | 86 | "tcap": { 87 | "tcap_comment": "# TCAP Cat1 firewall rules", 88 | "oc_blacklist": [ 89 | "5", 90 | "6", 91 | "9", 92 | "16", 93 | "20", 94 | "21", 95 | "22", 96 | "24", 97 | "25", 98 | "26", 99 | "27", 100 | "28", 101 | "29", 102 | "30", 103 | "31", 104 | "32", 105 | "33", 106 | "34", 107 | "35", 108 | "39", 109 | "40", 110 | "41", 111 | "42", 112 | "43", 113 | "50", 114 | "51", 115 | "52", 116 | "55", 117 | "58", 118 | "62", 119 | "65", 120 | "68", 121 | "69", 122 | "71", 123 | "72", 124 | "76", 125 | "77", 126 | "78", 127 | "79", 128 | "80", 129 | "81", 130 | "82", 131 | "83", 132 | "84", 133 | "85", 134 | "86", 135 | "109", 136 | "110", 137 | "111", 138 | "112", 139 | "113", 140 | "114", 141 | "115", 142 | "116", 143 | "117", 144 | "118", 145 | "119", 146 | "120", 147 | "121", 148 | "122", 149 | "123", 150 | "124", 151 | "125", 152 | "126" 153 | ] 154 | }, 155 | 156 | "map": { 157 | "map_comment": "# MAP Cat2 firewall rules", 158 | "cat2_oc_blacklist": [ 159 | "3", 160 | "4", 161 | "7", 162 | "8", 163 | "70" 164 | ] 165 | }, 166 | 167 | "lua": { 168 | "lua_comment": "# LUA Blacklist firewall rules. Currently supported LUA variables are: sccp_calling_gt, sccp_called_gt, tcap_oc, tcap_ac, tcap_tag, map_imsi, map_msisdn", 169 | "blacklist_rules": [ 170 | "sccp_called_gt == '22222222222'", 171 | "sccp_calling_gt == '11111111111' and tcap_oc == '59'" 172 | ] 173 | }, 174 | 175 | "ids": { 176 | "ids_comment": "# IDS API. After evaluating internal firewall rules, the external IDS system can be used to check message (e.g. Cat3). If not required remove this ids json block from config.", 177 | 178 | "ids_api_type_comment": "# Type of connector. Currently supported only REST", 179 | "ids_api_type": "REST", 180 | "ids_servers": [ 181 | { 182 | "host": "https://localhost:8443/ss7fw_api/1.0/eval_sccp_message_in_ids", 183 | "username": "user", 184 | "password": "password" 185 | } 186 | ] 187 | }, 188 | 189 | "mthreat": { 190 | "mthreat_comment": "# mThreat API. If the message matches internal firewall or IDS rules, then the firewall can report the event in anonymized way to mThreat. If not required remove this mthreat json block from config.", 191 | 192 | "mthreat_api_type_comment": "# Type of connector. Currently supported only REST", 193 | "mthreat_api_type": "REST", 194 | "mthreat_salt_comment": "# Change the salt value for unique anonymization", 195 | "mthreat_salt": "XVm4AoKrkicsgEcx", 196 | "mthreat_servers": [ 197 | { 198 | "host": "https://127.0.0.1:8444/mthreat_api/1.0/send_ss7_alert_to_mthreat", 199 | "username": "user", 200 | "password": "pass" 201 | } 202 | ] 203 | }, 204 | 205 | "honeypot": { 206 | "honeypot_comment": "# Honeypot configuration. Only used if firewall policy is DNAT_TO_HONEYPOT", 207 | 208 | "sccp_gt_comment": "# The firewall after detecting the message will perform DNAT to the following GT.", 209 | "sccp_gt": "33333333333", 210 | 211 | "dnat_session_expiration_timeout_comment": "# After matching the firewall or IDS rules, the firewall will apply DNAT for calling GT for the defined number of seconds", 212 | "dnat_session_expiration_timeout": "30" 213 | } 214 | }, 215 | 216 | "encryption_rules": { 217 | "encryption_rules_comment": "# TCAP encryption. NTP synchronization of FW instance is required to work this properly. If autodiscovery is enabled the public keys are added dynamically. Public and private keys are Base64 encoded.", 218 | 219 | "called_gt_encryption_comment": "# Should include json block with {called_gt, public_key}. For example of config see sigfw_1.json or sigfw_2.json.", 220 | "called_gt_encryption": [ 221 | ], 222 | "called_gt_decryption_comment": "# Should include json block with {called_gt, public_key, private}. For example of config see sigfw_1.json or sigfw_2.json.", 223 | "called_gt_decryption": [ 224 | ], 225 | "autodiscovery_comment": "# When enabled the Firewall will try to retrieve public key for unknown destinations by sending MAP Invoke with OpCode 99.", 226 | "autodiscovery": "true", 227 | "dtls_encryption_comment": "# If dtls_encryption is enabled, than the autodiscovery is not used anymore. DTLS handshake in SS7 protocol is used instead. For DTLS handshake the trustore and keystore is used. After successful handshake the DTLS encryption is used. Signature_rules, can be still used together with DTLS, however DTLS provides also integrity protection so they are not mandatory.", 228 | "dtls_encryption": "true" 229 | }, 230 | 231 | "signature_rules": { 232 | "signature_rules_comment": "# TCAP signing. NTP synchronization of FW instance is required to work this properly. Public and private keys are Base64 encoded.", 233 | 234 | "calling_gt_verify_comment": "# Should include json block with {calling_gt, public_key}. For example of config see sigfw_1.json or sigfw_2.json.", 235 | "calling_gt_verify": [ 236 | ], 237 | "calling_gt_signing_comment": "# Should include json block with {calling_gt, public_key, private_key}. For example of config see sigfw_1.json or sigfw_2.json.", 238 | "calling_gt_signing": [ 239 | ] 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/ss7fw_keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P1sec/SigFW/5942c557696b1351963727812fc35cc315ebcce4/sigfw/sigfw.sigfw/ss7fw_keystore -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/truststore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P1sec/SigFW/5942c557696b1351963727812fc35cc315ebcce4/sigfw/sigfw.sigfw/truststore -------------------------------------------------------------------------------- /sigfw/sigfw.sigfw/wireshark_diameter_custom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /sigfw/sigfw_interface/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | -------------------------------------------------------------------------------- /sigfw/sigfw_interface/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.p1sec.sigfw 5 | SigFW_interface 6 | 1.0 7 | jar 8 | 9 | UTF-8 10 | 1.7 11 | 1.7 12 | 13 | true 14 | 15 | 16 | 1.7.1-123 17 | 1.7.1-123 18 | 8.0.112 19 | 1.0.9 20 | 1.2 21 | 1.7.21 22 | 23 | 24 | 25 | 26 | jboss-public-repository-group 27 | JBoss Public Repository Group 28 | https://repository.jboss.org/nexus/content/groups/public-jboss/ 29 | default 30 | 31 | true 32 | never 33 | 34 | 35 | true 36 | never 37 | 38 | 39 | 40 | jboss-deprecated-repository 41 | JBoss Deprecated Maven Repository 42 | https://repository.jboss.org/nexus/content/repositories/deprecated/ 43 | default 44 | 45 | true 46 | never 47 | 48 | 49 | false 50 | never 51 | 52 | 53 | 54 | 55 | 56 | jboss-public-repository-group 57 | JBoss Public Repository Group 58 | https://repository.jboss.org/nexus/content/groups/public-jboss/ 59 | 60 | true 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | 75 | 76 | 77 | 78 | org.mobicents.protocols.asn 79 | asn 80 | 2.2.0-143 81 | 82 | 83 | org.mobicents.protocols.ss7.sccp 84 | sccp-api 85 | ${restcomm.jss7.version} 86 | 87 | 88 | org.mobicents.protocols.ss7.sccp 89 | sccp-impl 90 | ${restcomm.jss7.version} 91 | 92 | 93 | org.mobicents.protocols.ss7.tcap 94 | tcap-impl 95 | ${restcomm.jss7.version} 96 | 97 | 98 | org.mobicents.protocols.ss7.tcap 99 | tcap-api 100 | ${restcomm.jss7.version} 101 | 102 | 103 | org.mobicents.protocols.ss7.map 104 | map-api 105 | ${restcomm.jss7.version} 106 | 107 | 108 | org.mobicents.protocols.ss7.map 109 | map-impl 110 | ${restcomm.jss7.version} 111 | 112 | 113 | org.mobicents.protocols.ss7.cap 114 | cap-api 115 | ${restcomm.jss7.version} 116 | 117 | 118 | org.mobicents.protocols.ss7.cap 119 | cap-impl 120 | ${restcomm.jss7.version} 121 | 122 | 123 | org.mobicents.protocols.ss7.isup 124 | isup-api 125 | ${restcomm.jss7.version} 126 | 127 | 128 | org.mobicents.protocols.ss7.isup 129 | isup-impl 130 | ${restcomm.jss7.version} 131 | 132 | 133 | org.mobicents.protocols.ss7.inap 134 | inap-api 135 | ${restcomm.jss7.version} 136 | 137 | 138 | org.mobicents.protocols.ss7.inap 139 | inap-impl 140 | ${restcomm.jss7.version} 141 | 142 | 143 | org.mobicents.protocols.ss7.tools.simulator 144 | simulator-core 145 | ${restcomm.jss7.version} 146 | 147 | 148 | com.sun.jdmk 149 | jmxtools 150 | 1.2.1 151 | 152 | 153 | org.mobicents.protocols.sctp 154 | sctp-api 155 | 2.0.18 156 | 157 | 158 | org.mobicents.protocols.sctp 159 | sctp-impl 160 | 2.0.18 161 | 162 | 163 | org.mobicents.protocols.ss7.m3ua 164 | m3ua-api 165 | ${restcomm.jss7.version} 166 | 167 | 168 | org.mobicents.protocols.ss7.m3ua 169 | m3ua-impl 170 | ${restcomm.jss7.version} 171 | 172 | 173 | org.mobicents.protocols.ss7.mtp 174 | mtp-api 175 | ${restcomm.jss7.version} 176 | 177 | 178 | org.mobicents.protocols.ss7.mtp 179 | mtp 180 | ${restcomm.jss7.version} 181 | 182 | 183 | org.mobicents.protocols.ss7.hardware 184 | restcomm-dialogic 185 | ${restcomm.jss7.version} 186 | 187 | 188 | 189 | org.mobicents.diameter 190 | restcomm-diameter-mux-jar 191 | ${restcomm.diameter.mux.version} 192 | 193 | 194 | org.mobicents.diameter 195 | jdiameter-api 196 | ${restcomm.diameter.jdiameter.version} 197 | 198 | 199 | org.mobicents.diameter 200 | jdiameter-impl 201 | ${restcomm.diameter.jdiameter.version} 202 | 203 | 204 | 205 | org.slf4j 206 | slf4j-log4j12 207 | 208 | 209 | 210 | 211 | 212 | 221 | 222 | SigFW_interface 223 | 224 | 225 | -------------------------------------------------------------------------------- /sigfw/sigfw_interface/src/main/java/com/p1sec/sigfw/SigFW_interface/CryptoInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | * Modified jSS7 SctpClient.java example 24 | */ 25 | package com.p1sec.sigfw.SigFW_interface; 26 | 27 | import java.security.InvalidKeyException; 28 | import java.security.KeyPair; 29 | import java.security.PublicKey; 30 | //import javafx.util.Pair; 31 | import java.util.AbstractMap; 32 | import java.util.Map; 33 | import java.util.SortedMap; 34 | import javax.net.ssl.SSLEngine; 35 | import org.jdiameter.api.Message; 36 | import org.mobicents.protocols.ss7.sccp.LongMessageRuleType; 37 | import org.mobicents.protocols.ss7.sccp.impl.message.MessageFactoryImpl; 38 | import org.mobicents.protocols.ss7.sccp.message.SccpDataMessage; 39 | import org.mobicents.protocols.ss7.tcap.asn.comp.Component; 40 | import org.mobicents.protocols.ss7.tcap.asn.comp.TCBeginMessage; 41 | 42 | /** 43 | * 44 | * @author Martin Kacer 45 | */ 46 | public interface CryptoInterface { 47 | 48 | /** 49 | * Method to sign Diameter message 50 | * 51 | * @param message Diameter message which will be signed 52 | * @param keyPair KeyPair used to sign message 53 | * @param signingRealm Diameter realm signing the message 54 | */ 55 | public void diameterSign(Message message, SortedMap origin_realm_signing, SortedMap origin_realm_signing_signing_realm, Map dtls_engine_permanent_client); 56 | 57 | /** 58 | * Method to verify the Diameter message signature 59 | * 60 | * 61 | * @param message Diameter message which will be verified 62 | * @param SortedMap Public Key hash map, used to verify message signature 63 | * @return result, empty string if successful, otherwise error message 64 | */ 65 | public String diameterVerify(Message message, SortedMap origin_realm_verify_signing_realm, Map dtls_engine_permanent_server); 66 | 67 | 68 | /** 69 | * Method to encrypt Diameter message 70 | * 71 | * @param message Diameter message which will be encrypted 72 | * @param publicKey Public Key used for message encryption 73 | */ 74 | public void diameterEncrypt(Message message, PublicKey publicKey) throws InvalidKeyException; 75 | public void diameterEncrypt_v2(Message message, PublicKey publicKey) throws InvalidKeyException; 76 | public void diameterEncrypt_v3(Message message, PublicKey publicKey) throws InvalidKeyException; 77 | 78 | /** 79 | * Method to decrypt Diameter message 80 | * 81 | * @param message Diameter message which will be decrypted 82 | * @param keyPair Key Pair used for message encryption 83 | * @return result, empty string if successful, otherwise error message 84 | */ 85 | public String diameterDecrypt(Message message, KeyPair keyPair); 86 | 87 | /** 88 | * Method remove from SCCP message duplicated TCAP signatures and verifies the TCAP signature. 89 | * Method currently is designed only for TCAP begin messages. 90 | * 91 | * 92 | * @param message SCCP message 93 | * @param tcb TCAP Begin Message 94 | * @param comps TCAP Components 95 | * @param publicKey Public Key 96 | * @return -1 no public key to verify signature, 0 signature does not match, 1 signature ok 97 | */ 98 | public int tcapVerify(SccpDataMessage message, TCBeginMessage tcb, Component[] comps, PublicKey publicKey); 99 | 100 | /** 101 | * Method to add TCAP signature into SCCP message. 102 | * Method currently is designed only for TCAP begin messages. 103 | * 104 | * 105 | * @param message SCCP message 106 | * @param tcb TCAP Begin Message 107 | * @param comps TCAP Components 108 | * @param lmrt Long Message Rule Type, if UDT or XUDT should be send 109 | * @param keyPair Key Pair 110 | * @return Long Message Rule Type, if UDT or XUDT should be send 111 | */ 112 | LongMessageRuleType tcapSign(SccpDataMessage message, TCBeginMessage tcb, Component[] comps, LongMessageRuleType lmrt, KeyPair keyPair); 113 | 114 | /** 115 | * Method to encrypt TCAP message. 116 | * 117 | * 118 | * @param message SCCP message 119 | * @param sccpMessageFactory SCCP message factory 120 | * @param publicKey Public Key 121 | * @param lmrt Long Message Rule Type, if UDT or XUDT should be send 122 | * @return pair - message and indicator if UDT or XUDT should be send 123 | */ 124 | public AbstractMap.SimpleEntry tcapEncrypt(SccpDataMessage message, MessageFactoryImpl sccpMessageFactory, PublicKey publicKey, LongMessageRuleType lmr); 125 | 126 | /** 127 | * Method to decrypt TCAP message. 128 | * 129 | * 130 | * @param message SCCP message 131 | * @param comps TCAP components 132 | * @param sccpMessageFactory SCCP message factory 133 | * @param keyPair Key Pair 134 | * @return pair - message and result indicator 135 | */ 136 | public AbstractMap.SimpleEntry tcapDecrypt(SccpDataMessage message, Component[] comps, MessageFactoryImpl sccpMessageFactory, KeyPair keyPair); 137 | } 138 | -------------------------------------------------------------------------------- /sigfw/sigfw_interface/src/main/java/com/p1sec/sigfw/SigFW_interface/FirewallRulesInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * SigFW 3 | * Open Source SS7/Diameter firewall 4 | * By Martin Kacer, Philippe Langlois 5 | * Copyright 2017, P1 Security S.A.S and individual contributors 6 | * 7 | * See the AUTHORS in the distribution for a 8 | * full listing of individual contributors. 9 | * 10 | * This is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Affero General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Affero General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Affero General Public License 21 | * along with this program. If not, see . 22 | * 23 | * Modified jSS7 SctpClient.java example 24 | */ 25 | package com.p1sec.sigfw.SigFW_interface; 26 | 27 | import java.io.InputStream; 28 | import java.util.Properties; 29 | import org.apache.log4j.Logger; 30 | import org.apache.log4j.PropertyConfigurator; 31 | import org.mobicents.protocols.api.Association; 32 | import org.mobicents.protocols.api.PayloadData; 33 | import org.mobicents.protocols.ss7.sccp.message.SccpDataMessage; 34 | 35 | /** 36 | * 37 | * @author Martin Kacer 38 | */ 39 | public interface FirewallRulesInterface { 40 | 41 | public boolean ss7FirewallRules(SccpDataMessage message); 42 | public boolean diameterFirewallRules(Association asctn, PayloadData pd); 43 | } 44 | --------------------------------------------------------------------------------