Files
fgbgp/messages/bgp_open.go
2018-03-23 18:59:10 +01:00

386 lines
8.8 KiB
Go

package messages
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
log "github.com/sirupsen/logrus"
"io"
"net"
)
type BGPCapability_MP struct {
Afi uint16
Safi byte
}
type BGPCapability_ASN struct {
ASN uint32
}
type AddPath struct {
Afi uint16
Safi byte
TxRx byte
}
type BGPCapability_ROUTEREFRESH struct {
}
type BGPCapability_ADDPATH struct {
AddPathList []AddPath
}
type BGPCapability struct {
Type byte
Data []byte
}
type BGPCapabilityIf SerializableInterface
type BGPCapabilities struct {
BGPCapabilities []BGPCapabilityIf
}
type BGPParameterIf SerializableInterface
type BGPParameter struct {
Type byte
Data BGPParameterIf
}
type BGPMessageOpen struct {
BGPMessageHead
Version byte
ASN uint16
HoldTime uint16
Identifier []byte
Parameters []BGPParameter
}
func (m BGPParameter) String() string {
str := "Parameter (%v):"
str += m.Data.String()
return fmt.Sprintf(str, m.Type)
}
func (m BGPCapability) String() string {
str := "Capability: %v (%v): %v"
return fmt.Sprintf(str, CapaDescr[int(m.Type)], m.Type, m.Data)
}
func (c BGPCapability_ROUTEREFRESH) String() string {
return "Capability Route-Refresh"
}
func (c BGPCapability_MP) String() string {
return fmt.Sprintf("Capability Multiprotocol: %v-%v (%v) (%v)", AfiToStr[c.Afi], SafiToStr[c.Safi], c.Afi, c.Safi)
}
func (c BGPCapability_ADDPATH) String() string {
var addpathstr string
for i := range c.AddPathList {
addpathstr += c.AddPathList[i].String() + ", "
}
return fmt.Sprintf("Capability Add-Path: [ %v]", addpathstr)
}
func (c BGPCapability_ASN) String() string {
return fmt.Sprintf("Capability ASN: %v", c.ASN)
}
func (c BGPCapabilities) String() string {
var str string
for i := range c.BGPCapabilities {
if c.BGPCapabilities[i] != nil {
str += c.BGPCapabilities[i].String() + ", "
}
}
return str
}
func (m *BGPMessageOpen) String() string {
str := "BGP Open: Version: %v / ASN: %v / HoldTime: %v / Identifier: %v / Parameters (%v): [ "
ip := net.IP(m.Identifier)
str = fmt.Sprintf(str, m.Version, m.ASN, m.HoldTime, ip.String(), len(m.Parameters))
for i := range m.Parameters {
str += m.Parameters[i].String()
}
str += "]"
return str
}
func (m BGPCapabilities) Len() int {
var sum int
for c := range m.BGPCapabilities {
sum += m.BGPCapabilities[c].Len()
}
return sum
}
func (c BGPCapabilities) Write(bw io.Writer) {
for i := range c.BGPCapabilities {
c.BGPCapabilities[i].Write(bw)
}
}
func (m BGPCapability_ROUTEREFRESH) Len() int {
return 2
}
func (m BGPCapability_ROUTEREFRESH) Write(bw io.Writer) {
binary.Write(bw, binary.BigEndian, byte(CAPA_RR))
binary.Write(bw, binary.BigEndian, byte(0))
}
func (m BGPCapability_MP) Len() int {
return 6
}
func (m BGPCapability_MP) Write(bw io.Writer) {
binary.Write(bw, binary.BigEndian, byte(CAPA_MP))
binary.Write(bw, binary.BigEndian, byte(4))
binary.Write(bw, binary.BigEndian, m.Afi)
binary.Write(bw, binary.BigEndian, byte(0))
binary.Write(bw, binary.BigEndian, m.Safi)
}
func (m BGPCapability_ASN) Len() int {
return 6
}
func (m BGPCapability_ASN) Write(bw io.Writer) {
binary.Write(bw, binary.BigEndian, byte(CAPA_ASN))
binary.Write(bw, binary.BigEndian, byte(4))
binary.Write(bw, binary.BigEndian, m.ASN)
}
func (p AddPath) Len() int {
return 4
}
func (p AddPath) Write(bw io.Writer) {
binary.Write(bw, binary.BigEndian, p.Afi)
binary.Write(bw, binary.BigEndian, p.Safi)
binary.Write(bw, binary.BigEndian, p.TxRx)
}
func (m BGPCapability_ADDPATH) Len() int {
var sum int
for c := range m.AddPathList {
sum += m.AddPathList[c].Len()
}
return sum
}
func (m BGPCapability_ADDPATH) Write(bw io.Writer) {
for c := range m.AddPathList {
m.AddPathList[c].Write(bw)
}
}
func (m BGPCapability) Len() int {
return 1 + 1 + len(m.Data)
}
func (m BGPCapability) Write(bw io.Writer) {
binary.Write(bw, binary.BigEndian, m.Type)
binary.Write(bw, binary.BigEndian, byte(len(m.Data)))
binary.Write(bw, binary.BigEndian, m.Data)
}
func (m BGPParameter) Len() int {
return 1 + 1 + m.Data.Len()
}
func (m BGPParameter) Write(bw io.Writer) {
binary.Write(bw, binary.BigEndian, m.Type)
binary.Write(bw, binary.BigEndian, byte(m.Data.Len()))
m.Data.Write(bw)
}
func (m BGPMessageOpen) LenParams() int {
sum := 0
for i := range m.Parameters {
sum += m.Parameters[i].Len()
}
return sum
}
func (m BGPMessageOpen) LenContent() int {
return 10 + m.LenParams()
}
func (m BGPMessageOpen) Len() int {
return GetBGPHeaderLen() + m.LenContent()
}
func (m BGPMessageOpen) Write(bw io.Writer) {
WriteBGPHeader(MESSAGE_OPEN, uint16(m.LenContent()), bw)
binary.Write(bw, binary.BigEndian, m.Version)
binary.Write(bw, binary.BigEndian, m.ASN)
binary.Write(bw, binary.BigEndian, m.HoldTime)
binary.Write(bw, binary.BigEndian, m.Identifier[0:4])
binary.Write(bw, binary.BigEndian, byte(m.LenParams()))
for i := range m.Parameters {
m.Parameters[i].Write(bw)
}
}
func (c BGPCapability) ParseCapability() BGPCapabilityIf {
buf := bytes.NewBuffer(c.Data)
var ret BGPCapabilityIf
switch c.Type {
case CAPA_MP:
mpstruct := BGPCapability_MP{}
binary.Read(buf, binary.BigEndian, &mpstruct.Afi)
buf.ReadByte()
binary.Read(buf, binary.BigEndian, &mpstruct.Safi)
ret = mpstruct
case CAPA_ADDPATH:
apstruct := BGPCapability_ADDPATH{
AddPathList: make([]AddPath, len(c.Data)/4),
}
for i := 0; i < len(c.Data)/4; i++ {
binary.Read(buf, binary.BigEndian, &(apstruct.AddPathList[i].Afi))
binary.Read(buf, binary.BigEndian, &(apstruct.AddPathList[i].Safi))
binary.Read(buf, binary.BigEndian, &(apstruct.AddPathList[i].TxRx))
}
ret = apstruct
case CAPA_ASN:
asnstruct := BGPCapability_ASN{}
binary.Read(buf, binary.BigEndian, &asnstruct.ASN)
ret = asnstruct
case CAPA_RR:
ret = BGPCapability_ROUTEREFRESH{}
default:
unknownstruct := BGPCapability{}
unknownstruct.Type = c.Type
unknownstruct.Data = c.Data
ret = unknownstruct
}
return ret
}
func ParseOpen(b []byte) (*BGPMessageOpen, error) {
m := BGPMessageOpen{}
if len(b) < 10 {
return nil, errors.New(fmt.Sprintf("ParseOpen: wrong open size: %v < 10", len(b)))
}
version := b[0]
asn := uint16(b[1])<<8 | uint16(b[2])
holdtime := uint16(b[3])<<8 | uint16(b[4])
if holdtime > 0 && holdtime < 3 {
log.Warnf("ParseOpen: BGP open hold time must be zero or at least 3. Got %v.", holdtime)
}
identifier := b[5:9]
optparamlen := int(b[9])
m.Version = version
m.HoldTime = holdtime
m.Identifier = identifier
m.ASN = asn
m.Parameters = make([]BGPParameter, 0)
if len(b)-10 != optparamlen {
return nil, errors.New(fmt.Sprintf("ParseOpen: wrong open size for optional parameters: %v != %v", len(b)-10, optparamlen))
}
if optparamlen > 0 && len(b)-10 >= 2 {
i := 10
for i < len(b)-1 {
parmtype := b[i]
parmlength := int(b[i+1])
if i+1+parmlength > len(b) {
return nil, errors.New(fmt.Sprintf("ParseOpen: wrong parameter length: %v > %v", i+1+parmlength, len(b)))
}
i += 2
bgpparameter := BGPParameter{
Type: parmtype,
}
var parameterdata BGPCapabilityIf
baseparam := i
switch parmtype {
case PARAMETER_CAPA:
bgpcapa := BGPCapabilities{make([]BGPCapabilityIf, 0)}
for i < len(b)-1 && i < baseparam+parmlength {
capatype := b[i]
capalength := int(b[i+1])
if i+1+capalength > len(b) {
return nil, errors.New(fmt.Sprintf("ParseOpen: wrong capability length: %v > %v", i+1+capalength, len(b)))
}
capa := b[i+2 : i+2+capalength]
//log.Debugf("ParseOpen: Capa %v %v %v", capatype, capalength, capa)
i += 2 + capalength
capastruct := BGPCapability{
Type: capatype,
Data: capa,
}
capastructparsed := capastruct.ParseCapability()
bgpcapa.BGPCapabilities = append(bgpcapa.BGPCapabilities, capastructparsed)
}
parameterdata = bgpcapa
}
bgpparameter.Data = parameterdata
m.Parameters = append(m.Parameters, bgpparameter)
}
}
return &m, nil
}
func CraftOpenMessage(asn uint32, holdtime uint16, identifier []byte, mplist []BGPCapability_MP, addpathlist []AddPath, routerefresh bool) *BGPMessageOpen {
asn_2o := uint16(asn)
if asn >= 65536 {
asn_2o = 23456
}
// Check for identifier = 4: "bytes",
open := &BGPMessageOpen{
Version: 4,
ASN: asn_2o,
HoldTime: holdtime,
Identifier: identifier,
Parameters: make([]BGPParameter, 1)}
ptr := &BGPCapabilities{make([]BGPCapabilityIf, 0)}
ptr.BGPCapabilities = append(ptr.BGPCapabilities, &BGPCapability_ASN{asn})
if mplist != nil && len(mplist) > 0 {
for i := range mplist {
ptr.BGPCapabilities = append(ptr.BGPCapabilities, &mplist[i])
}
}
if addpathlist != nil && len(addpathlist) > 0 {
addpathcapa := BGPCapability_ADDPATH{AddPathList: addpathlist}
ptr.BGPCapabilities = append(ptr.BGPCapabilities, addpathcapa)
}
if routerefresh {
ptr.BGPCapabilities = append(ptr.BGPCapabilities, BGPCapability_ROUTEREFRESH{})
}
parameter := BGPParameter{
Type: PARAMETER_CAPA,
Data: ptr,
}
open.Parameters[0] = parameter
return open
}