Initial
This commit is contained in:
385
messages/bgp_open.go
Normal file
385
messages/bgp_open.go
Normal file
@@ -0,0 +1,385 @@
|
||||
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
|
||||
}
|
||||
797
messages/bgp_update.go
Normal file
797
messages/bgp_update.go
Normal file
@@ -0,0 +1,797 @@
|
||||
package messages
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BGPAttribute_NEXTHOP struct {
|
||||
NextHop net.IP
|
||||
}
|
||||
|
||||
type BGPAttribute_ORIGIN struct {
|
||||
Origin byte
|
||||
}
|
||||
|
||||
type BGPAttribute_MED struct {
|
||||
Med uint32
|
||||
}
|
||||
|
||||
type BGPAttribute_LOCPREF struct {
|
||||
LocPref uint32
|
||||
}
|
||||
|
||||
type BGPAttribute_COMMUNITIES struct {
|
||||
Communities []uint32
|
||||
}
|
||||
|
||||
type ASPath_Segment struct {
|
||||
SType byte
|
||||
ASPath []uint32
|
||||
}
|
||||
|
||||
type BGPAttribute_ASPATH struct {
|
||||
Segments []ASPath_Segment
|
||||
Enc2Bytes bool
|
||||
}
|
||||
|
||||
type BGPAttribute_MP_UNREACH struct {
|
||||
Afi uint16
|
||||
Safi byte
|
||||
NLRI []NLRI
|
||||
|
||||
EnableAddPath bool
|
||||
}
|
||||
|
||||
type BGPAttribute_MP_REACH struct {
|
||||
Afi uint16
|
||||
Safi byte
|
||||
NextHop net.IP
|
||||
NLRI []NLRI
|
||||
|
||||
EnableAddPath bool
|
||||
}
|
||||
|
||||
type BGPAttribute_ATOMIC_AGGREGATE struct {
|
||||
}
|
||||
|
||||
type BGPAttribute_AGGREGATOR struct {
|
||||
ASN uint32
|
||||
Identifier []byte
|
||||
Enc2Bytes bool
|
||||
}
|
||||
|
||||
type BGPAttributeIf SerializableInterface
|
||||
|
||||
type BGPAttribute struct {
|
||||
Flags byte
|
||||
Code byte
|
||||
Data []byte
|
||||
}
|
||||
|
||||
type BGPMessageUpdate struct {
|
||||
BGPMessageHead
|
||||
WithdrawnRoutes []NLRI
|
||||
PathAttributes []BGPAttributeIf
|
||||
NLRI []NLRI
|
||||
|
||||
EnableAddPath bool
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ORIGIN) String() string {
|
||||
return fmt.Sprintf("Origin: %v", m.Origin)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_AGGREGATOR) String() string {
|
||||
id := net.IP(m.Identifier)
|
||||
return fmt.Sprintf("Aggregator: ASN: %v / Id: %v", m.ASN, id)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ATOMIC_AGGREGATE) String() string {
|
||||
return "Atomic aggregate"
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MED) String() string {
|
||||
return fmt.Sprintf("Med: %v", m.Med)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_LOCPREF) String() string {
|
||||
return fmt.Sprintf("LocPref: %v", m.LocPref)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ASPATH) String() string {
|
||||
return fmt.Sprintf("ASPath: %v", m.Segments)
|
||||
}
|
||||
|
||||
func (m ASPath_Segment) String() string {
|
||||
return fmt.Sprintf("Segment (type: %v | len: %v): %v", m.SType, len(m.ASPath), m.ASPath)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_COMMUNITIES) String() string {
|
||||
var comlist string
|
||||
for i := range m.Communities {
|
||||
comlist += fmt.Sprintf("%v:%v, ", m.Communities[i]&0xFFFF0000>>16, m.Communities[i]&0xFFFF)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Communities: [ %v]", comlist)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_REACH) String() string {
|
||||
var NLRI string
|
||||
for i := range m.NLRI {
|
||||
NLRI += m.NLRI[i].String() + ", "
|
||||
}
|
||||
|
||||
return fmt.Sprintf("MP Reach: %v-%v (%v) (%v) / Nexthop: %v / NLRI: [ %v]", AfiToStr[m.Afi], SafiToStr[m.Safi], m.Afi, m.Safi, m.NextHop, NLRI)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_UNREACH) String() string {
|
||||
var NLRI string
|
||||
for i := range m.NLRI {
|
||||
NLRI += m.NLRI[i].String() + ", "
|
||||
}
|
||||
|
||||
return fmt.Sprintf("MP Unreach: %v-%v (%v) (%v) / NLRI: [ %v]", AfiToStr[m.Afi], SafiToStr[m.Safi], m.Afi, m.Safi, NLRI)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_NEXTHOP) String() string {
|
||||
return fmt.Sprintf("Nexthop %v", m.NextHop.String())
|
||||
}
|
||||
|
||||
func (m BGPAttribute) String() string {
|
||||
str := "%b %v (%v): %v"
|
||||
return fmt.Sprintf(str, m.Flags, BgpAttributes[int(m.Code)], m.Code, m.Data)
|
||||
}
|
||||
|
||||
func (m BGPMessageUpdate) String() string {
|
||||
// To be completed
|
||||
return fmt.Sprintf("BGP Update: Withdraw: %v / PathAttributes: %v / NLRI: %v", m.WithdrawnRoutes, m.PathAttributes, m.NLRI)
|
||||
}
|
||||
|
||||
func (m BGPMessageUpdate) LenWithdrawn() int {
|
||||
var sumW int
|
||||
for i := range m.WithdrawnRoutes {
|
||||
sumW += m.WithdrawnRoutes[i].Len(m.EnableAddPath)
|
||||
}
|
||||
return sumW
|
||||
}
|
||||
|
||||
func (m BGPMessageUpdate) LenPathAttribute() int {
|
||||
var sumPA int
|
||||
for i := range m.PathAttributes {
|
||||
sumPA += m.PathAttributes[i].Len()
|
||||
}
|
||||
return sumPA
|
||||
}
|
||||
|
||||
func (m BGPMessageUpdate) LenContent() int {
|
||||
sumW := m.LenWithdrawn()
|
||||
sumPA := m.LenPathAttribute()
|
||||
|
||||
var sumA int
|
||||
for i := range m.NLRI {
|
||||
sumA += m.NLRI[i].Len(m.EnableAddPath)
|
||||
}
|
||||
|
||||
return 2 + sumW + 2 + sumPA + sumA
|
||||
}
|
||||
|
||||
func (m BGPMessageUpdate) Len() int {
|
||||
return GetBGPHeaderLen() + m.LenContent()
|
||||
}
|
||||
|
||||
func (m BGPMessageUpdate) Write(bw io.Writer) {
|
||||
WriteBGPHeader(MESSAGE_UPDATE, uint16(m.LenContent()), bw)
|
||||
|
||||
binary.Write(bw, binary.BigEndian, uint16(m.LenWithdrawn()))
|
||||
for i := range m.WithdrawnRoutes {
|
||||
m.WithdrawnRoutes[i].Write(bw, m.EnableAddPath)
|
||||
}
|
||||
|
||||
binary.Write(bw, binary.BigEndian, uint16(m.LenPathAttribute()))
|
||||
for i := range m.PathAttributes {
|
||||
m.PathAttributes[i].Write(bw)
|
||||
}
|
||||
|
||||
for i := range m.NLRI {
|
||||
m.NLRI[i].Write(bw, m.EnableAddPath)
|
||||
}
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ORIGIN) Len() int {
|
||||
return AttributeHeaderLen(1) + 1
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ORIGIN) Write(bw io.Writer) {
|
||||
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_TRANSITIVE))
|
||||
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_ORIGIN))
|
||||
binary.Write(bw, binary.BigEndian, byte(1))
|
||||
binary.Write(bw, binary.BigEndian, m.Origin)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_AGGREGATOR) Len() int {
|
||||
return AttributeHeaderLen(8) + 8
|
||||
}
|
||||
|
||||
func (m BGPAttribute_AGGREGATOR) Write(bw io.Writer) {
|
||||
// May cause issue as ASN is 32 bits
|
||||
|
||||
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_OPTIONAL))
|
||||
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_AGGREGATOR))
|
||||
binary.Write(bw, binary.BigEndian, byte(8))
|
||||
binary.Write(bw, binary.BigEndian, m.ASN)
|
||||
binary.Write(bw, binary.BigEndian, m.Identifier)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ATOMIC_AGGREGATE) Len() int {
|
||||
return AttributeHeaderLen(0)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ATOMIC_AGGREGATE) Write(bw io.Writer) {
|
||||
WriteAttributeHeader(bw, 0, ATTRIBUTE_OPTIONAL, ATTRIBUTE_ATOMIC_AGGREGATE)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MED) Len() int {
|
||||
return AttributeHeaderLen(4) + 4
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MED) Write(bw io.Writer) {
|
||||
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_OPTIONAL))
|
||||
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_MED))
|
||||
binary.Write(bw, binary.BigEndian, byte(4))
|
||||
binary.Write(bw, binary.BigEndian, m.Med)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_LOCPREF) Len() int {
|
||||
return AttributeHeaderLen(4) + 4
|
||||
}
|
||||
|
||||
func (m BGPAttribute_LOCPREF) Write(bw io.Writer) {
|
||||
WriteAttributeHeader(bw, 4, ATTRIBUTE_OPTIONAL, ATTRIBUTE_LOCPREF)
|
||||
binary.Write(bw, binary.BigEndian, m.LocPref)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ASPATH) Len() int {
|
||||
var size int
|
||||
for i := range m.Segments {
|
||||
size += m.Segments[i].LenContent(m.Enc2Bytes)
|
||||
}
|
||||
return AttributeHeaderLen(size) + size
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ASPATH) Write(bw io.Writer) {
|
||||
WriteAttributeHeader(bw, m.LenContent(), ATTRIBUTE_TRANSITIVE, ATTRIBUTE_ASPATH)
|
||||
if len(m.Segments) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for i := range m.Segments {
|
||||
m.Segments[i].Write(bw, m.Enc2Bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func (m BGPAttribute_ASPATH) LenContent() int {
|
||||
var size int
|
||||
for i := range m.Segments {
|
||||
size += m.Segments[i].LenContent(m.Enc2Bytes)
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (m ASPath_Segment) LenSets() int {
|
||||
aspathlen := len(m.ASPath)
|
||||
itera := aspathlen / 0xff
|
||||
if aspathlen%0xff != 0 {
|
||||
itera += 1
|
||||
}
|
||||
return itera
|
||||
}
|
||||
|
||||
func (m ASPath_Segment) LenContent(enc2bytes bool) int {
|
||||
if len(m.ASPath) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
numsets := m.LenSets()
|
||||
if enc2bytes {
|
||||
return 2*numsets + 2*len(m.ASPath)
|
||||
}
|
||||
return 2*numsets + 4*len(m.ASPath)
|
||||
}
|
||||
|
||||
func (m ASPath_Segment) Write(bw io.Writer, enc2bytes bool) {
|
||||
if len(m.ASPath) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
itera := m.LenSets()
|
||||
var cursetlen byte
|
||||
|
||||
for i := 0; i < itera; i++ {
|
||||
cursetlen = 0xff
|
||||
if i == itera-1 {
|
||||
cursetlen = byte(len(m.ASPath) % 0xff)
|
||||
}
|
||||
binary.Write(bw, binary.BigEndian, m.SType)
|
||||
binary.Write(bw, binary.BigEndian, byte(cursetlen))
|
||||
for j := 0xff * i; j < len(m.ASPath) && j < 0xff*(i+1); j++ {
|
||||
if enc2bytes {
|
||||
binary.Write(bw, binary.BigEndian, uint16(m.ASPath[j]))
|
||||
} else {
|
||||
binary.Write(bw, binary.BigEndian, m.ASPath[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AttributeHeaderLen(size int) int {
|
||||
if size > 0xff {
|
||||
return 4
|
||||
} else {
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
func IPtoBytes(ip net.IP) []byte {
|
||||
if ip.To4() == nil {
|
||||
return ip.To16()
|
||||
}
|
||||
return ip.To4()
|
||||
}
|
||||
|
||||
func WriteAttributeHeader(bw io.Writer, size int, attrflag byte, attrcode byte) {
|
||||
var extended byte
|
||||
if size > 0xff {
|
||||
extended = ATTRIBUTE_EXTENDED
|
||||
}
|
||||
binary.Write(bw, binary.BigEndian, byte(attrflag|extended))
|
||||
binary.Write(bw, binary.BigEndian, attrcode)
|
||||
if extended != 0 {
|
||||
binary.Write(bw, binary.BigEndian, byte((size&0xff00)>>8))
|
||||
}
|
||||
binary.Write(bw, binary.BigEndian, byte(size&0xff))
|
||||
}
|
||||
|
||||
func (m BGPAttribute_COMMUNITIES) LenContent() int {
|
||||
return 4 * len(m.Communities)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_COMMUNITIES) Len() int {
|
||||
size := m.LenContent()
|
||||
return AttributeHeaderLen(size) + size
|
||||
}
|
||||
|
||||
func (m BGPAttribute_COMMUNITIES) Write(bw io.Writer) {
|
||||
WriteAttributeHeader(bw, m.LenContent(), ATTRIBUTE_TRANSITIVEOPT, ATTRIBUTE_COMMUNITIES)
|
||||
for i := range m.Communities {
|
||||
binary.Write(bw, binary.BigEndian, m.Communities[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_REACH) LenMrt() uint16 {
|
||||
ip := IPtoBytes(m.NextHop)
|
||||
return 2 + 1 + 1 + uint16(len(ip))
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_REACH) WriteMrt(buf io.Writer) {
|
||||
binary.Write(buf, binary.BigEndian, byte(ATTRIBUTE_OPTIONAL))
|
||||
binary.Write(buf, binary.BigEndian, byte(ATTRIBUTE_REACH))
|
||||
|
||||
nhb := IPtoBytes(m.NextHop)
|
||||
lengthnh := len(nhb)
|
||||
|
||||
binary.Write(buf, binary.BigEndian, byte(1+lengthnh))
|
||||
binary.Write(buf, binary.BigEndian, byte(lengthnh))
|
||||
binary.Write(buf, binary.BigEndian, nhb)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_REACH) GetNextHopLen() int {
|
||||
return len(IPtoBytes(m.NextHop))
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_REACH) ContentLen() int {
|
||||
var sum int
|
||||
for i := range m.NLRI {
|
||||
sum += m.NLRI[i].Len(m.EnableAddPath)
|
||||
}
|
||||
|
||||
size := 4 + m.GetNextHopLen() + 1 + sum
|
||||
return size
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_REACH) Len() int {
|
||||
size := m.ContentLen()
|
||||
return AttributeHeaderLen(size) + size
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_REACH) Write(bw io.Writer) {
|
||||
WriteAttributeHeader(bw, m.ContentLen(), ATTRIBUTE_OPTIONAL, ATTRIBUTE_REACH)
|
||||
|
||||
binary.Write(bw, binary.BigEndian, m.Afi)
|
||||
binary.Write(bw, binary.BigEndian, m.Safi)
|
||||
binary.Write(bw, binary.BigEndian, byte(m.GetNextHopLen()))
|
||||
binary.Write(bw, binary.BigEndian, IPtoBytes(m.NextHop))
|
||||
binary.Write(bw, binary.BigEndian, byte(0))
|
||||
for i := range m.NLRI {
|
||||
m.NLRI[i].Write(bw, m.EnableAddPath)
|
||||
}
|
||||
}
|
||||
func (m BGPAttribute_MP_UNREACH) ContentLen() int {
|
||||
var sum int
|
||||
for i := range m.NLRI {
|
||||
sum += m.NLRI[i].Len(m.EnableAddPath)
|
||||
}
|
||||
size := 3 + sum
|
||||
return size
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_UNREACH) Len() int {
|
||||
size := m.ContentLen()
|
||||
return AttributeHeaderLen(size) + size
|
||||
}
|
||||
|
||||
func (m BGPAttribute_MP_UNREACH) Write(bw io.Writer) {
|
||||
WriteAttributeHeader(bw, m.ContentLen(), ATTRIBUTE_OPTIONAL, ATTRIBUTE_UNREACH)
|
||||
|
||||
binary.Write(bw, binary.BigEndian, m.Afi)
|
||||
binary.Write(bw, binary.BigEndian, m.Safi)
|
||||
for i := range m.NLRI {
|
||||
m.NLRI[i].Write(bw, m.EnableAddPath)
|
||||
}
|
||||
}
|
||||
|
||||
func (m BGPAttribute_NEXTHOP) ContentLen() int {
|
||||
ip := IPtoBytes(m.NextHop)
|
||||
return len(ip)
|
||||
}
|
||||
|
||||
func (m BGPAttribute_NEXTHOP) Len() int {
|
||||
size := m.ContentLen()
|
||||
return AttributeHeaderLen(size) + size
|
||||
}
|
||||
|
||||
func (m BGPAttribute_NEXTHOP) Write(bw io.Writer) {
|
||||
WriteAttributeHeader(bw, m.ContentLen(), ATTRIBUTE_TRANSITIVE, ATTRIBUTE_NEXTHOP)
|
||||
|
||||
ip := IPtoBytes(m.NextHop)
|
||||
binary.Write(bw, binary.BigEndian, ip)
|
||||
}
|
||||
|
||||
func (m BGPAttribute) Len() int {
|
||||
size := len(m.Data)
|
||||
return AttributeHeaderLen(size) + size
|
||||
}
|
||||
|
||||
func (m BGPAttribute) Write(bw io.Writer) {
|
||||
WriteAttributeHeader(bw, len(m.Data), m.Flags, m.Code)
|
||||
binary.Write(bw, binary.BigEndian, m.Data)
|
||||
}
|
||||
|
||||
/*func (m *BGPMessageUpdate) AddASNToPath(asn uint32) {
|
||||
for i := range(m.PathAttributes) {
|
||||
if v,ok := m.PathAttributes[i].(BGPAttribute_ASPATH); ok {
|
||||
v.ASPath = append(v.ASPath, asn)
|
||||
m.PathAttributes[i] = v
|
||||
return
|
||||
}
|
||||
}
|
||||
m.PathAttributes = append(m.PathAttributes, BGPAttribute_ASPATH{
|
||||
SType: 2,
|
||||
ASPath: []uint32{asn,},
|
||||
})
|
||||
}*/
|
||||
|
||||
func ParseNLRI(b []byte, afi uint16, safi byte, path bool) ([]NLRI, error) {
|
||||
prefixlist := make([]NLRI, 0)
|
||||
|
||||
if afi != AFI_IPV4 && afi != AFI_IPV6 {
|
||||
return prefixlist, errors.New(fmt.Sprintf("ParseNLRI: cannot decode this Afi/Safi %v/%v", afi, safi))
|
||||
}
|
||||
|
||||
psize := 32
|
||||
asize := 4
|
||||
if afi == AFI_IPV6 {
|
||||
psize = 128
|
||||
asize = 16
|
||||
}
|
||||
|
||||
i := 0
|
||||
|
||||
for i < len(b) {
|
||||
|
||||
var pathid uint32
|
||||
if path {
|
||||
if len(b)-i < 5 {
|
||||
return nil, errors.New(fmt.Sprintf("ParseNLRI: wrong NLRI size with add-path: %v < 5", len(b)))
|
||||
}
|
||||
pathid = uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3])
|
||||
i += 4
|
||||
}
|
||||
|
||||
length := int(b[i])
|
||||
lengthb := length
|
||||
add := 0
|
||||
if length%8 != 0 {
|
||||
add = 1
|
||||
}
|
||||
length = length/8 + add
|
||||
i++
|
||||
if i+length > len(b) {
|
||||
return prefixlist, errors.New(fmt.Sprintf("ParseNLRI: wrong NLRI size: %v > %v", i+length, len(b)))
|
||||
}
|
||||
prefix := b[i : i+length]
|
||||
|
||||
mask := net.CIDRMask(lengthb, psize)
|
||||
ip := make([]byte, asize)
|
||||
|
||||
if len(prefix) > len(ip) {
|
||||
return prefixlist, errors.New(fmt.Sprintf("ParseNLRI: wrong IP size: %v > %v", len(prefix), len(ip)))
|
||||
}
|
||||
|
||||
for j := range prefix {
|
||||
ip[j] = prefix[j]
|
||||
}
|
||||
ipnet := net.IPNet{
|
||||
IP: ip,
|
||||
Mask: mask,
|
||||
}
|
||||
prefixlist = append(prefixlist, NLRI_IPPrefix{
|
||||
Prefix: ipnet,
|
||||
PathId: pathid,
|
||||
})
|
||||
|
||||
i += length
|
||||
}
|
||||
return prefixlist, nil
|
||||
}
|
||||
|
||||
func ParsePathAttribute(b []byte, addpathlist []AfiSafi, enc2bytes bool) ([]BGPAttributeIf, error) {
|
||||
attributes := make([]BGPAttributeIf, 0)
|
||||
i := 0
|
||||
for i < len(b) {
|
||||
if len(b)-i < 3 {
|
||||
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: attribute size (need 3 bytes, got %v)", len(b)-i))
|
||||
}
|
||||
attrflag := b[i]
|
||||
attrcode := b[i+1]
|
||||
extended := byte((attrflag & ATTRIBUTE_EXTENDED) >> 4)
|
||||
length := int(b[i+2])
|
||||
|
||||
if extended != 0 && i+3 > len(b)-1 {
|
||||
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: wrong extended size: %v > %v", i+3, len(b)-1))
|
||||
}
|
||||
|
||||
offset := 0
|
||||
if extended != 0 {
|
||||
length = int(uint16(b[i+2])<<8 | uint16(b[i+3]))
|
||||
offset = 1
|
||||
}
|
||||
if i+offset+3+length > len(b) || i+offset+3 > len(b) {
|
||||
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: wrong size: %v > %v or %v > %v (ext: %v / %v)", i+offset+3+length, len(b), i+offset+3, len(b), i, extended))
|
||||
}
|
||||
|
||||
data := b[i+offset+3 : i+offset+3+length]
|
||||
|
||||
if i+3+offset+length > len(b) {
|
||||
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: wrong attribute size: %v > %v", i+3+length, len(b)))
|
||||
}
|
||||
|
||||
var intf SerializableInterface
|
||||
buf := bytes.NewBuffer(data)
|
||||
|
||||
switch attrcode {
|
||||
case ATTRIBUTE_ORIGIN:
|
||||
o := byte(2)
|
||||
if len(data) > 0 {
|
||||
o = data[0]
|
||||
} else {
|
||||
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: empty data for ORIGIN attribute"))
|
||||
}
|
||||
a := BGPAttribute_ORIGIN{
|
||||
Origin: o,
|
||||
}
|
||||
intf = a
|
||||
case ATTRIBUTE_MED:
|
||||
a := BGPAttribute_MED{}
|
||||
binary.Read(buf, binary.BigEndian, &(a.Med))
|
||||
intf = a
|
||||
case ATTRIBUTE_AGGREGATOR:
|
||||
a := BGPAttribute_AGGREGATOR{}
|
||||
if len(data) == 8 && !enc2bytes {
|
||||
binary.Read(buf, binary.BigEndian, &(a.ASN))
|
||||
a.Identifier = data[4:8]
|
||||
} else if len(data) == 6 && enc2bytes {
|
||||
var tmpas uint16
|
||||
binary.Read(buf, binary.BigEndian, &tmpas)
|
||||
a.ASN = uint32(tmpas)
|
||||
a.Identifier = data[2:6]
|
||||
}
|
||||
a.Enc2Bytes = enc2bytes
|
||||
intf = a
|
||||
case ATTRIBUTE_ATOMIC_AGGREGATE:
|
||||
a := BGPAttribute_ATOMIC_AGGREGATE{}
|
||||
intf = a
|
||||
case ATTRIBUTE_LOCPREF:
|
||||
a := BGPAttribute_LOCPREF{}
|
||||
binary.Read(buf, binary.BigEndian, &(a.LocPref))
|
||||
intf = a
|
||||
case ATTRIBUTE_ASPATH:
|
||||
a := BGPAttribute_ASPATH{Segments: make([]ASPath_Segment, 0)}
|
||||
|
||||
var aslen byte
|
||||
var err_rd error
|
||||
var stype byte
|
||||
stype, err_rd = buf.ReadByte()
|
||||
for err_rd == nil {
|
||||
aslen, err_rd = buf.ReadByte()
|
||||
if err_rd != nil {
|
||||
break
|
||||
}
|
||||
|
||||
s := ASPath_Segment{SType: stype, ASPath: make([]uint32, 0)}
|
||||
|
||||
if err_rd != nil {
|
||||
break
|
||||
}
|
||||
if !enc2bytes {
|
||||
var tmpas uint32
|
||||
if err_rd != nil {
|
||||
break
|
||||
}
|
||||
for j := 0; j < int(aslen) && j <= 255; j++ {
|
||||
binary.Read(buf, binary.BigEndian, &tmpas)
|
||||
s.ASPath = append(s.ASPath, tmpas)
|
||||
}
|
||||
|
||||
} else {
|
||||
var tmpas uint16
|
||||
if err_rd != nil {
|
||||
break
|
||||
}
|
||||
for j := 0; j < int(aslen) && j <= 255; j++ {
|
||||
binary.Read(buf, binary.BigEndian, &tmpas)
|
||||
s.ASPath = append(s.ASPath, uint32(tmpas))
|
||||
}
|
||||
|
||||
}
|
||||
a.Segments = append(a.Segments, s)
|
||||
stype, err_rd = buf.ReadByte()
|
||||
if err_rd != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
a.Enc2Bytes = enc2bytes
|
||||
intf = a
|
||||
case ATTRIBUTE_NEXTHOP:
|
||||
intf = BGPAttribute_NEXTHOP{NextHop: data[0:4]}
|
||||
case ATTRIBUTE_COMMUNITIES:
|
||||
a := BGPAttribute_COMMUNITIES{Communities: make([]uint32, length/4)}
|
||||
for j := 0; j < length/4; j++ {
|
||||
binary.Read(buf, binary.BigEndian, &(a.Communities[j]))
|
||||
}
|
||||
intf = a
|
||||
case ATTRIBUTE_REACH:
|
||||
a := BGPAttribute_MP_REACH{}
|
||||
binary.Read(buf, binary.BigEndian, &(a.Afi))
|
||||
binary.Read(buf, binary.BigEndian, &(a.Safi))
|
||||
nhlen, _ := buf.ReadByte()
|
||||
nh := make([]byte, nhlen)
|
||||
buf.Read(nh)
|
||||
a.NextHop = nh
|
||||
buf.ReadByte()
|
||||
parseinfo := InAfiSafi(a.Afi, a.Safi, addpathlist)
|
||||
a.NLRI, _ = ParseNLRI(buf.Bytes(), a.Afi, a.Safi, parseinfo)
|
||||
a.EnableAddPath = parseinfo
|
||||
intf = a
|
||||
case ATTRIBUTE_UNREACH:
|
||||
a := BGPAttribute_MP_UNREACH{}
|
||||
binary.Read(buf, binary.BigEndian, &(a.Afi))
|
||||
binary.Read(buf, binary.BigEndian, &(a.Safi))
|
||||
parseinfo := InAfiSafi(a.Afi, a.Safi, addpathlist)
|
||||
a.NLRI, _ = ParseNLRI(buf.Bytes(), a.Afi, a.Safi, parseinfo)
|
||||
intf = a
|
||||
default:
|
||||
intf = BGPAttribute{
|
||||
attrflag,
|
||||
attrcode,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
attributes = append(attributes, intf)
|
||||
|
||||
i += 3 + length + offset
|
||||
}
|
||||
return attributes, nil
|
||||
}
|
||||
|
||||
func ParseUpdate(b []byte, addpathlist []AfiSafi, enc2bytes bool) (*BGPMessageUpdate, error) {
|
||||
m := &BGPMessageUpdate{}
|
||||
var err error
|
||||
|
||||
addpath_ipv4uni := InAfiSafi(AFI_IPV4, SAFI_UNICAST, addpathlist)
|
||||
m.EnableAddPath = addpath_ipv4uni
|
||||
|
||||
if len(b) < 4 {
|
||||
return nil, errors.New(fmt.Sprintf("ParseUpdate: wrong withdrawn routes size: %v < 4", len(b)))
|
||||
}
|
||||
|
||||
wdrouteslen := int(uint16(b[0])<<8 | uint16(b[1]))
|
||||
|
||||
if wdrouteslen+4 > len(b) {
|
||||
return nil, errors.New(fmt.Sprintf("ParseUpdate: wrong withdrawn routes size: %v > %v", wdrouteslen+4, len(b)))
|
||||
}
|
||||
offset := 2
|
||||
withdrawnroutes := b[offset : offset+wdrouteslen]
|
||||
m.WithdrawnRoutes, err = ParseNLRI(withdrawnroutes, AFI_IPV4, SAFI_UNICAST, addpath_ipv4uni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offset += wdrouteslen
|
||||
|
||||
tplen := int(uint16(b[offset])<<8 | uint16(b[offset+1]))
|
||||
offset += 2
|
||||
|
||||
if tplen+offset > len(b) {
|
||||
return nil, errors.New(fmt.Sprintf("ParseUpdate: wrong total path size: %v > %v", tplen+offset, len(b)))
|
||||
}
|
||||
pathattributes := b[offset : offset+tplen]
|
||||
m.PathAttributes, err = ParsePathAttribute(pathattributes, addpathlist, enc2bytes)
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
offset += tplen
|
||||
NLRI := b[offset:]
|
||||
m.NLRI, err = ParseNLRI(NLRI, AFI_IPV4, SAFI_UNICAST, addpath_ipv4uni)
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func CraftUpdateMessage() *BGPMessageUpdate {
|
||||
//_, prefix, _ := net.ParseCIDR("8.8.8.8/24")
|
||||
|
||||
_, prefixtest, _ := net.ParseCIDR("2001::/46")
|
||||
ip := net.ParseIP("2002::1")
|
||||
pa := []BGPAttributeIf{
|
||||
BGPAttribute_ORIGIN{
|
||||
Origin: 2,
|
||||
},
|
||||
BGPAttribute_ASPATH{
|
||||
Segments: []ASPath_Segment{ASPath_Segment{ASPath: []uint32{65001}}},
|
||||
},
|
||||
BGPAttribute_COMMUNITIES{
|
||||
Communities: []uint32{0x7b0929},
|
||||
},
|
||||
//BGPAttribute_NEXTHOP{
|
||||
// NextHop: []byte{1,2,3,4},
|
||||
//},
|
||||
BGPAttribute_MP_REACH{
|
||||
Afi: AFI_IPV6,
|
||||
Safi: SAFI_UNICAST,
|
||||
NextHop: ip,
|
||||
//enableAddPath: true,
|
||||
NLRI: []NLRI{
|
||||
NLRI_IPPrefix{
|
||||
PathId: uint32(time.Now().UTC().Unix()),
|
||||
Prefix: *prefixtest,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
m := &BGPMessageUpdate{
|
||||
//NLRI: []NLRI{NLRI{Prefix: *prefix,PathId:123,},},
|
||||
PathAttributes: pa,
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
473
messages/messages.go
Normal file
473
messages/messages.go
Normal file
@@ -0,0 +1,473 @@
|
||||
package messages
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
errCodeToStr = map[int]string{
|
||||
1: "Message Header Error",
|
||||
2: "OPEN Message Error",
|
||||
3: "UPDATE Message Error",
|
||||
4: "Hold Timer Expired",
|
||||
5: "Finite State Machine Error",
|
||||
6: "Cease",
|
||||
}
|
||||
errSubCodeToStr = map[int]map[int]string{
|
||||
1: map[int]string{
|
||||
1: "Connection Not Synchronized.",
|
||||
2: "Bad Message Length.",
|
||||
3: "Bad Message Type.",
|
||||
},
|
||||
2: map[int]string{
|
||||
1: "Unsupported Version Number.",
|
||||
2: "Bad Peer AS.",
|
||||
3: "Bad BGP Identifier.",
|
||||
4: "Unsupported Optional Parameter.",
|
||||
6: "Unacceptable Hold Time.",
|
||||
},
|
||||
3: map[int]string{
|
||||
1: "Malformed Attribute List.",
|
||||
2: "Unrecognized Well-known Attribute.",
|
||||
3: "Missing Well-known Attribute.",
|
||||
4: "Attribute Flags Error.",
|
||||
5: "Attribute Length Error.",
|
||||
6: "Invalid ORIGIN Attribute.",
|
||||
8: "Invalid NEXT_HOP Attribute.",
|
||||
9: "Optional Attribute Error.",
|
||||
10: "Invalid Network Field.",
|
||||
11: "Malformed AS_PATH.",
|
||||
},
|
||||
}
|
||||
CapaDescr = map[int]string{
|
||||
1: "Multiprotocol Extensions for BGP-4",
|
||||
2: "Route Refresh Capability for BGP-4",
|
||||
3: "Outbound Route Filtering Capability",
|
||||
4: "Multiple routes to a destination capability",
|
||||
5: "Extended Next Hop Encoding",
|
||||
6: "BGP-Extended Message",
|
||||
7: "BGPsec Capability",
|
||||
8: "Multiple Labels Capability",
|
||||
64: "Graceful Restart Capability",
|
||||
65: "Support for 4-octet AS number capability",
|
||||
66: "Deprecated (2003-03-06)",
|
||||
67: "Support for Dynamic Capability (capability specific)",
|
||||
68: "Multisession BGP Capability",
|
||||
69: "ADD-PATH Capability",
|
||||
70: "Enhanced Route Refresh Capability",
|
||||
71: "Long-Lived Graceful Restart (LLGR) Capability",
|
||||
72: "Unassigned",
|
||||
73: "FQDN Capability",
|
||||
}
|
||||
BgpAttributes = map[int]string{
|
||||
0: "Reserved",
|
||||
ATTRIBUTE_ORIGIN: "ORIGIN",
|
||||
ATTRIBUTE_ASPATH: "AS_PATH",
|
||||
ATTRIBUTE_NEXTHOP: "NEXT_HOP",
|
||||
ATTRIBUTE_MED: "MULTI_EXIT_DISC",
|
||||
ATTRIBUTE_LOCPREF: "LOCAL_PREF",
|
||||
6: "ATOMIC_AGGREGATE",
|
||||
7: "AGGREGATOR",
|
||||
ATTRIBUTE_COMMUNITIES: "COMMUNITY",
|
||||
9: "ORIGINATOR_ID",
|
||||
10: "CLUSTER_LIST",
|
||||
11: "DPA (deprecated)",
|
||||
12: "ADVERTISER (historic) (deprecated)",
|
||||
13: "RCID_PATH / CLUSTER_ID (Historic) (deprecated)",
|
||||
ATTRIBUTE_REACH: "MP_REACH_NLRI",
|
||||
ATTRIBUTE_UNREACH: "MP_UNREACH_NLRI",
|
||||
16: "EXTENDED COMMUNITIES",
|
||||
ATTRIBUTE_AS4PATH: "AS4_PATH",
|
||||
18: "AS4_AGGREGATOR",
|
||||
19: "SAFI Specific Attribute (SSA) (deprecated)",
|
||||
20: "Connector Attribute (deprecated)",
|
||||
21: "AS_PATHLIMIT (deprecated)",
|
||||
22: "PMSI_TUNNEL",
|
||||
23: "Tunnel Encapsulation Attribute",
|
||||
24: "Traffic Engineering",
|
||||
25: "IPv6 Address Specific Extended Community",
|
||||
26: "AIGP",
|
||||
27: "PE Distinguisher Labels",
|
||||
28: "BGP Entropy Label Capability Attribute (deprecated)",
|
||||
29: "BGP-LS Attribute",
|
||||
30: "Deprecated",
|
||||
31: "Deprecated",
|
||||
32: "LARGE_COMMUNITY",
|
||||
33: "BGPsec_Path",
|
||||
34: "BGP Community Container Attribute",
|
||||
40: "BGP Prefix-SID",
|
||||
128: "ATTR_SET",
|
||||
129: "Deprecated",
|
||||
241: "Deprecated",
|
||||
242: "Deprecated",
|
||||
243: "Deprecated",
|
||||
}
|
||||
Afi = map[string]uint16{
|
||||
"ipv4": AFI_IPV4,
|
||||
"ipv6": AFI_IPV6,
|
||||
}
|
||||
AfiToStr = map[uint16]string{
|
||||
AFI_IPV4: "ipv4",
|
||||
AFI_IPV6: "ipv6",
|
||||
}
|
||||
Safi = map[string]byte{
|
||||
"unicast": SAFI_UNICAST,
|
||||
"multicast": SAFI_MULTICAST,
|
||||
}
|
||||
SafiToStr = map[byte]string{
|
||||
SAFI_UNICAST: "unicast",
|
||||
SAFI_MULTICAST: "multicast",
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
MESSAGE_OPEN = 1
|
||||
MESSAGE_UPDATE = 2
|
||||
MESSAGE_NOTIFICATION = 3
|
||||
MESSAGE_KEEPALIVE = 4
|
||||
MESSAGE_ROUTEREFRESH = 5
|
||||
|
||||
CAPA_MP = 1
|
||||
CAPA_ASN = 65
|
||||
CAPA_ADDPATH = 69
|
||||
CAPA_RR = 2
|
||||
|
||||
ATTRIBUTE_ORIGIN = 1
|
||||
ATTRIBUTE_ASPATH = 2
|
||||
ATTRIBUTE_NEXTHOP = 3
|
||||
ATTRIBUTE_MED = 4
|
||||
ATTRIBUTE_LOCPREF = 5
|
||||
ATTRIBUTE_ATOMIC_AGGREGATE = 6
|
||||
ATTRIBUTE_AGGREGATOR = 7
|
||||
ATTRIBUTE_COMMUNITIES = 8
|
||||
ATTRIBUTE_REACH = 14
|
||||
ATTRIBUTE_UNREACH = 15
|
||||
ATTRIBUTE_AS4PATH = 17
|
||||
|
||||
ATTRIBUTE_TRANSITIVE = 0x40
|
||||
ATTRIBUTE_TRANSITIVEOPT = 0xC0
|
||||
ATTRIBUTE_OPTIONAL = 0x80
|
||||
ATTRIBUTE_EXTENDED = 0x16
|
||||
|
||||
PARAMETER_CAPA = 2
|
||||
|
||||
AFI_IPV4 = 1
|
||||
AFI_IPV6 = 2
|
||||
|
||||
SAFI_UNICAST = 1
|
||||
SAFI_MULTICAST = 2
|
||||
)
|
||||
|
||||
type NLRI interface {
|
||||
GetAfi() uint16
|
||||
GetSafi() byte
|
||||
Len(addpath bool) int
|
||||
Write(w io.Writer, addpath bool)
|
||||
Bytes(addpath bool) []byte
|
||||
String() string
|
||||
Equals(nlri NLRI) bool
|
||||
}
|
||||
|
||||
type NLRI_IPPrefix struct {
|
||||
Prefix net.IPNet
|
||||
PathId uint32
|
||||
}
|
||||
|
||||
func (m NLRI_IPPrefix) Equals(mm NLRI) bool {
|
||||
mmc, ok := mm.(NLRI_IPPrefix)
|
||||
if ok && mmc.GetAfi() == m.GetAfi() && mmc.GetSafi() == m.GetSafi() &&
|
||||
mmc.PathId == m.PathId &&
|
||||
mmc.Prefix.IP.Equal(m.Prefix.IP) &&
|
||||
bytes.Equal(mmc.Prefix.Mask, m.Prefix.Mask) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m NLRI_IPPrefix) GetAfi() uint16 {
|
||||
if m.Prefix.IP.To4() != nil {
|
||||
return AFI_IPV4
|
||||
} else if m.Prefix.IP.To16() != nil {
|
||||
return AFI_IPV6
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (n NLRI_IPPrefix) GetSafi() byte {
|
||||
return SAFI_UNICAST
|
||||
}
|
||||
|
||||
func (n NLRI_IPPrefix) String() string {
|
||||
return fmt.Sprintf("PathId: %v / Prefix: %v", n.PathId, n.Prefix.String())
|
||||
}
|
||||
|
||||
func (n NLRI_IPPrefix) Len(addpath bool) int {
|
||||
add := 0
|
||||
if addpath {
|
||||
add = 4
|
||||
}
|
||||
return add + 1 + n.GetSplitLen()
|
||||
}
|
||||
|
||||
func (n NLRI_IPPrefix) GetSplitLen() int {
|
||||
ones, _ := n.Prefix.Mask.Size()
|
||||
add := 0
|
||||
if ones%8 != 0 {
|
||||
add = 1
|
||||
}
|
||||
return ones/8 + add
|
||||
}
|
||||
|
||||
func (n NLRI_IPPrefix) Write(w io.Writer, addpath bool) {
|
||||
if addpath {
|
||||
binary.Write(w, binary.BigEndian, n.PathId)
|
||||
}
|
||||
|
||||
ones, _ := n.Prefix.Mask.Size()
|
||||
binary.Write(w, binary.BigEndian, byte(ones))
|
||||
length := n.GetSplitLen()
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
binary.Write(w, binary.BigEndian, n.Prefix.IP[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (n NLRI_IPPrefix) Bytes(addpath bool) []byte {
|
||||
buf := make([]byte, 0)
|
||||
w := bytes.NewBuffer(buf)
|
||||
|
||||
n.Write(w, addpath)
|
||||
|
||||
return w.Bytes()
|
||||
}
|
||||
|
||||
type AfiSafi struct {
|
||||
Afi uint16
|
||||
Safi byte
|
||||
}
|
||||
|
||||
/*
|
||||
type NLRI struct {
|
||||
Prefix net.IPNet
|
||||
PathId uint32
|
||||
}*/
|
||||
|
||||
type SerializableInterface interface {
|
||||
//Bytes() []byte
|
||||
String() string
|
||||
Write(w io.Writer)
|
||||
Len() int
|
||||
}
|
||||
|
||||
type BGPMessageHead struct {
|
||||
Received time.Time
|
||||
}
|
||||
|
||||
type BGPMessageKeepAlive struct {
|
||||
BGPMessageHead
|
||||
}
|
||||
|
||||
type BGPMessageRouteRefresh struct {
|
||||
BGPMessageHead
|
||||
AfiSafi AfiSafi
|
||||
}
|
||||
|
||||
type BGPMessageNotification struct {
|
||||
BGPMessageHead
|
||||
ErrorCode byte
|
||||
ErrorSubcode byte
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (m AfiSafi) String() string {
|
||||
return fmt.Sprintf("%v-%v (%v) (%v)", AfiToStr[m.Afi], SafiToStr[m.Safi], m.Afi, m.Safi)
|
||||
}
|
||||
|
||||
func (ap AddPath) EqualsAfiSafi(comp AddPath) bool {
|
||||
return ap.Afi == comp.Afi && ap.Safi == comp.Safi
|
||||
}
|
||||
|
||||
func (p AddPath) String() string {
|
||||
return fmt.Sprintf("Afi: %v-%v (%v) (%v) / TxRx: %v", AfiToStr[p.Afi], SafiToStr[p.Safi], p.Afi, p.Safi, p.TxRx)
|
||||
}
|
||||
|
||||
func (m BGPMessageKeepAlive) String() string {
|
||||
str := "BGP KeepAlive\n"
|
||||
return str
|
||||
}
|
||||
|
||||
func (m BGPMessageKeepAlive) Write(bw io.Writer) {
|
||||
WriteBGPHeader(MESSAGE_KEEPALIVE, 0, bw)
|
||||
}
|
||||
|
||||
func (m BGPMessageKeepAlive) Len() int {
|
||||
return GetBGPHeaderLen()
|
||||
}
|
||||
|
||||
func (m BGPMessageKeepAlive) Bytes() []byte {
|
||||
buf := make([]byte, 0)
|
||||
bw := bytes.NewBuffer(buf)
|
||||
|
||||
m.Write(bw)
|
||||
|
||||
return bw.Bytes()
|
||||
}
|
||||
|
||||
func (m BGPMessageRouteRefresh) String() string {
|
||||
str := fmt.Sprintf("BGP Route Refresh %v\n", m.AfiSafi.String())
|
||||
return str
|
||||
}
|
||||
|
||||
func (m BGPMessageRouteRefresh) Len() int {
|
||||
return GetBGPHeaderLen() + 4
|
||||
}
|
||||
|
||||
func (m BGPMessageRouteRefresh) Write(bw io.Writer) {
|
||||
WriteBGPHeader(MESSAGE_ROUTEREFRESH, 4, bw)
|
||||
binary.Write(bw, binary.BigEndian, m.AfiSafi.Afi)
|
||||
binary.Write(bw, binary.BigEndian, byte(0))
|
||||
binary.Write(bw, binary.BigEndian, m.AfiSafi.Safi)
|
||||
}
|
||||
|
||||
/*
|
||||
func (m NLRI) String() string {
|
||||
return fmt.Sprintf("PathId: %v / Prefix: %v", m.PathId, m.Prefix.String())
|
||||
}
|
||||
|
||||
func (n NLRI) Bytes(addpath bool) []byte {
|
||||
buf := make([]byte, 0)
|
||||
bw := bytes.NewBuffer(buf)
|
||||
|
||||
if addpath {
|
||||
binary.Write(bw, binary.BigEndian, n.PathId)
|
||||
}
|
||||
|
||||
ones, _ := n.Prefix.Mask.Size()
|
||||
bw.WriteByte(byte(ones))
|
||||
|
||||
add := 0
|
||||
if ones%8 != 0 {
|
||||
add = 1
|
||||
}
|
||||
length := ones/8 + add
|
||||
|
||||
for i := 0; i<length; i++ {
|
||||
bw.WriteByte(n.Prefix.IP[i])
|
||||
}
|
||||
|
||||
return bw.Bytes()
|
||||
}*/
|
||||
|
||||
func (m *BGPMessageNotification) String() string {
|
||||
str := "BGP Notification: %v (%v): %v (%v): %v"
|
||||
desc := errCodeToStr[int(m.ErrorCode)]
|
||||
sub := errSubCodeToStr[int(m.ErrorCode)]
|
||||
var descsub string
|
||||
if sub != nil {
|
||||
descsub = errSubCodeToStr[int(m.ErrorCode)][int(m.ErrorSubcode)]
|
||||
}
|
||||
return fmt.Sprintf(str, desc, m.ErrorCode, descsub, m.ErrorSubcode, m.Data)
|
||||
}
|
||||
|
||||
func (m BGPMessageNotification) Len() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m BGPMessageNotification) Write(bw io.Writer) {
|
||||
|
||||
}
|
||||
|
||||
func InAfiSafi(afi uint16, safi byte, list []AfiSafi) bool {
|
||||
for i := range list {
|
||||
if list[i].Afi == afi && list[i].Safi == safi {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ParsePacketHeader(b []byte) (byte, uint16, error) {
|
||||
if len(b) >= 19 {
|
||||
length := uint16(b[16])<<8 | uint16(b[17])
|
||||
if length < 19 || length > 4096 {
|
||||
return 0, 0, errors.New(fmt.Sprintf("BGP Packet parser: wrong length: 19: !<= %v !<= 4096", length))
|
||||
}
|
||||
if length < 19 {
|
||||
return 0, 0, errors.New(fmt.Sprintf("BGP Packet parser: wrong length: 19: !<= %v", length))
|
||||
}
|
||||
|
||||
length -= 19
|
||||
bgptype := b[18]
|
||||
//log.Debugf("ParsePacketHeader: len: %v type: %v", length, bgptype)
|
||||
return bgptype, length, nil
|
||||
} else {
|
||||
return 0, 0, errors.New(fmt.Sprintf("BGP Packet parser: wrong header size: %v < 19", len(b)))
|
||||
}
|
||||
}
|
||||
|
||||
func ParseKeepAlive() (*BGPMessageKeepAlive, error) {
|
||||
return &BGPMessageKeepAlive{}, nil
|
||||
}
|
||||
|
||||
func ParseNotification(b []byte) (*BGPMessageNotification, error) {
|
||||
if len(b) < 2 {
|
||||
return nil, errors.New(fmt.Sprintf("ParseNotification: wrong open size: %v < 2", len(b)))
|
||||
}
|
||||
|
||||
errCode := b[0]
|
||||
errSubcode := b[1]
|
||||
errData := make([]byte, 0)
|
||||
if len(b) >= 2 {
|
||||
errData = b[2:]
|
||||
}
|
||||
|
||||
r := &BGPMessageNotification{
|
||||
BGPMessageHead{time.Now()},
|
||||
errCode,
|
||||
errSubcode,
|
||||
errData,
|
||||
}
|
||||
|
||||
log.Errorf("ParseNotification: %v", r.String())
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func ParsePacket(bgptype byte, b []byte) (SerializableInterface, error) {
|
||||
switch bgptype {
|
||||
case MESSAGE_OPEN:
|
||||
openmsg, err := ParseOpen(b)
|
||||
return openmsg, err
|
||||
case MESSAGE_UPDATE:
|
||||
return ParseUpdate(b, nil, false)
|
||||
case MESSAGE_NOTIFICATION:
|
||||
return ParseNotification(b)
|
||||
case MESSAGE_KEEPALIVE:
|
||||
return ParseKeepAlive()
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("Unknown packet type: %v", bgptype))
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func CraftKeepAliveMessage() *BGPMessageKeepAlive {
|
||||
return &BGPMessageKeepAlive{}
|
||||
}
|
||||
|
||||
func GetBGPHeaderLen() int {
|
||||
return 19
|
||||
}
|
||||
|
||||
func WriteBGPHeader(bgptype byte, size uint16, bw io.Writer) {
|
||||
bw.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
|
||||
binary.Write(bw, binary.BigEndian, uint16(19+size))
|
||||
binary.Write(bw, binary.BigEndian, bgptype)
|
||||
}
|
||||
Reference in New Issue
Block a user