Skip to content
Snippets Groups Projects
Unverified Commit e4c87566 authored by Annika Wickert's avatar Annika Wickert Committed by GitHub
Browse files

Merge pull request #116 from bio-routing/bmp

BMP receiver packet processing
parents e66dad18 366ab502
Branches
Tags
No related merge requests found
Showing
with 1396 additions and 26 deletions
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix github.com/bio-routing/bio-rd
......@@ -7,28 +6,3 @@ gazelle(
external = "vendored",
prefix = "github.com/bio-routing/bio-rd",
)
go_library(
name = "go_default_library",
srcs = [
"main.go",
"main_ipv4.go",
],
importpath = "github.com/bio-routing/bio-rd",
visibility = ["//visibility:private"],
deps = [
"//config:go_default_library",
"//net:go_default_library",
"//protocols/bgp/server:go_default_library",
"//routingtable:go_default_library",
"//routingtable/filter:go_default_library",
"//routingtable/locRIB:go_default_library",
"//vendor/github.com/sirupsen/logrus:go_default_library",
],
)
go_binary(
name = "bio-rd",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = [
"main.go",
"main_ipv4.go",
],
importpath = "github.com/bio-routing/bio-rd/examples/bgp",
visibility = ["//visibility:private"],
deps = [
"//config:go_default_library",
"//net:go_default_library",
"//protocols/bgp/server:go_default_library",
"//routingtable:go_default_library",
"//routingtable/filter:go_default_library",
"//routingtable/locRIB:go_default_library",
"//vendor/github.com/sirupsen/logrus:go_default_library",
],
)
go_binary(
name = "bgp",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
File moved
File moved
File moved
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = ["main_bmp.go"],
importpath = "github.com/bio-routing/bio-rd/examples/bmp",
visibility = ["//visibility:private"],
deps = [
"//protocols/bmp/server:go_default_library",
"//routingtable/locRIB:go_default_library",
"//vendor/github.com/sirupsen/logrus:go_default_library",
],
)
go_binary(
name = "bmp",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
package main
import (
"fmt"
"net"
"time"
"github.com/bio-routing/bio-rd/protocols/bmp/server"
"github.com/bio-routing/bio-rd/routingtable/locRIB"
"github.com/sirupsen/logrus"
)
func main() {
logrus.Printf("This is a BMP speaker\n")
rib := locRIB.New()
b := server.NewServer()
b.AddRouter(net.IP{127, 0, 0, 1}, 1234, rib, nil)
go func() {
for {
fmt.Printf("LocRIB count: %d\n", rib.Count())
time.Sleep(time.Second * 10)
}
}()
select {}
}
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = ["gen_initial_corpus.go"],
importpath = "github.com/bio-routing/bio-rd/fuzzing/packet",
visibility = ["//visibility:private"],
)
go_binary(
name = "packet",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"common_header.go",
"decode.go",
"information_tlv.go",
"initiation_message.go",
"peer_down.go",
"peer_up.go",
"per_peer_header.go",
"route_mirroring.go",
"route_monitoring.go",
"stats_report.go",
"termination_message.go",
],
importpath = "github.com/bio-routing/bio-rd/protocols/bmp/packet",
visibility = ["//visibility:public"],
deps = [
"//util/decoder:go_default_library",
"//vendor/github.com/taktv6/tflow2/convert:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"common_header_test.go",
"decode_test.go",
"information_tlv_test.go",
"initiation_message_test.go",
"peer_down_test.go",
"peer_up_test.go",
"per_peer_header_test.go",
"route_mirroring_test.go",
"route_monitoring_test.go",
"stats_report_test.go",
"termination_message_test.go",
],
embed = [":go_default_library"],
deps = ["//vendor/github.com/stretchr/testify/assert:go_default_library"],
)
package packet
import (
"bytes"
"github.com/bio-routing/bio-rd/util/decoder"
"github.com/taktv6/tflow2/convert"
)
const (
// CommonHeaderLen is the length of a common header
CommonHeaderLen = 6
)
// CommonHeader represents a common header
type CommonHeader struct {
Version uint8
MsgLength uint32
MsgType uint8
}
// Serialize serializes a common header
func (c *CommonHeader) Serialize(buf *bytes.Buffer) {
buf.WriteByte(c.Version)
buf.Write(convert.Uint32Byte(c.MsgLength))
buf.WriteByte(c.MsgType)
}
func decodeCommonHeader(buf *bytes.Buffer) (*CommonHeader, error) {
ch := &CommonHeader{}
fields := []interface{}{
&ch.Version,
&ch.MsgLength,
&ch.MsgType,
}
err := decoder.Decode(buf, fields)
if err != nil {
return ch, err
}
return ch, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCommonHeaderSerialize(t *testing.T) {
tests := []struct {
name string
input *CommonHeader
expected []byte
}{
{
name: "Test #1",
input: &CommonHeader{
Version: 3,
MsgLength: 100,
MsgType: 10,
},
expected: []byte{3, 0, 0, 0, 100, 10},
},
}
for _, test := range tests {
buf := bytes.NewBuffer(nil)
test.input.Serialize(buf)
assert.Equalf(t, test.expected, buf.Bytes(), "Test %q", test.name)
}
}
func TestDecodeCommonHeader(t *testing.T) {
tests := []struct {
name string
input []byte
wantFail bool
expected *CommonHeader
}{
{
name: "Full packet",
input: []byte{
3, 0, 0, 0, 100, 10,
},
wantFail: false,
expected: &CommonHeader{
Version: 3,
MsgLength: 100,
MsgType: 10,
},
},
{
name: "Incomplete",
input: []byte{
3, 0, 0, 0, 100,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
ch, err := decodeCommonHeader(buf)
if err != nil {
if test.wantFail {
continue
}
t.Errorf("Unexpected failure for test %q: %v", test.name, err)
continue
}
if test.wantFail {
t.Errorf("Unexpected success for test %q", test.name)
continue
}
assert.Equalf(t, test.expected, ch, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"fmt"
)
const (
// MinLen is the minimal length of a BMP message
MinLen = 6
RouteMonitoringType = 0
StatisticsReportType = 1
PeerDownNotificationType = 2
PeerUpNotificationType = 3
InitiationMessageType = 4
TerminationMessageType = 5
RouteMirroringMessageType = 6
BGPMessage = 0
BGPInformation = 1
ErroredPDU = 0
MessageLost = 1
// BMPVersion is the supported BMP version
BMPVersion = 3
)
// Msg is an interface that every BMP message must fulfill
type Msg interface {
MsgType() uint8
}
// Decode decodes a BMP message
func Decode(msg []byte) (Msg, error) {
buf := bytes.NewBuffer(msg)
ch, err := decodeCommonHeader(buf)
if err != nil {
return nil, fmt.Errorf("Unable to decode common header: %v", err)
}
if ch.Version != BMPVersion {
return nil, fmt.Errorf("Unsupported BMP version: %d", ch.Version)
}
switch ch.MsgType {
case RouteMonitoringType:
rm, err := decodeRouteMonitoringMsg(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode route monitoring message: %v", err)
}
return rm, err
case StatisticsReportType:
sr, err := decodeStatsReport(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode stats report: %v", err)
}
return sr, nil
case PeerDownNotificationType:
pd, err := decodePeerUpNotification(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode peer down notification: %v", err)
}
return pd, nil
case PeerUpNotificationType:
pu, err := decodePeerUpNotification(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode peer up notification: %v", err)
}
return pu, nil
case InitiationMessageType:
im, err := decodeInitiationMessage(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode initiation message: %v", err)
}
return im, nil
case TerminationMessageType:
tm, err := decodeTerminationMessage(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode termination message: %v", err)
}
return tm, nil
case RouteMirroringMessageType:
rm, err := decodeRouteMirroringMsg(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode route mirroring message: %v", err)
}
return rm, nil
default:
return nil, fmt.Errorf("Unexpected message type: %d", ch.MsgType)
}
}
package packet
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecode(t *testing.T) {
tests := []struct {
name string
input []byte
wantFail bool
expected Msg
}{
{
name: "incomplete common header",
input: []byte{1, 2},
wantFail: true,
},
{
name: "Invalid version",
input: []byte{0, 0, 0, 0, 6, 5},
wantFail: true,
},
{
name: "Route monitoring ok",
input: []byte{
3, 0, 0, 0, 6 + 38 + 4, 0,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
1, 2, 3, 4,
},
wantFail: false,
expected: &RouteMonitoringMsg{
CommonHeader: &CommonHeader{
Version: 3,
MsgLength: 6 + 38 + 4,
MsgType: 0,
},
PerPeerHeader: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
BGPUpdate: []byte{1, 2, 3, 4},
},
},
{
name: "Route monitoring nok",
input: []byte{
3, 0, 0, 0, 6 + 38 + 4, 0,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
1, 2,
},
wantFail: true,
},
{
name: "Statistic report ok",
input: []byte{
3, 0, 0, 0, 6 + 9 + 38, 1,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
0, 0, 0, 1,
0, 1, 0, 1, 1,
},
wantFail: false,
expected: &StatsReport{
CommonHeader: &CommonHeader{
Version: 3,
MsgLength: 6 + 9 + 38,
MsgType: 1,
},
PerPeerHeader: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
StatsCount: 1,
Stats: []*InformationTLV{
{
InformationType: 1,
InformationLength: 1,
Information: []byte{1},
},
},
},
},
{
name: "Statistic report nok",
input: []byte{
3, 0, 0, 0, 6 + 9 + 38, 1,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
},
wantFail: true,
},
{
name: "peer down ok",
input: []byte{
3, 0, 0, 0, 6 + 9 + 38, 1,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
0, 0, 0, 1,
0, 1, 0, 1, 1,
},
wantFail: false,
expected: &StatsReport{
CommonHeader: &CommonHeader{
Version: 3,
MsgLength: 6 + 9 + 38,
MsgType: 1,
},
PerPeerHeader: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
StatsCount: 1,
Stats: []*InformationTLV{
{
InformationType: 1,
InformationLength: 1,
Information: []byte{1},
},
},
},
},
{
name: "peer down nok",
input: []byte{
3, 0, 0, 0, 6 + 9 + 38, 1,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
0, 0, 0, 1,
0, 1, 0, 1,
},
wantFail: true,
},
{
name: "peer up ok",
input: []byte{
3, 0, 0, 0, 54, 3,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 100,
0, 200,
// OPEN Sent
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
5, // Opt Parm Len
1, 2, 3, 4, 5,
// OPEN Recv
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
0, // Opt Parm Len
120, 140, 160, // Information
},
wantFail: false,
expected: &PeerUpNotification{
CommonHeader: &CommonHeader{
Version: 3,
MsgLength: 54,
MsgType: 3,
},
PerPeerHeader: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
LocalAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
LocalPort: 100,
RemotePort: 200,
SentOpenMsg: []byte{
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
5, // Opt Parm Len
1, 2, 3, 4, 5,
},
ReceivedOpenMsg: []byte{
// OPEN Recv
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
0, // Opt Parm Len
},
Information: []byte{
120, 140, 160, // Information
},
},
},
{
name: "peer up nok",
input: []byte{
3, 0, 0, 0, 54, 3,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 100,
0, 200,
// OPEN Sent
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
5, // Opt Parm Len
1, 2, 3, 4, 5,
// OPEN Recv
4, // Version
1,
},
wantFail: true,
},
{
name: "initiation message ok",
input: []byte{
3, 0, 0, 0, 11, 4,
0, 1, 0, 1, 5,
},
wantFail: false,
expected: &InitiationMessage{
CommonHeader: &CommonHeader{
Version: 3,
MsgLength: 11,
MsgType: 4,
},
TLVs: []*InformationTLV{
{
InformationType: 1,
InformationLength: 1,
Information: []byte{5},
},
},
},
},
{
name: "initiation message nok",
input: []byte{
3, 0, 0, 0,
},
wantFail: true,
},
{
name: "termination message ok",
input: []byte{
3, 0, 0, 0, 11, 5,
0, 1, 0, 1, 5,
},
wantFail: false,
expected: &TerminationMessage{
CommonHeader: &CommonHeader{
Version: 3,
MsgLength: 11,
MsgType: 5,
},
TLVs: []*InformationTLV{
{
InformationType: 1,
InformationLength: 1,
Information: []byte{5},
},
},
},
},
{
name: "termination message nok",
input: []byte{
3, 0, 0, 0, 11, 5,
0, 1, 0,
},
wantFail: true,
},
{
name: "route mirror message ok",
input: []byte{
3, 0, 0, 0, 49, 6,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
0, 1, 0, 1, 5,
},
wantFail: false,
expected: &RouteMirroringMsg{
CommonHeader: &CommonHeader{
Version: 3,
MsgLength: 49,
MsgType: 6,
},
PerPeerHeader: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
TLVs: []*InformationTLV{
{
InformationType: 1,
InformationLength: 1,
Information: []byte{5},
},
},
},
},
{
name: "route mirror message nok",
input: []byte{
3, 0, 0, 0, 49, 6,
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0,
},
wantFail: true,
},
{
name: "invalid msg type",
input: []byte{
3, 0, 0, 0, 49, 7,
},
wantFail: true,
},
}
for _, test := range tests {
m, err := Decode(test.input)
if err != nil {
if test.wantFail {
continue
}
t.Errorf("Unexpected failure for test %q: %v", test.name, err)
continue
}
if test.wantFail {
t.Errorf("Unexpected success for test %q", test.name)
continue
}
assert.Equalf(t, test.expected, m, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"github.com/bio-routing/bio-rd/util/decoder"
)
const (
MinInformationTLVLen = 4
)
// InformationTLV represents an information TLV
type InformationTLV struct {
InformationType uint16
InformationLength uint16
Information []byte
}
func decodeInformationTLV(buf *bytes.Buffer) (*InformationTLV, error) {
infoTLV := &InformationTLV{}
fields := []interface{}{
&infoTLV.InformationType,
&infoTLV.InformationLength,
}
err := decoder.Decode(buf, fields)
if err != nil {
return infoTLV, err
}
infoTLV.Information = make([]byte, infoTLV.InformationLength)
fields = []interface{}{
&infoTLV.Information,
}
err = decoder.Decode(buf, fields)
if err != nil {
return infoTLV, err
}
return infoTLV, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodeInformationTLV(t *testing.T) {
tests := []struct {
name string
input []byte
wantFail bool
expected *InformationTLV
}{
{
name: "Full",
input: []byte{
0, 10, 0, 5,
1, 2, 3, 4, 5,
},
wantFail: false,
expected: &InformationTLV{
InformationType: 10,
InformationLength: 5,
Information: []byte{1, 2, 3, 4, 5},
},
},
{
name: "Incomplete Value",
input: []byte{
0, 10, 0, 5,
1, 2, 3, 4,
},
wantFail: true,
},
{
name: "Incomplete Header",
input: []byte{
0, 10,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
infoTLV, err := decodeInformationTLV(buf)
if err != nil {
if test.wantFail {
continue
}
t.Errorf("Unexpected failure for test %q: %v", test.name, err)
continue
}
if test.wantFail {
t.Errorf("Unexpected success for test %q", test.name)
continue
}
assert.Equalf(t, test.expected, infoTLV, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"fmt"
)
// InitiationMessage represents an initiation message
type InitiationMessage struct {
CommonHeader *CommonHeader
TLVs []*InformationTLV
}
// MsgType returns the type of this message
func (im *InitiationMessage) MsgType() uint8 {
return im.CommonHeader.MsgType
}
func decodeInitiationMessage(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
im := &InitiationMessage{
CommonHeader: ch,
TLVs: make([]*InformationTLV, 0, 2),
}
read := uint32(0)
toRead := ch.MsgLength - CommonHeaderLen
for read < toRead {
tlv, err := decodeInformationTLV(buf)
if err != nil {
return nil, fmt.Errorf("Unable to decode TLV: %v", err)
}
im.TLVs = append(im.TLVs, tlv)
read += uint32(tlv.InformationLength) + MinInformationTLVLen
}
return im, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestInitiationMessageMsgType(t *testing.T) {
pd := &InitiationMessage{
CommonHeader: &CommonHeader{
MsgType: 100,
},
}
if pd.MsgType() != 100 {
t.Errorf("Unexpected result")
}
}
func TestDecodeInitiationMessage(t *testing.T) {
tests := []struct {
name string
input []byte
ch *CommonHeader
wantFail bool
expected *InitiationMessage
}{
{
name: "Full",
input: []byte{
0, 1, // sysDescr
0, 4, // Length
42, 42, 42, 42, // AAAA
0, 2, //sysName
0, 5, // Length
43, 43, 43, 43, 43, // BBBBB
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 17,
},
wantFail: false,
expected: &InitiationMessage{
CommonHeader: &CommonHeader{
MsgLength: CommonHeaderLen + 17,
},
TLVs: []*InformationTLV{
{
InformationType: 1,
InformationLength: 4,
Information: []byte{42, 42, 42, 42},
},
{
InformationType: 2,
InformationLength: 5,
Information: []byte{43, 43, 43, 43, 43},
},
},
},
},
{
name: "Incomplete",
input: []byte{
0, 1, // sysDescr
0, 4, // Length
42, 42, 42, 42, // AAAA
0, 2, //sysName
0, 5, // Length
43, 43, 43, 43, // BBBB
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 17,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
im, err := decodeInitiationMessage(buf, test.ch)
if err != nil {
if test.wantFail {
continue
}
t.Errorf("Unexpected failure for test %q: %v", test.name, err)
continue
}
if test.wantFail {
t.Errorf("Unexpected success for test %q", test.name)
continue
}
assert.Equalf(t, test.expected, im, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"fmt"
"github.com/bio-routing/bio-rd/util/decoder"
)
const (
reasonMin = 1
reasonMax = 3
)
// PeerDownNotification represents a peer down notification
type PeerDownNotification struct {
CommonHeader *CommonHeader
PerPeerHeader *PerPeerHeader
Reason uint8
Data []byte
}
// MsgType returns the type of this message
func (p *PeerDownNotification) MsgType() uint8 {
return p.CommonHeader.MsgType
}
func decodePeerDownNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerDownNotification, error) {
p := &PeerDownNotification{
CommonHeader: ch,
}
pph, err := decodePerPeerHeader(buf)
if err != nil {
return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
}
p.PerPeerHeader = pph
fields := []interface{}{
&p.Reason,
}
err = decoder.Decode(buf, fields)
if err != nil {
return nil, err
}
if p.Reason < reasonMin || p.Reason > reasonMax {
return p, nil
}
p.Data = make([]byte, ch.MsgLength-PerPeerHeaderLen-CommonHeaderLen-1)
fields = []interface{}{
p.Data,
}
err = decoder.Decode(buf, fields)
if err != nil {
return nil, err
}
return p, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestPeerDownMsgType(t *testing.T) {
pd := &PeerDownNotification{
CommonHeader: &CommonHeader{
MsgType: 100,
},
}
if pd.MsgType() != 100 {
t.Errorf("Unexpected result")
}
}
func TestDecodePeerDownNotification(t *testing.T) {
tests := []struct {
name string
input []byte
ch *CommonHeader
wantFail bool
expected *PeerDownNotification
}{
{
name: "Full",
input: []byte{
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
1,
1, 2, 3,
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 4 + 38,
},
wantFail: false,
expected: &PeerDownNotification{
CommonHeader: &CommonHeader{
MsgLength: CommonHeaderLen + 4 + 38,
},
PerPeerHeader: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
Reason: 1,
Data: []byte{
1, 2, 3,
},
},
},
{
name: "Full no data",
input: []byte{
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
4,
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + PerPeerHeaderLen + 4,
},
wantFail: false,
expected: &PeerDownNotification{
CommonHeader: &CommonHeader{
MsgLength: CommonHeaderLen + PerPeerHeaderLen + 4,
},
PerPeerHeader: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
Reason: 4,
Data: nil,
},
},
{
name: "Incomplete per peer header",
input: []byte{
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0,
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 5,
},
wantFail: true,
},
{
name: "Incomplete data",
input: []byte{
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
1,
1, 2, 3,
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 5,
},
wantFail: true,
},
{
name: "Incomplete",
input: []byte{},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 5,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
p, err := decodePeerDownNotification(buf, test.ch)
if err != nil {
if test.wantFail {
continue
}
t.Errorf("Unexpected failure for test %q: %v", test.name, err)
continue
}
if test.wantFail {
t.Errorf("Unexpected success for test %q", test.name)
continue
}
assert.Equalf(t, test.expected, p, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"fmt"
"github.com/bio-routing/bio-rd/util/decoder"
)
const (
// OpenMsgMinLen is the minimal length of a BGP open message
OpenMsgMinLen = 10
)
// PeerUpNotification represents a peer up notification
type PeerUpNotification struct {
CommonHeader *CommonHeader
PerPeerHeader *PerPeerHeader
LocalAddress [16]byte
LocalPort uint16
RemotePort uint16
SentOpenMsg []byte
ReceivedOpenMsg []byte
Information []byte
}
// MsgType returns the type of this message
func (p *PeerUpNotification) MsgType() uint8 {
return p.CommonHeader.MsgType
}
func decodePeerUpNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerUpNotification, error) {
p := &PeerUpNotification{
CommonHeader: ch,
}
pph, err := decodePerPeerHeader(buf)
if err != nil {
return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
}
p.PerPeerHeader = pph
fields := []interface{}{
&p.LocalAddress,
&p.LocalPort,
&p.RemotePort,
}
err = decoder.Decode(buf, fields)
if err != nil {
return nil, err
}
sentOpenMsg, err := getOpenMsg(buf)
if err != nil {
return nil, fmt.Errorf("Unable to get OPEN message: %v", err)
}
p.SentOpenMsg = sentOpenMsg
recvOpenMsg, err := getOpenMsg(buf)
if err != nil {
return nil, fmt.Errorf("Unable to get OPEN message: %v", err)
}
p.ReceivedOpenMsg = recvOpenMsg
if buf.Len() == 0 {
return p, nil
}
p.Information = make([]byte, buf.Len())
fields = []interface{}{
&p.Information,
}
// This can not fail as p.Information has exactly the size of what is left in buf
decoder.Decode(buf, fields)
return p, nil
}
func getOpenMsg(buf *bytes.Buffer) ([]byte, error) {
msg := make([]byte, OpenMsgMinLen)
fields := []interface{}{
&msg,
}
err := decoder.Decode(buf, fields)
if err != nil {
return nil, fmt.Errorf("Unable to read: %v", err)
}
if msg[OpenMsgMinLen-1] == 0 {
return msg, nil
}
optParams := make([]byte, msg[OpenMsgMinLen-1])
fields = []interface{}{
&optParams,
}
err = decoder.Decode(buf, fields)
if err != nil {
return nil, fmt.Errorf("Unable to read: %v", err)
}
msg = append(msg, optParams...)
return msg, nil
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment