Skip to content

Commit

Permalink
Feat/urr (#69)
Browse files Browse the repository at this point in the history
* support: URR related IEs

* ignore session report msg in PeekNextResponse()

* print log msg when received session report related msg

* upgrade to golang 1.18 & go-pfcp v0.0.19

* update urr related handlers

* support to handle sessionReport

* add fuzz package

* support ie fuzzing

* update Fuzzing Test

* ignore HeartbeatRequest

* fix ci linter error

* package rename

* add license/copyright header

* update makefile

* Fix lint issue

* fix gosec G404 & update behavior of test target in Makefile

* update go.mod

* fix ci-lint error in fuzz test

* update README

* fix ci linter error

* fix: support loopback interface

* Update .gitignore

* fix: update typo and add args for fuzz test

* doc: update README

* Apply suggestions from code review

---------

Co-authored-by: gab-arrobo <gabriel.arrobo@intel.com>
Co-authored-by: CTFang@WireLab <ctfang.cs12@nycu.edu.tw>
  • Loading branch information
3 people committed Mar 28, 2024
1 parent 528d74b commit 2f3579b
Show file tree
Hide file tree
Showing 18 changed files with 1,363 additions and 216 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -1,9 +1,12 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2022-present Open Networking Foundation

.fuzz/test_data
.idea/
.coverage/
output
*.pyc
*.swp
*.log
client
server
4 changes: 3 additions & 1 deletion Makefile
Expand Up @@ -26,8 +26,10 @@ golint:
rm -rf $(CURDIR)/.coverage
mkdir -p $(CURDIR)/.coverage

# -run flag ensures that the fuzz test won't be run
# because the fuzz test needs a UPF to run
test: .coverage
go test -race -coverprofile=.coverage/coverage-unit.txt -covermode=atomic -v ./...
go test -race -coverprofile=.coverage/coverage-unit.txt -covermode=atomic -run=^Test -v ./...

reuse-lint:
docker run --rm -v $(CURDIR):/pfcpsim -w /pfcpsim omecproject/reuse-verify:latest reuse lint
Expand Down
80 changes: 79 additions & 1 deletion README.md
Expand Up @@ -3,6 +3,7 @@
# pfcpsim
pfcpsim is a simulator to interact with PFCP agents. Can be used to simulate a 4G SGW-C / 5G SMF.

> All related features are implemented according to the 3GPP TS 29.244 V16.3.1(2020-04).
## Overview

pfcpsim is designed to work within a containerized environment. The docker image comes with both client (`pfcpctl`) and server (`pfcpsim`).
Expand All @@ -13,7 +14,9 @@ pfcpsim is designed to work within a containerized environment. The docker image

## Getting Started

#### 1. Create the container. Images are available on [Dockerhub](https://hub.docker.com/r/opennetworking/pfcpsim/tags):
### Normal Case

#### 1. Create the container. Images are available on [DockerHub](https://hub.docker.com/r/opennetworking/pfcpsim/tags):
```bash
docker container run --rm -d --name pfcpsim pfcpsim:<image_tag> -p 12345 --interface <interface-name>
```
Expand Down Expand Up @@ -57,6 +60,81 @@ docker exec pfcpsim pfcpctl --server localhost:12345 session delete --count 5 --
docker exec pfcpsim pfcpctl --server localhost:12345 service disassociate
```

### Fuzzing Mode

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)](https://github.com/ianchen0119)
> 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.

#### 1. Launch the UPF instance

Pfcpsim supports to test various UPF implementations.
You can choose the UPF implementation you want to test, and launch the UPF instance.

#### 2. Change the configuration in `fuzz/ie_fuzz_test.go`

You should change the configuration in `fuzz/ie_fuzz_test.go`:
```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.

#### 3. Run the fuzzing test

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
```
## Compile binaries
If you don't want to use docker you can just compile the binaries of `pfcpsim` and `pfcpctl`:
Expand Down
94 changes: 94 additions & 0 deletions fuzz/ie_fuzz_test.go
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024-present Ian Chen <ychen.cs10@nycu.edu.tw>

package fuzz

import (
"crypto/rand"
"flag"
"math/big"
"testing"
"time"

"github.com/omec-project/pfcpsim/internal/pfcpsim/export"
"github.com/omec-project/pfcpsim/pkg/pfcpsim/session"
"github.com/stretchr/testify/require"
)

const (
MaxUint = ^uint(0)
MaxInt = int(MaxUint >> 1)
)

func getRand(n int) int {
res, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
if err != nil {
return n
}

return int(res.Int64())
}

var (
iface = flag.String("iface", "eth0", "the interface name you used to establish the connection with UPF.")
upfN3 = flag.String("upfN3", "192.168.0.5", "the N3 interface address of the UPF")
upfN4 = flag.String("upfN4", "127.0.0.8", "the N4 interface address of the UPF")
)

func Fuzz(f *testing.F) {
var testcases []uint
for i := 0; i < 100; i++ {
testcases = append(testcases, uint(getRand(MaxInt)))
}

for _, tc := range testcases {
f.Add(tc)
}

session.SetCheck(false)

f.Fuzz(func(t *testing.T, input uint) {
time.Sleep(5 * time.Second)

sim := export.NewPfcpSimCfg(*iface, *upfN3, *upfN4)

err := sim.InitPFCPSim()
if err != nil {
require.NoError(t, err, "InitPFCPSim failed")
}

err = sim.Associate()
if err != nil {
require.NoError(t, err, "Associate failed")
}

defer func() {
err = sim.TerminatePFCPSim()
require.NoError(t, err)
}()

err = sim.CreateSession(2, getRand(session.PdrMax),
int(input)%session.QerMax,
int(input)%session.FarMax,
int(input)%session.UrrMax,
input)
if err != nil {
require.NoError(t, err, "CreateSession failed")
}

err = sim.ModifySession(2,
getRand(session.FarMax),
getRand(session.UrrMax),
input)
if err != nil {
require.NoError(t, err, "ModifySession failed")
}

time.Sleep(3 * time.Second)

err = sim.DeleteSession(2)
if err != nil {
require.NoError(t, err, "DeleteSession failed")
}
})
}
24 changes: 12 additions & 12 deletions go.mod
Expand Up @@ -3,23 +3,23 @@ module github.com/omec-project/pfcpsim
go 1.21

require (
github.com/c-robinson/iplib v1.0.3
github.com/golang/protobuf v1.5.2
github.com/c-robinson/iplib v1.0.6
github.com/golang/protobuf v1.5.3
github.com/jessevdk/go-flags v1.5.0
github.com/pborman/getopt/v2 v2.1.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
github.com/wmnsk/go-pfcp v0.0.14
google.golang.org/grpc v1.44.0
google.golang.org/protobuf v1.27.1
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.9.0
github.com/wmnsk/go-pfcp v0.0.19
google.golang.org/grpc v1.54.0
google.golang.org/protobuf v1.30.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 // indirect
golang.org/x/text v0.3.0 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

0 comments on commit 2f3579b

Please sign in to comment.