go-bgp

a collection of golang BGP tools to monitor, archive and serve
git clone git://git.2f30.org/go-bgp
Log | Files | Refs | README

mrt.go (11322B)


      1 package mrt
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/binary"
      6 	"errors"
      7 	"fmt"
      8 	"io"
      9 	"log"
     10 	"net"
     11 	"os"
     12 	"unicode/utf8"
     13 	//"runtime"
     14 )
     15 
     16 var logger = log.New(os.Stderr, "go-mrt: ", log.Ldate|log.Llongfile)
     17 
     18 type MrtHdr struct {
     19 	Mrt_timestamp uint32
     20 	Mrt_type      uint16
     21 	Mrt_subtype   uint16
     22 	Mrt_len       uint32
     23 }
     24 
     25 type parsefunc func([]byte) MrtSubTyper
     26 
     27 type MrtMsg struct {
     28 	Hdr	MrtHdr
     29 	Msg	[]byte
     30 }
     31 
     32 type MrtSubTyper interface {
     33 	Type() string //almost dummy functionality
     34 	String() string
     35 }
     36 
     37 type Mrter interface {
     38 	Hdr()	MrtHdr
     39 	Type()	uint16
     40 	SubType() uint16
     41 	Len()	uint32
     42 	Msg()	[]byte
     43 }
     44 
     45 type MrtOSPFHdr struct {
     46 	otype    uint16
     47 	RemoteIP uint32
     48 	LocalIP  uint32
     49 }
     50 
     51 func (m *MrtOSPFHdr) Type() string {
     52 	return "OSPFHdr"
     53 }
     54 
     55 func (m *MrtOSPFHdr) String() string {
     56 	remip := make(net.IP, 4)
     57 	locip := make(net.IP, 4)
     58 	remip[0] = byte(m.RemoteIP)
     59 	remip[1] = byte(m.RemoteIP >> 8)
     60 	remip[2] = byte(m.RemoteIP >> 16)
     61 	remip[3] = byte(m.RemoteIP >> 24)
     62 	locip[0] = byte(m.LocalIP)
     63 	locip[1] = byte(m.LocalIP >> 8)
     64 	locip[2] = byte(m.LocalIP >> 16)
     65 	locip[3] = byte(m.LocalIP >> 24)
     66 	return fmt.Sprintf("OSPF Header. Type [%d] Remote IP [%s] Local IP [%s]", m.otype, remip, locip)
     67 }
     68 
     69 type MrtInfoMsg struct {
     70 	inftype uint16
     71 	optmsg  string
     72 }
     73 
     74 func (m *MrtInfoMsg) String() string {
     75 	return fmt.Sprintf("Informational Message. Type [%v] Optstring [%s]", m.inftype, m.optmsg)
     76 }
     77 
     78 func (m *MrtInfoMsg) Type() string {
     79 	return m.String()
     80 }
     81 
     82 func (m *MrtMsg) PFunc() (ret parsefunc, ok bool) {
     83 	var subtype = m.Hdr.Mrt_subtype
     84 	var mtype = m.Hdr.Mrt_type
     85 	infofunc := func(a []byte) MrtSubTyper {
     86 		runes := []rune{}
     87 		infomsg := &MrtInfoMsg{inftype: mtype, optmsg: "No Optional Message"}
     88 		for len(a) > 0 {
     89 			r, sz := utf8.DecodeRune(a)
     90 			if r == utf8.RuneError {
     91 				logger.Println("failed to decode rune in optional message")
     92 				return infomsg
     93 			}
     94 			a = a[sz:]
     95 			runes = append(runes, r)
     96 		}
     97 		if len(runes) > 0 {
     98 			infomsg.optmsg = string(runes)
     99 		}
    100 		return infomsg
    101 	}
    102 
    103 	ospffunc := func(a []byte) MrtSubTyper {
    104 		ret := &MrtOSPFHdr{otype: subtype}
    105 		buf := bytes.NewReader(a)
    106 		err := binary.Read(buf, binary.BigEndian, &ret.RemoteIP)
    107 		err = binary.Read(buf, binary.BigEndian, &ret.LocalIP)
    108 		if err != nil {
    109 			panic(fmt.Sprintf("error while reading binary OSPF header: %s", err))
    110 		}
    111 		return ret
    112 	}
    113 
    114 	bgp4mpscfunc := func(a []byte) MrtSubTyper {
    115 		ret := &MrtBGP4MPStateChangeHdr{}
    116 		buf := bytes.NewReader(a)
    117 		if subtype == BGP4MP_STATE_CHANGE {
    118 			ret.PeerASN = make([]byte, 2)
    119 			ret.LocalASN = make([]byte, 2)
    120 		} else {
    121 			ret.PeerASN = make([]byte, 4)
    122 			ret.LocalASN = make([]byte, 4)
    123 		}
    124 		err := binary.Read(buf, binary.BigEndian, &ret.PeerASN)
    125 		if err != nil {
    126 			panic(fmt.Sprintf("error while reading binary BGP4MP header: %s", err))
    127 		}
    128 		binary.Read(buf, binary.BigEndian, &ret.LocalASN)
    129 		binary.Read(buf, binary.BigEndian, &ret.InterfaceInd)
    130 		binary.Read(buf, binary.BigEndian, &ret.AddrFamily)
    131 		if ret.AddrFamily == 1 {
    132 			ret.PeerIP = make([]byte, 4)
    133 			ret.LocalIP = make([]byte, 4)
    134 		} else if ret.AddrFamily == 2 {
    135 			ret.PeerIP = make([]byte, 16)
    136 			ret.LocalIP = make([]byte, 16)
    137 		}
    138 		binary.Read(buf, binary.BigEndian, &ret.PeerIP)
    139 		binary.Read(buf, binary.BigEndian, &ret.LocalIP)
    140 		binary.Read(buf, binary.BigEndian, &ret.OldState)
    141 		binary.Read(buf, binary.BigEndian, &ret.NewState)
    142 		return ret
    143 	}
    144 
    145 	bgp4mpmsgfunc := func(a []byte) MrtSubTyper {
    146 		ret := &MrtBGP4MPMsgHdr{}
    147 		buf := bytes.NewReader(a)
    148 		if subtype == BGP4MP_MESSAGE {
    149 			ret.PeerASN = make([]byte, 2)
    150 			ret.LocalASN = make([]byte, 2)
    151 		} else if subtype == BGP4MP_MESSAGE_AS4 {
    152 			ret.PeerASN = make([]byte, 4)
    153 			ret.LocalASN = make([]byte, 4)
    154 		}
    155 		err := binary.Read(buf, binary.BigEndian, &ret.PeerASN)
    156 		if err != nil {
    157 			panic(fmt.Sprintf("error while reading binary BGP4MP header: %s", err))
    158 		}
    159 		binary.Read(buf, binary.BigEndian, &ret.LocalASN)
    160 		binary.Read(buf, binary.BigEndian, &ret.InterfaceInd)
    161 		//fmt.Printf("ADdr family should be:%v\n", binary.BigEndian.Uint16(a[6:8]))
    162 		binary.Read(buf, binary.BigEndian, &ret.AddrFamily)
    163 		if ret.AddrFamily == 1 {
    164 			ret.PeerIP = make([]byte, 4)
    165 			ret.LocalIP = make([]byte, 4)
    166 		} else if ret.AddrFamily == 2 {
    167 			ret.PeerIP = make([]byte, 16)
    168 			ret.LocalIP = make([]byte, 16)
    169 		} else {
    170 			panic("Address Family in BGP4MP msg func is wrong")
    171 		}
    172 		binary.Read(buf, binary.BigEndian, &ret.PeerIP)
    173 		binary.Read(buf, binary.BigEndian, &ret.LocalIP)
    174 		return ret
    175 	}
    176 
    177 	ret = nil
    178 	ok = false
    179 	switch mtype {
    180 	case MSG_PROTOCOL_BGP4MP:
    181 		if subtype == BGP4MP_STATE_CHANGE || subtype == BGP4MP_STATE_CHANGE_AS4 {
    182 			ret, ok = bgp4mpscfunc, true
    183 		} else if subtype == BGP4MP_MESSAGE || subtype == BGP4MP_MESSAGE_AS4 ||
    184 			subtype == BGP4MP_MESSAGE_LOCAL || subtype == BGP4MP_MESSAGE_AS4_LOCAL {
    185 			ret, ok = bgp4mpmsgfunc, true
    186 		}
    187 	case MSG_START, MSG_I_AM_DEAD:
    188 		if subtype == 0 {
    189 			ret, ok = infofunc, true
    190 		} else {
    191 			logger.Println("Mrt type is Informational but Subtype non-zero")
    192 		}
    193 	case MSG_PROTOCOL_OSPF:
    194 		if subtype == 0 || subtype == 1 {
    195 			ret, ok = ospffunc, true
    196 		} else {
    197 			logger.Println("Mrt type is OSPF but Subtype is neither 0 or 1")
    198 		}
    199 	case MSG_NULL, MSG_DIE, MSG_PEER_DOWN, MSG_PROTOCOL_BGP, MSG_PROTOCOL_IDRP, MSG_PROTOCOL_BGP4PLUS, MSG_PROTOCOL_BGP4PLUS1:
    200 		logger.Println("Deprecated message type")
    201 	default:
    202 		logger.Printf("unknown. header [%v]\n", m.Hdr)
    203 	}
    204 	return
    205 }
    206 
    207 type MrtBGP4MPStateChangeHdr struct {
    208 	PeerASN      []byte
    209 	LocalASN     []byte
    210 	InterfaceInd uint16
    211 	AddrFamily   uint16
    212 	PeerIP       []byte
    213 	LocalIP      []byte
    214 	OldState     uint16
    215 	NewState     uint16
    216 }
    217 
    218 func (m *MrtBGP4MPStateChangeHdr) Type() string {
    219 	return "BGP4MPStateChange"
    220 }
    221 
    222 func (m *MrtBGP4MPStateChangeHdr) String() string {
    223 	return "BGP4MPStateChange"
    224 }
    225 
    226 type MrtBGP4MPMsgHdr struct {
    227 	PeerASN      []byte
    228 	LocalASN     []byte
    229 	InterfaceInd uint16
    230 	AddrFamily   uint16
    231 	PeerIP       []byte
    232 	LocalIP      []byte
    233 }
    234 
    235 func (m *MrtBGP4MPMsgHdr) Type() string {
    236 	return "BGP4MPMsg"
    237 }
    238 
    239 func (m *MrtBGP4MPMsgHdr) String() string {
    240 	if len(m.PeerIP) < 4 || len(m.LocalIP) < 4 {
    241 		return "BGP4MPMsg unable to read IPs"
    242 	}
    243 	return fmt.Sprintf("LocalIP:%s RemoteIP:%s", net.IPv4(m.PeerIP[0], m.PeerIP[1], m.PeerIP[2], m.PeerIP[3]), net.IPv4(m.LocalIP[0], m.LocalIP[1], m.LocalIP[2], m.LocalIP[3]))
    244 }
    245 
    246 type MrtTableDumpV1Hdr struct {
    247 	ViewNum   uint16
    248 	SeqNum    uint16
    249 	Prefix    []byte
    250 	PrefixLen uint8
    251 	Status    uint8
    252 	OrigTime  uint32
    253 	PeerIP    []byte
    254 	PeerAS    uint16
    255 	AttrLen   uint16
    256 }
    257 
    258 func (m *MrtTableDumpV1Hdr) Type() string {
    259 	return "TableDumpV1Hdr"
    260 }
    261 
    262 func (m *MrtTableDumpV1Hdr) String() string {
    263 	return "TableDumpV1Hdr"
    264 }
    265 
    266 type MrtTableDumpV2PIHdr struct {
    267 	CollectorID	uint32
    268 	ViewNameLen	[]byte
    269 	PeerCount	uint16
    270 	Peers		[]MrtTableDumpV2PeerEntry
    271 }
    272 
    273 type MrtTableDumpV2PeerEntry struct {
    274 	PeerType	uint8
    275 	PeerBGPID	uint32
    276 	PeerIP		[]byte
    277 	PeerAS		[]byte
    278 }
    279 
    280 type MrtTableDumpV2RIBDef struct {
    281 	SequenceNum	uint32
    282 	PrefixLen	uint8
    283 	Prefix		uint32
    284 	EntryCount	uint16
    285 	Entries		[]MrtTableDumpV2RIBEntry
    286 }
    287 
    288 type MrtTableDumpV2RIBGen struct {
    289 	SequenceNum	uint32
    290 	AFI		uint16
    291 	SAFI		uint8
    292 	NLRI		[]byte
    293 	EntryCount	uint16
    294 	Entries		[]MrtTableDumpV2RIBEntry
    295 }
    296 
    297 type MrtTableDumpV2RIBEntry struct {
    298 	PeerIndex	uint16
    299 	OrigTime	uint32
    300 	AttrLen		uint16
    301 	BGPAttrs	[]byte
    302 }
    303 
    304 type MrtFile struct {
    305 	file    io.Reader
    306 	entries uint32
    307 	off     int64
    308 }
    309 
    310 const (
    311 	MrtHdr_size = 12
    312 	dump_size   = 10000
    313 )
    314 
    315 // mrt-type consts
    316 const (
    317 	MSG_NULL               = iota //  0 empty msg (deprecated)
    318 	MSG_START                     //  1 sender is starting up
    319 	MSG_DIE                       //  2 receiver should shut down (deprecated)
    320 	MSG_I_AM_DEAD                 //  3 sender is shutting down
    321 	MSG_PEER_DOWN                 //  4 sender's peer is down (deprecated)
    322 	MSG_PROTOCOL_BGP              //  5 msg is a BGP packet (deprecated)
    323 	MSG_PROTOCOL_RIP              //  6 msg is a RIP packet
    324 	MSG_PROTOCOL_IDRP             //  7 msg is an IDRP packet (deprecated)
    325 	MSG_PROTOCOL_RIPNG            //  8 msg is a RIPNG packet
    326 	MSG_PROTOCOL_BGP4PLUS         //  9 msg is a BGP4+ packet (deprecated)
    327 	MSG_PROTOCOL_BGP4PLUS1        // 10 msg is a BGP4+ (draft 01) (deprecated)
    328 	MSG_PROTOCOL_OSPF             // 11 msg is an OSPF packet
    329 	MSG_TABLE_DUMP                // 12 routing table dump
    330 	MSG_TABLE_DUMP_V2             // 13 routing table dump
    331 	MSG_PROTOCOL_BGP4MP    = 16   // 16 zebras own packet format
    332 	MSG_PROTOCOL_BGP4MP_ET = 17
    333 	MSG_PROTOCOL_ISIS      = 32 // 32 msg is a ISIS package
    334 	MSG_PROTOCOL_ISIS_ET   = 33
    335 	MSG_PROTOCOL_OSPFV3    = 48 // 48 msg is a OSPFv3 package
    336 	MSG_PROTOCOL_OSPFV3_ET = 49
    337 )
    338 
    339 // mrt-subtype consts
    340 const (
    341 	BGP4MP_STATE_CHANGE      = 0 // state change
    342 	BGP4MP_MESSAGE           = 1 // bgp message
    343 	BGP4MP_MESSAGE_AS4       = 4 // same as BGP4MP_MESSAGE with 4byte AS
    344 	BGP4MP_STATE_CHANGE_AS4  = 5
    345 	BGP4MP_MESSAGE_LOCAL     = 6 // same as BGP4MP_MESSAGE but for self
    346 	BGP4MP_MESSAGE_AS4_LOCAL = 7 // originated updates. Not implemented
    347 )
    348 
    349 const (
    350 	OSPF_STATE_CHANGE = iota
    351 	OSPF_LSA_UPDATE
    352 )
    353 
    354 const (
    355 	PEER_INDEX_TABLE = iota + 1
    356 	RIB_IPV4_UNICAST
    357 	RIB_IPV4_MULTICAST
    358 	RIB_IPV6_UNICAST
    359 	RIB_IPV6_MULTICAST
    360 	RIB_GENERIC
    361 )
    362 
    363 func NewMrtHdr(b []byte) (ret MrtHdr, err error) {
    364 	buf := bytes.NewReader(b)
    365 	err = binary.Read(buf, binary.BigEndian, &ret)
    366 	return
    367 }
    368 
    369 func NewMrtFile(f io.Reader) (ret MrtFile) {
    370 	ret = MrtFile{f, 0, 0}
    371 	return
    372 }
    373 
    374 //This function can be passed into a bufio.Scanner.Split() to read buffered
    375 //mrt msgs
    376 func SplitMrt(data []byte, atEOF bool) (advance int, token []byte, err error) {
    377 	if atEOF && len(data) == 0 {
    378 		return 0, nil, nil
    379 	}
    380 	if cap(data) < MrtHdr_size { // read more
    381 		return 0, nil, nil
    382 	}
    383 	//this reads the data and (they are big endian so it handles that)
    384 	hdr, errh := NewMrtHdr(data[:MrtHdr_size])
    385 	if errh != nil {
    386 		return 0, nil, errh
    387 	}
    388 	totlen := int(hdr.Mrt_len + MrtHdr_size)
    389 	if len(data) < totlen { //need to read more
    390 		return 0, nil, nil
    391 	}
    392 	//logger.Printf("scanned mrt with len:%d datalen is :%d", totlen, len(data))
    393 	return totlen, data[0:totlen], nil
    394 }
    395 
    396 func (f *MrtFile) Read(b []byte) (n int, err error) {
    397 	//fmt.Printf(" b len:%v cap:%v\n",len(b), cap(b))
    398 	if cap(b) < MrtHdr_size {
    399 		err = errors.New("buffer size less than header size")
    400 		return
    401 	}
    402 	n, err = f.file.Read(b[:MrtHdr_size])
    403 	if err != nil {
    404 		return
    405 	}
    406 	hdr, errh := NewMrtHdr(b[:MrtHdr_size])
    407 	if errh != nil {
    408 		err = errors.New(fmt.Sprintf("error in reading header from offset %v : %s", f.off, errh))
    409 		return
    410 	}
    411 	//fmt.Printf("got header at offset:%d ! :%v\n", f.off, hdr)
    412 	//n = int(hdr.Mrt_len+MrtHdr_size)
    413 	//f.off = f.off + int64(n)
    414 	f.entries = f.entries + 1
    415 	//this will just jump over the msg
    416 	//noff,errs := f.file.Seek(int64(hdr.Mrt_len), os.SEEK_CUR)
    417 	if dump_size-(hdr.Mrt_len+MrtHdr_size) <= 0 {
    418 		err = errors.New(fmt.Sprintf("bgp message of size:%v at offset is too large", hdr.Mrt_len, f.off+MrtHdr_size))
    419 		return
    420 	}
    421 	//fmt.Printf("i will access b[%v:%v] len:%v cap:%v\n",MrtHdr_size, hdr.Mrt_len+MrtHdr_size, len(b), cap(b))
    422 	nr, err := f.file.Read(b[MrtHdr_size : hdr.Mrt_len+MrtHdr_size])
    423 	if nr != int(hdr.Mrt_len) {
    424 		n = n + nr //header + len of read
    425 		err = errors.New(fmt.Sprintf("error in reading bgp message of size :%v . got :%v bytes.", hdr.Mrt_len, n))
    426 		return
    427 	}
    428 	n = n + nr
    429 	f.off += int64(n)
    430 	//fmt.Printf("seeked at offset:%d \n", f.off)
    431 	return
    432 }