pfcpsim is a PFCP simulator to interact with PFCP agents and can be used to simulate a 4G SGW-C or 5G SMF.
All related features are implemented according to the 3GPP TS 29.244 V16.3.1 (2020-04).
pfcpsim is designed to work within a containerized environment. The docker image
comes with both client (pfcpctl
) and server (pfcpsim
).
PFCPClient
is embedded in a gRPC Server. Interaction between pfcpsim and pfcpctl
is performed through RPCs, as shown in the following schema:
Note: Release images are available on DockerHub, while per-PR images are available on Aether registry
docker container run --rm -d --name pfcpsim pfcpsim:<image_tag> -p 12345 --interface <interface-name>
-p
(optional, default is 54321): to set a custom gRPC listening port--interface
(optional, default is first non-loopback interface): to indicate a specific interface from which retrieve the local IP address
docker exec pfcpsim pfcpctl -s localhost:12345 service configure --n3-addr <N3-interface-address> --remote-peer-addr <PFCP-server-address>
-s
/--server
: (optional, default is 'localhost:54321') the gRPC server address.service
: selects the service subparser.configure
: selects the Configure RPC that allows to set the addresses of the N3 interface and the remote PFCP agent peer.--n3-addr
: address of the N3 Interface between UPF and nodeB.--remote-peer-addr
: address of the PFCP server. It supports the override of the IANA PFCP port (e.g.10.0.0.1:8888
).
To list all the available commands just append --help
, when executing pfcpctl
.
3. associate
command will connect to remote peer set in the previous configuration step and perform an association.
docker exec pfcpsim pfcpctl -s localhost:12345 service associate
docker exec pfcpsim pfcpctl -s localhost:12345 session create --count 5 --baseID 2 --ue-pool <CIDR-IP-pool> --gnb-addr <GNodeB-address> --sdf-filter 'permit out ip from 0.0.0.0/0 to assigned 81-81'
--count
the amount of sessions to create--baseID
the base ID used to incrementally create sessions--ue-pool
the IP pool from which UE addresses will be generated (e.g.17.0.0.0/24
)--gnb-addr
the (e/g)NodeB address--sdf-filter
(optional) the SDF Filter to use when creating PDRs. If not set, PDI will contain a SDF Filter IE with an empty string as SDF Filter.
docker exec pfcpsim pfcpctl --server localhost:12345 session delete --count 5 --baseID 2
docker exec pfcpsim pfcpctl --server localhost:12345 service disassociate
Pfcpsim is able to generate malformed PFCP messages and can be used to explore potential vulnerabilities of PFCP agents (UPF).
Note: PFCP fuzzer is developed by the Ian Chen (free5GC team) PFCP fuzzer was used to test the UPF implementation of the free5GC project, and successfully found some vulnerabilities.
To use the PFCP fuzzer, we need to prepare the fuzzing environment first. The following steps show how to use the PFCP fuzzer.
Pfcpsim supports to test various UPF implementations. You can choose the UPF implementation you want to test, and launch the UPF instance.
You should change the configuration in fuzz/ie_fuzz_test.go
:
sim := export.NewPfcpSimCfg(iface, upfN3, upfN4)
iface
: the interface name you used to establish the connection with UPF.upfN3
: the N3 interface address of the UPF.upfN4
: the N4 interface address of the UPF.
You can run the fuzzing test by the following command:
go test -fuzz=Fuzz -p 1 -parallel 1 -fuzztime 15m ./fuzz/...
To specify args:
go test -fuzz=Fuzz -p 1 -parallel 1 -fuzztime 15m ./fuzz/... -args -iface=lo -upfN3=192.168.0.5 -upfN4=127.0.0.8
-fuzztime
: the time you want to run the fuzzing test.- Do not change the value of either
-parallel
or-p
flag because it will cause the race condition. - The output for the fuzzing test looks like this:
fuzz: elapsed: 0s, gathering baseline coverage: 0/100 completed
fuzz: elapsed: 3s, gathering baseline coverage: 0/100 completed
...
fuzz: elapsed: 13m21s, gathering baseline coverage: 99/100 completed
fuzz: elapsed: 13m21s, gathering baseline coverage: 100/100 completed, now fuzzing with 1 workers
fuzz: elapsed: 13m24s, execs: 100 (0/sec), new interesting: 0 (total: 100)
...
fuzz: elapsed: 15m1s, execs: 111 (0/sec), new interesting: 0 (total: 100)
PASS
ok github.com/omec-project/pfcpsim/fuzz 900.684s
-
If the test result shows "PASS" and the UPF didn't crash, it means that the fuzzy test was successful!
-
If Pfcpsim can't connect to the UPF, the user will see an output like this:
...
failure while testing seed corpus entry: Fuzz/seed#0
fuzz: elapsed: 5s, gathering baseline coverage: 0/106 completed
--- FAIL: Fuzz (5.02s)
--- FAIL: Fuzz (5.00s)
ie_fuzz_test.go:57:
Error Trace: /home/xxxx/pfcpsim/fuzz/ie_fuzz_test.go:57
/usr/local/go/src/reflect/value.go:556
/usr/local/go/src/reflect/value.go:339
/usr/local/go/src/testing/fuzz.go:337
Error: Received unexpected error:
route ip+net: no such network interface
Test: Fuzz
Messages: InitPFCPSim failed
FAIL
exit status 1
FAIL github.com/omec-project/pfcpsim/fuzz 5.023s
If you don't want to use docker you can just compile the binaries of pfcpsim
and pfcpctl
:
git clone https://github.com/omec-project/pfcpsim && cd pfcpsim/
go build -o server cmd/pfcpsim/main.go
go build -o client cmd/pfcpctl/main.go
You can now place server
and client
wherever you want.
To setup pfcpsim
use the same steps shown above (without executing docker
)
as shown below:
./server -p 12345 --interface <interface-name>