├── LICENSE ├── README.md ├── bgp.go └── mrt.go /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Satoshi Matsumoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-mrt 2 | 3 | Go library for parsing MRT format data 4 | -------------------------------------------------------------------------------- /bgp.go: -------------------------------------------------------------------------------- 1 | package mrt 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "io" 8 | "net" 9 | "time" 10 | ) 11 | 12 | type BGPPathAttributeOrigin uint8 13 | 14 | const ( 15 | BGPPathAttributeOriginIGP BGPPathAttributeOrigin = iota 16 | BGPPathAttributeOriginEGP 17 | BGPPathAttributeOriginIncomplete 18 | ) 19 | 20 | type BGPPathAttributeASPath []*BGPASPathSegment 21 | 22 | type BGPASPathSegment struct { 23 | Type BGPASPathSegmentType 24 | Value []AS 25 | } 26 | 27 | type BGPASPathSegmentType uint8 28 | 29 | const ( 30 | BGPASPathSegmentTypeASSet BGPASPathSegmentType = iota + 1 31 | BGPASPathSegmentTypeASSequence 32 | ) 33 | 34 | func decodeASPathAttr(data []byte, as4 bool) (BGPPathAttributeASPath, error) { 35 | d := &decoder{data} 36 | 37 | var attr BGPPathAttributeASPath 38 | 39 | for d.size() != 0 { 40 | segment := &BGPASPathSegment{} 41 | segment.Type = BGPASPathSegmentType(d.uint8()) 42 | 43 | n := int(d.uint8()) 44 | segment.Value = make([]AS, n) 45 | for i := 0; i < n; i++ { 46 | if as4 { 47 | segment.Value[i] = d.as4() 48 | } else { 49 | segment.Value[i] = d.as2() 50 | } 51 | } 52 | 53 | attr = append(attr, segment) 54 | } 55 | 56 | return attr, nil 57 | } 58 | 59 | type BGPPathAttributeAggregator struct { 60 | AS AS 61 | IPAddress net.IP 62 | } 63 | 64 | func decodeAggregatorAttr(data []byte, as4 bool) (*BGPPathAttributeAggregator, error) { 65 | d := &decoder{data} 66 | attr := &BGPPathAttributeAggregator{} 67 | if as4 { 68 | attr.AS = d.as4() 69 | } else { 70 | attr.AS = d.as2() 71 | } 72 | attr.IPAddress = d.ipv4() 73 | return attr, nil 74 | } 75 | 76 | type BGPPathAttributeCommunities []BGPCommunity 77 | 78 | type BGPCommunity uint32 79 | 80 | func decodeCommunitiesAttr(data []byte) (BGPPathAttributeCommunities, error) { 81 | d := &decoder{data} 82 | n := d.size() / 4 83 | attr := make(BGPPathAttributeCommunities, n) 84 | for i := 0; i < n; i++ { 85 | attr[i] = BGPCommunity(d.uint32()) 86 | } 87 | return attr, nil 88 | } 89 | 90 | type BGPPathAttributeClusterList []BGPClusterID 91 | 92 | type BGPClusterID net.IP 93 | 94 | func decodeClusterListAttr(data []byte) (BGPPathAttributeClusterList, error) { 95 | d := &decoder{data} 96 | n := d.size() / net.IPv4len 97 | attr := make(BGPPathAttributeClusterList, n) 98 | for i := 0; i < n; i++ { 99 | attr[i] = BGPClusterID(d.ipv4()) 100 | } 101 | return attr, nil 102 | } 103 | 104 | type BGPPathAttributeMPReachNLRI struct { 105 | AFI AFI 106 | SAFI SAFI 107 | NextHop net.IP 108 | NLRI []*net.IPNet 109 | } 110 | 111 | func decodeMPReachNLRIAttr(data []byte) (*BGPPathAttributeMPReachNLRI, error) { 112 | d := &decoder{data} 113 | 114 | attr := &BGPPathAttributeMPReachNLRI{} 115 | attr.AFI = AFI(d.uint16()) 116 | attr.SAFI = SAFI(d.uint8()) 117 | 118 | n := int(d.uint8()) 119 | if attr.AFI == AFIIPv4 { 120 | attr.NextHop = d.ipv4N(n) 121 | d.skip(1) // Reserved (1 octet) 122 | for d.size() != 0 { 123 | attr.NLRI = append(attr.NLRI, d.nlriIPv4()) 124 | } 125 | } else if attr.AFI == AFIIPv6 { 126 | attr.NextHop = d.ipv6N(n) 127 | d.skip(1) // Reserved (1 octet) 128 | for d.size() != 0 { 129 | attr.NLRI = append(attr.NLRI, d.nlriIPv6()) 130 | } 131 | } else { 132 | return nil, fmt.Errorf("unknown AFI: %d", attr.AFI) 133 | } 134 | 135 | return attr, nil 136 | } 137 | 138 | type BGPPathAttributeMPUnreachNLRI struct { 139 | AFI AFI 140 | SAFI SAFI 141 | WithdrawnRoutes []*net.IPNet 142 | } 143 | 144 | func decodeMPUnreachNLRIAttr(data []byte) (*BGPPathAttributeMPUnreachNLRI, error) { 145 | d := &decoder{data} 146 | 147 | attr := &BGPPathAttributeMPUnreachNLRI{} 148 | attr.AFI = AFI(d.uint16()) 149 | attr.SAFI = SAFI(d.uint8()) 150 | 151 | for d.size() != 0 { 152 | if attr.AFI == AFIIPv4 { 153 | attr.WithdrawnRoutes = append(attr.WithdrawnRoutes, d.nlriIPv4()) 154 | } else if attr.AFI == AFIIPv6 { 155 | attr.WithdrawnRoutes = append(attr.WithdrawnRoutes, d.nlriIPv6()) 156 | } else { 157 | return nil, fmt.Errorf("unknown AFI: %d", attr.AFI) 158 | } 159 | } 160 | 161 | return attr, nil 162 | } 163 | 164 | type BGPPathAttributeExtendedCommunities []BGPExtendedCommunity 165 | 166 | type BGPExtendedCommunity [8]byte 167 | 168 | func decodeExtendedCommunitiesAttr(data []byte) (BGPPathAttributeExtendedCommunities, error) { 169 | d := &decoder{data} 170 | n := d.size() / 8 171 | attr := make(BGPPathAttributeExtendedCommunities, n) 172 | for i := 0; i < n; i++ { 173 | d.copy(attr[i][:]) 174 | } 175 | return attr, nil 176 | } 177 | 178 | type BGPPathAttributeLargeCommunities []BGPLargeCommunity 179 | 180 | type BGPLargeCommunity [12]byte 181 | 182 | func decodeLargeCommunitiesAttr(data []byte) (BGPPathAttributeLargeCommunities, error) { 183 | d := &decoder{data} 184 | n := d.size() / 12 185 | attr := make(BGPPathAttributeLargeCommunities, n) 186 | for i := 0; i < n; i++ { 187 | d.copy(attr[i][:]) 188 | } 189 | return attr, nil 190 | } 191 | 192 | type BGPPathAttribute struct { 193 | Flag uint8 194 | TypeCode uint8 195 | Value interface{} 196 | } 197 | 198 | type bgpPathAttributeReader struct { 199 | reader io.Reader 200 | as4 bool 201 | } 202 | 203 | func (r *bgpPathAttributeReader) Next() (*BGPPathAttribute, error) { 204 | attrTypeBytes := make([]byte, 2) 205 | if _, err := io.ReadFull(r.reader, attrTypeBytes); err != nil { 206 | return nil, err 207 | } 208 | 209 | attr := &BGPPathAttribute{} 210 | attr.Flag = attrTypeBytes[0] 211 | attr.TypeCode = attrTypeBytes[1] 212 | 213 | attrLenSize := 1 214 | if attr.Flag&0x10 != 0 { 215 | attrLenSize = 2 216 | } 217 | 218 | attrLenBytes := make([]byte, attrLenSize) 219 | if _, err := io.ReadFull(r.reader, attrLenBytes); err != nil { 220 | return nil, err 221 | } 222 | 223 | attrLen := int(attrLenBytes[0]) 224 | if attrLenSize == 2 { 225 | attrLen = int(binary.BigEndian.Uint16(attrLenBytes)) 226 | } 227 | 228 | valueBytes := make([]byte, attrLen) 229 | if _, err := io.ReadFull(r.reader, valueBytes); err != nil { 230 | return nil, err 231 | } 232 | 233 | var err error 234 | switch attr.TypeCode { 235 | case 1: 236 | attr.Value = BGPPathAttributeOrigin(valueBytes[0]) 237 | case 2: 238 | attr.Value, err = decodeASPathAttr(valueBytes, r.as4) 239 | case 3: 240 | attr.Value = net.IP(valueBytes) 241 | case 4: 242 | attr.Value = binary.BigEndian.Uint32(valueBytes) 243 | case 5: 244 | attr.Value = binary.BigEndian.Uint32(valueBytes) 245 | case 6: 246 | // zero-length attribute 247 | case 7: 248 | attr.Value, err = decodeAggregatorAttr(valueBytes, r.as4) 249 | case 8: 250 | attr.Value, err = decodeCommunitiesAttr(valueBytes) 251 | case 9: 252 | attr.Value = net.IP(valueBytes) 253 | case 10: 254 | attr.Value, err = decodeClusterListAttr(valueBytes) 255 | case 14: 256 | attr.Value, err = decodeMPReachNLRIAttr(valueBytes) 257 | case 15: 258 | attr.Value, err = decodeMPUnreachNLRIAttr(valueBytes) 259 | case 16: 260 | attr.Value, err = decodeExtendedCommunitiesAttr(valueBytes) 261 | case 17: 262 | attr.Value, err = decodeASPathAttr(valueBytes, true) 263 | case 18: 264 | attr.Value, err = decodeAggregatorAttr(valueBytes, true) 265 | case 32: 266 | attr.Value, err = decodeLargeCommunitiesAttr(valueBytes) 267 | default: 268 | return nil, fmt.Errorf("unknown BGP path attribute type code: %d", attr.TypeCode) 269 | } 270 | 271 | return attr, err 272 | } 273 | 274 | func decodeBGPMessage(data []byte, as4 bool, afi AFI) (*BGPMessage, error) { 275 | msgType := BGPMessageType(data[18]) 276 | 277 | var msg BGPMessage 278 | var err error 279 | switch msgType { 280 | case BGPMessageTypeOpen: 281 | msg, err = decodeOpenMessage(data) 282 | case BGPMessageTypeUpdate: 283 | msg, err = decodeUpdateMessage(data, as4, afi) 284 | case BGPMessageTypeNotification: 285 | msg, err = decodeNotificationMessage(data) 286 | case BGPMessageTypeKeepalive: 287 | msg, err = decodeKeepaliveMessage(data) 288 | default: 289 | return nil, fmt.Errorf("unknown BGP message type: %d", msgType) 290 | } 291 | 292 | return &msg, err 293 | } 294 | 295 | type BGPMessageType uint8 296 | 297 | const ( 298 | BGPMessageTypeOpen BGPMessageType = iota + 1 299 | BGPMessageTypeUpdate 300 | BGPMessageTypeNotification 301 | BGPMessageTypeKeepalive 302 | ) 303 | 304 | type BGPMessage interface { 305 | Type() BGPMessageType 306 | } 307 | 308 | type bgpMessageHeader struct { 309 | type_ BGPMessageType 310 | } 311 | 312 | func (h *bgpMessageHeader) Type() BGPMessageType { 313 | return h.type_ 314 | } 315 | 316 | func (h *bgpMessageHeader) decodeHeader(d *decoder) error { 317 | d.skip(16) // Marker (16 octets) 318 | d.skip(2) // Length (2 octets) 319 | h.type_ = BGPMessageType(d.uint8()) 320 | return nil 321 | } 322 | 323 | type BGPOpenMessage struct { 324 | bgpMessageHeader 325 | Version uint8 326 | MyAS AS 327 | HoldTime time.Duration 328 | BGPIdentifier net.IP 329 | OptionalParameters []*OptionalParameter 330 | } 331 | 332 | type OptionalParameter struct { 333 | Type uint8 334 | Value []byte 335 | } 336 | 337 | func decodeOpenMessage(data []byte) (*BGPOpenMessage, error) { 338 | d := &decoder{data} 339 | msg := &BGPOpenMessage{} 340 | msg.decodeHeader(d) 341 | msg.Version = d.uint8() 342 | msg.MyAS = d.as2() 343 | msg.HoldTime = time.Duration(d.uint16()) * time.Second 344 | msg.BGPIdentifier = d.ipv4() 345 | d.skip(1) // Optional Parameters Length (1 octet) 346 | for d.size() != 0 { 347 | p := &OptionalParameter{} 348 | p.Type = d.uint8() 349 | p.Value = d.bytes(int(d.uint8())) 350 | msg.OptionalParameters = append(msg.OptionalParameters, p) 351 | } 352 | return msg, nil 353 | } 354 | 355 | type BGPUpdateMessage struct { 356 | bgpMessageHeader 357 | WithdrawnRoutes []*net.IPNet 358 | PathAttributes []*BGPPathAttribute 359 | NLRI []*net.IPNet 360 | } 361 | 362 | func decodeUpdateMessage(data []byte, as4 bool, afi AFI) (*BGPUpdateMessage, error) { 363 | d := &decoder{data} 364 | 365 | msg := &BGPUpdateMessage{} 366 | msg.decodeHeader(d) 367 | 368 | routesLen := int(d.uint16()) 369 | restLen := d.size() - routesLen 370 | for d.size() != restLen { 371 | if afi == AFIIPv4 { 372 | msg.WithdrawnRoutes = append(msg.WithdrawnRoutes, d.nlriIPv4()) 373 | } else if afi == AFIIPv6 { 374 | msg.WithdrawnRoutes = append(msg.WithdrawnRoutes, d.nlriIPv6()) 375 | } else { 376 | return nil, fmt.Errorf("unknown AFI: %d", afi) 377 | } 378 | } 379 | 380 | attrBytes := d.skip(int(d.uint16())) 381 | reader := bgpPathAttributeReader{reader: bytes.NewReader(attrBytes), as4: as4} 382 | for { 383 | attr, err := reader.Next() 384 | if err == io.EOF { 385 | break 386 | } 387 | if err != nil { 388 | return nil, err 389 | } 390 | msg.PathAttributes = append(msg.PathAttributes, attr) 391 | } 392 | 393 | for d.size() != 0 { 394 | if afi == AFIIPv4 { 395 | msg.NLRI = append(msg.NLRI, d.nlriIPv4()) 396 | } else if afi == AFIIPv6 { 397 | msg.NLRI = append(msg.NLRI, d.nlriIPv6()) 398 | } else { 399 | return nil, fmt.Errorf("unknown AFI: %d", afi) 400 | } 401 | } 402 | 403 | return msg, nil 404 | } 405 | 406 | type BGPNotificationMessage struct { 407 | bgpMessageHeader 408 | ErrorCode uint8 409 | ErrorSubcode uint8 410 | Data []byte 411 | } 412 | 413 | func decodeNotificationMessage(data []byte) (*BGPNotificationMessage, error) { 414 | d := &decoder{data} 415 | msg := &BGPNotificationMessage{} 416 | msg.decodeHeader(d) 417 | msg.ErrorCode = d.uint8() 418 | msg.ErrorSubcode = d.uint8() 419 | msg.Data = d.bytes(d.size()) 420 | return msg, nil 421 | } 422 | 423 | type BGPKeepaliveMessage struct { 424 | bgpMessageHeader 425 | } 426 | 427 | func decodeKeepaliveMessage(data []byte) (*BGPKeepaliveMessage, error) { 428 | d := &decoder{data} 429 | msg := &BGPKeepaliveMessage{} 430 | msg.decodeHeader(d) 431 | return msg, nil 432 | } 433 | -------------------------------------------------------------------------------- /mrt.go: -------------------------------------------------------------------------------- 1 | package mrt 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "net" 10 | "strconv" 11 | "time" 12 | ) 13 | 14 | type AS []byte 15 | 16 | func (as AS) String() string { 17 | if len(as) == 2 { 18 | return strconv.FormatUint(uint64(binary.BigEndian.Uint16(as)), 10) 19 | } else if len(as) == 4 { 20 | return strconv.FormatUint(uint64(binary.BigEndian.Uint32(as)), 10) 21 | } else { 22 | return string(as) 23 | } 24 | } 25 | 26 | func (as AS) MarshalText() ([]byte, error) { 27 | if len(as) == 0 { 28 | return []byte(""), nil 29 | } 30 | if len(as) != 2 && len(as) != 4 { 31 | return nil, errors.New("invalid AS number") 32 | } 33 | return []byte(as.String()), nil 34 | } 35 | 36 | type decoder struct { 37 | buf []byte 38 | } 39 | 40 | func (d *decoder) uint8() uint8 { 41 | x := d.buf[0] 42 | d.buf = d.buf[1:] 43 | return x 44 | } 45 | 46 | func (d *decoder) uint16() uint16 { 47 | x := binary.BigEndian.Uint16(d.buf) 48 | d.buf = d.buf[2:] 49 | return x 50 | } 51 | 52 | func (d *decoder) uint32() uint32 { 53 | x := binary.BigEndian.Uint32(d.buf) 54 | d.buf = d.buf[4:] 55 | return x 56 | } 57 | 58 | func (d *decoder) uint64() uint64 { 59 | x := binary.BigEndian.Uint64(d.buf) 60 | d.buf = d.buf[8:] 61 | return x 62 | } 63 | 64 | func (d *decoder) string(n int) string { 65 | x := string(d.buf[:n]) 66 | d.buf = d.buf[n:] 67 | return x 68 | } 69 | 70 | func (d *decoder) bytes(n int) []byte { 71 | x := make([]byte, n) 72 | d.copy(x) 73 | return x 74 | } 75 | 76 | func (d *decoder) ipv4() net.IP { 77 | x := make(net.IP, net.IPv4len) 78 | d.copy(x) 79 | return x 80 | } 81 | 82 | func (d *decoder) ipv4N(n int) net.IP { 83 | x := make(net.IP, net.IPv4len) 84 | d.copyN(x, n) 85 | return x 86 | } 87 | 88 | func (d *decoder) ipv6() net.IP { 89 | x := make(net.IP, net.IPv6len) 90 | d.copy(x) 91 | return x 92 | } 93 | 94 | func (d *decoder) ipv6N(n int) net.IP { 95 | x := make(net.IP, net.IPv6len) 96 | d.copyN(x, n) 97 | return x 98 | } 99 | 100 | func (d *decoder) as2() AS { 101 | x := make(AS, 2) 102 | d.copy(x) 103 | return x 104 | } 105 | 106 | func (d *decoder) as4() AS { 107 | x := make(AS, 4) 108 | d.copy(x) 109 | return x 110 | } 111 | 112 | func (d *decoder) nlriIPv4() *net.IPNet { 113 | l := int(d.uint8()) 114 | ip := d.ipv4N((l + 7) >> 3) 115 | mask := net.CIDRMask(l, net.IPv4len<<3) 116 | return &net.IPNet{IP: ip, Mask: mask} 117 | } 118 | 119 | func (d *decoder) nlriIPv6() *net.IPNet { 120 | l := int(d.uint8()) 121 | ip := d.ipv6N((l + 7) >> 3) 122 | mask := net.CIDRMask(l, net.IPv6len<<3) 123 | return &net.IPNet{IP: ip, Mask: mask} 124 | } 125 | 126 | func (d *decoder) unixTime() time.Time { 127 | return time.Unix(int64(d.uint32()), 0).UTC() 128 | } 129 | 130 | func (d *decoder) skip(n int) []byte { 131 | x := d.buf[:n] 132 | d.buf = d.buf[n:] 133 | return x 134 | } 135 | 136 | func (d *decoder) copy(b []byte) { 137 | copy(b, d.buf) 138 | d.buf = d.buf[len(b):] 139 | } 140 | 141 | func (d *decoder) copyN(b []byte, n int) { 142 | copy(b, d.buf[:n]) 143 | d.buf = d.buf[n:] 144 | } 145 | 146 | func (d *decoder) size() int { 147 | return len(d.buf) 148 | } 149 | 150 | type RecordType uint16 151 | 152 | const ( 153 | TYPE_OSPFv2 RecordType = 11 154 | TYPE_TABLE_DUMP = 12 155 | TYPE_TABLE_DUMP_V2 = 13 156 | TYPE_BGP4MP = 16 157 | TYPE_BGP4MP_ET = 17 158 | TYPE_ISIS = 32 159 | TYPE_ISIS_ET = 33 160 | TYPE_OSPFv3 = 48 161 | TYPE_OSPFv3_ET = 49 162 | ) 163 | 164 | func (t RecordType) HasExtendedTimestamp() bool { 165 | return t == TYPE_BGP4MP_ET || t == TYPE_ISIS_ET || t == TYPE_OSPFv3_ET 166 | } 167 | 168 | type header struct { 169 | timestamp time.Time 170 | type_ RecordType 171 | subtype uint16 172 | } 173 | 174 | func (h *header) Timestamp() time.Time { 175 | return h.timestamp 176 | } 177 | 178 | func (h *header) Type() RecordType { 179 | return h.type_ 180 | } 181 | 182 | func (h *header) Subtype() uint16 { 183 | return h.subtype 184 | } 185 | 186 | func (h *header) decodeHeader(d *decoder) error { 187 | h.timestamp = d.unixTime() 188 | h.type_ = RecordType(d.uint16()) 189 | h.subtype = d.uint16() 190 | d.skip(4) // Length (4 octets) 191 | if h.type_.HasExtendedTimestamp() { 192 | h.timestamp.Add(time.Duration(d.uint32()) * time.Microsecond) 193 | } 194 | return nil 195 | } 196 | 197 | type OSPFv2 struct { 198 | header 199 | RemoteIPAddress net.IP 200 | LocalIPAddress net.IP 201 | OSPFMessageContents []byte 202 | } 203 | 204 | func (r *OSPFv2) DecodeBytes(data []byte) error { 205 | d := &decoder{data} 206 | r.decodeHeader(d) 207 | r.RemoteIPAddress = d.ipv4() 208 | r.LocalIPAddress = d.ipv4() 209 | r.OSPFMessageContents = d.bytes(d.size()) 210 | return nil 211 | } 212 | 213 | const ( 214 | TABLE_DUMP_SUBTYPE_AFI_IPv4 = 1 215 | TABLE_DUMP_SUBTYPE_AFI_IPv6 = 2 216 | ) 217 | 218 | type TableDump struct { 219 | header 220 | ViewNumber uint16 221 | SequenceNumber uint16 222 | Prefix *net.IPNet 223 | OriginatedTime time.Time 224 | PeerIPAddress net.IP 225 | PeerAS AS 226 | BGPAttributes []*BGPPathAttribute 227 | } 228 | 229 | func (r *TableDump) DecodeBytes(data []byte) error { 230 | d := &decoder{data} 231 | r.decodeHeader(d) 232 | r.ViewNumber = d.uint16() 233 | r.SequenceNumber = d.uint16() 234 | 235 | if r.subtype == TABLE_DUMP_SUBTYPE_AFI_IPv4 { 236 | ip := d.ipv4() 237 | mask := net.CIDRMask(int(d.uint8()), net.IPv4len*8) 238 | r.Prefix = &net.IPNet{IP: ip, Mask: mask} 239 | } else { 240 | ip := d.ipv6() 241 | mask := net.CIDRMask(int(d.uint8()), net.IPv6len*8) 242 | r.Prefix = &net.IPNet{IP: ip, Mask: mask} 243 | } 244 | 245 | d.skip(1) // Status (1 octet) 246 | r.OriginatedTime = d.unixTime() 247 | if r.subtype == TABLE_DUMP_SUBTYPE_AFI_IPv4 { 248 | r.PeerIPAddress = d.ipv4() 249 | } else { 250 | r.PeerIPAddress = d.ipv6() 251 | } 252 | r.PeerAS = d.as2() 253 | 254 | attrBytes := d.skip(d.size()) 255 | reader := bgpPathAttributeReader{reader: bytes.NewReader(attrBytes), as4: false} 256 | for { 257 | attr, err := reader.Next() 258 | if err == io.EOF { 259 | break 260 | } 261 | if err != nil { 262 | return err 263 | } 264 | r.BGPAttributes = append(r.BGPAttributes, attr) 265 | } 266 | 267 | return nil 268 | } 269 | 270 | const ( 271 | TABLE_DUMP_V2_SUBTYPE_PEER_INDEX_TABLE = 1 272 | TABLE_DUMP_V2_SUBTYPE_RIB_IPv4_UNICAST = 2 273 | TABLE_DUMP_V2_SUBTYPE_RIB_IPv4_MULTICAST = 3 274 | TABLE_DUMP_V2_SUBTYPE_RIB_IPv6_UNICAST = 4 275 | TABLE_DUMP_V2_SUBTYPE_RIB_IPv6_MULTICAST = 5 276 | TABLE_DUMP_V2_SUBTYPE_RIB_GENERIC = 6 277 | ) 278 | 279 | type TableDumpV2PeerIndexTable struct { 280 | header 281 | CollectorBGPID net.IP 282 | ViewName string 283 | PeerEntries []*TableDumpV2PeerEntry 284 | } 285 | 286 | func (r *TableDumpV2PeerIndexTable) DecodeBytes(data []byte) error { 287 | d := &decoder{data} 288 | r.decodeHeader(d) 289 | r.CollectorBGPID = d.ipv4() 290 | r.ViewName = d.string(int(d.uint16())) 291 | 292 | n := int(d.uint16()) 293 | r.PeerEntries = make([]*TableDumpV2PeerEntry, n) 294 | for i := 0; i < n; i++ { 295 | entry := &TableDumpV2PeerEntry{} 296 | entry.PeerType = d.uint8() 297 | entry.PeerBGPID = d.ipv4() 298 | if entry.PeerType&0x1 == 0 { 299 | entry.PeerIPAddress = d.ipv4() 300 | } else { 301 | entry.PeerIPAddress = d.ipv6() 302 | } 303 | if entry.PeerType&0x2 == 0 { 304 | entry.PeerAS = d.as2() 305 | } else { 306 | entry.PeerAS = d.as4() 307 | } 308 | r.PeerEntries[i] = entry 309 | } 310 | 311 | return nil 312 | } 313 | 314 | type TableDumpV2PeerEntry struct { 315 | PeerType uint8 316 | PeerBGPID net.IP 317 | PeerIPAddress net.IP 318 | PeerAS AS 319 | } 320 | 321 | type TableDumpV2RIB struct { 322 | header 323 | SequenceNumber uint32 324 | Prefix *net.IPNet 325 | RIBEntries []*TableDumpV2RIBEntry 326 | } 327 | 328 | func (r *TableDumpV2RIB) DecodeBytes(data []byte) error { 329 | d := &decoder{data} 330 | r.decodeHeader(d) 331 | r.SequenceNumber = d.uint32() 332 | 333 | if r.subtype == TABLE_DUMP_V2_SUBTYPE_RIB_IPv4_UNICAST || 334 | r.subtype == TABLE_DUMP_V2_SUBTYPE_RIB_IPv4_MULTICAST { 335 | r.Prefix = d.nlriIPv4() 336 | } else { 337 | r.Prefix = d.nlriIPv6() 338 | } 339 | 340 | n := int(d.uint16()) 341 | r.RIBEntries = make([]*TableDumpV2RIBEntry, n) 342 | for i := 0; i < n; i++ { 343 | entry := &TableDumpV2RIBEntry{} 344 | entry.PeerIndex = d.uint16() 345 | entry.OriginatedTime = d.unixTime() 346 | 347 | attrBytes := d.skip(int(d.uint16())) 348 | reader := bgpPathAttributeReader{reader: bytes.NewReader(attrBytes), as4: true} 349 | for { 350 | attr, err := reader.Next() 351 | if err == io.EOF { 352 | break 353 | } 354 | if err != nil { 355 | return err 356 | } 357 | entry.BGPAttributes = append(entry.BGPAttributes, attr) 358 | } 359 | 360 | r.RIBEntries[i] = entry 361 | } 362 | 363 | return nil 364 | } 365 | 366 | type AFI uint16 367 | 368 | const ( 369 | AFIIPv4 AFI = 1 370 | AFIIPv6 = 2 371 | ) 372 | 373 | type SAFI uint8 374 | 375 | const ( 376 | SAFIUnicast SAFI = 1 377 | SAFIMulticast = 2 378 | ) 379 | 380 | type TableDumpV2RIBGeneric struct { 381 | header 382 | SequenceNumber uint32 383 | AFI AFI 384 | SAFI SAFI 385 | NLRI []byte 386 | RIBEntries []*TableDumpV2RIBEntry 387 | } 388 | 389 | func (r *TableDumpV2RIBGeneric) DecodeBytes(data []byte) error { 390 | d := &decoder{data} 391 | r.decodeHeader(d) 392 | r.SequenceNumber = d.uint32() 393 | r.AFI = AFI(d.uint16()) 394 | r.SAFI = SAFI(d.uint8()) 395 | // r.NLRI 396 | // r.RIBEntries 397 | return nil 398 | } 399 | 400 | type TableDumpV2RIBEntry struct { 401 | PeerIndex uint16 402 | OriginatedTime time.Time 403 | BGPAttributes []*BGPPathAttribute 404 | } 405 | 406 | const ( 407 | BGP4MP_SUBTYPE_BGP4MP_STATE_CHANGE = 0 408 | BGP4MP_SUBTYPE_BGP4MP_MESSAGE = 1 409 | BGP4MP_SUBTYPE_BGP4MP_MESSAGE_AS4 = 4 410 | BGP4MP_SUBTYPE_BGP4MP_STATE_CHANGE_AS4 = 5 411 | BGP4MP_SUBTYPE_BGP4MP_MESSAGE_LOCAL = 6 412 | BGP4MP_SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL = 7 413 | ) 414 | 415 | type BGP4MPStateChange struct { 416 | header 417 | PeerAS AS 418 | LocalAS AS 419 | InterfaceIndex uint16 420 | AFI AFI 421 | PeerIPAddress net.IP 422 | LocalIPAddress net.IP 423 | OldState uint16 424 | NewState uint16 425 | } 426 | 427 | func (r *BGP4MPStateChange) DecodeBytes(data []byte) error { 428 | d := &decoder{data} 429 | r.decodeHeader(d) 430 | 431 | if r.subtype == BGP4MP_SUBTYPE_BGP4MP_STATE_CHANGE { 432 | r.PeerAS = d.as2() 433 | r.LocalAS = d.as2() 434 | } else { 435 | r.PeerAS = d.as4() 436 | r.LocalAS = d.as4() 437 | } 438 | 439 | r.InterfaceIndex = d.uint16() 440 | r.AFI = AFI(d.uint16()) 441 | 442 | if r.AFI == AFIIPv4 { 443 | r.PeerIPAddress = d.ipv4() 444 | r.LocalIPAddress = d.ipv4() 445 | } else { 446 | r.PeerIPAddress = d.ipv6() 447 | r.LocalIPAddress = d.ipv6() 448 | } 449 | 450 | r.OldState = d.uint16() 451 | r.NewState = d.uint16() 452 | 453 | return nil 454 | } 455 | 456 | type BGP4MPMessage struct { 457 | header 458 | PeerAS AS 459 | LocalAS AS 460 | InterfaceIndex uint16 461 | AFI AFI 462 | PeerIPAddress net.IP 463 | LocalIPAddress net.IP 464 | BGPMessage *BGPMessage 465 | } 466 | 467 | func (r *BGP4MPMessage) DecodeBytes(data []byte) error { 468 | d := &decoder{data} 469 | r.decodeHeader(d) 470 | 471 | as4 := r.subtype == BGP4MP_SUBTYPE_BGP4MP_MESSAGE_AS4 || 472 | r.subtype == BGP4MP_SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL 473 | if as4 { 474 | r.PeerAS = d.as4() 475 | r.LocalAS = d.as4() 476 | } else { 477 | r.PeerAS = d.as2() 478 | r.LocalAS = d.as2() 479 | } 480 | 481 | r.InterfaceIndex = d.uint16() 482 | r.AFI = AFI(d.uint16()) 483 | 484 | if r.AFI == AFIIPv4 { 485 | r.PeerIPAddress = d.ipv4() 486 | r.LocalIPAddress = d.ipv4() 487 | } else { 488 | r.PeerIPAddress = d.ipv6() 489 | r.LocalIPAddress = d.ipv6() 490 | } 491 | 492 | var err error 493 | r.BGPMessage, err = decodeBGPMessage(d.skip(d.size()), as4, r.AFI) 494 | 495 | return err 496 | } 497 | 498 | type ISIS struct { 499 | header 500 | ISISPDU []byte 501 | } 502 | 503 | func (r *ISIS) DecodeBytes(data []byte) error { 504 | d := &decoder{data} 505 | r.decodeHeader(d) 506 | r.ISISPDU = d.bytes(d.size()) 507 | return nil 508 | } 509 | 510 | type OSPFv3 struct { 511 | header 512 | AFI AFI 513 | RemoteIPAddress net.IP 514 | LocalIPAddress net.IP 515 | OSPFMessageContents []byte 516 | } 517 | 518 | func (r *OSPFv3) DecodeBytes(data []byte) error { 519 | d := &decoder{data} 520 | r.decodeHeader(d) 521 | r.AFI = AFI(d.uint16()) 522 | r.LocalIPAddress = d.ipv4() 523 | r.RemoteIPAddress = d.ipv4() 524 | r.OSPFMessageContents = d.bytes(d.size()) 525 | return nil 526 | } 527 | 528 | type Record interface { 529 | Timestamp() time.Time 530 | Type() RecordType 531 | Subtype() uint16 532 | DecodeBytes([]byte) error 533 | } 534 | 535 | type Reader struct { 536 | reader io.Reader 537 | } 538 | 539 | func NewReader(r io.Reader) *Reader { 540 | return &Reader{ 541 | reader: r, 542 | } 543 | } 544 | 545 | func (r *Reader) Next() (Record, error) { 546 | hdrBytes := make([]byte, 12) 547 | if _, err := io.ReadFull(r.reader, hdrBytes); err != nil { 548 | return nil, err 549 | } 550 | 551 | hdrType := RecordType(binary.BigEndian.Uint16(hdrBytes[4:])) 552 | hdrSubtype := binary.BigEndian.Uint16(hdrBytes[6:]) 553 | hdrLength := binary.BigEndian.Uint32(hdrBytes[8:]) 554 | 555 | var record Record 556 | switch hdrType { 557 | case TYPE_OSPFv2: 558 | record = new(OSPFv2) 559 | case TYPE_TABLE_DUMP: 560 | switch hdrSubtype { 561 | case TABLE_DUMP_SUBTYPE_AFI_IPv4, TABLE_DUMP_SUBTYPE_AFI_IPv6: 562 | record = new(TableDump) 563 | default: 564 | return nil, fmt.Errorf("unknown MRT record subtype: %d", hdrSubtype) 565 | } 566 | case TYPE_TABLE_DUMP_V2: 567 | switch hdrSubtype { 568 | case TABLE_DUMP_V2_SUBTYPE_PEER_INDEX_TABLE: 569 | record = new(TableDumpV2PeerIndexTable) 570 | case TABLE_DUMP_V2_SUBTYPE_RIB_IPv4_UNICAST, 571 | TABLE_DUMP_V2_SUBTYPE_RIB_IPv4_MULTICAST, 572 | TABLE_DUMP_V2_SUBTYPE_RIB_IPv6_UNICAST, 573 | TABLE_DUMP_V2_SUBTYPE_RIB_IPv6_MULTICAST: 574 | record = new(TableDumpV2RIB) 575 | case TABLE_DUMP_V2_SUBTYPE_RIB_GENERIC: 576 | record = new(TableDumpV2RIBGeneric) 577 | default: 578 | return nil, fmt.Errorf("unknown MRT record subtype: %d", hdrSubtype) 579 | } 580 | case TYPE_BGP4MP, TYPE_BGP4MP_ET: 581 | switch hdrSubtype { 582 | case BGP4MP_SUBTYPE_BGP4MP_STATE_CHANGE, BGP4MP_SUBTYPE_BGP4MP_STATE_CHANGE_AS4: 583 | record = new(BGP4MPStateChange) 584 | case BGP4MP_SUBTYPE_BGP4MP_MESSAGE, 585 | BGP4MP_SUBTYPE_BGP4MP_MESSAGE_AS4, 586 | BGP4MP_SUBTYPE_BGP4MP_MESSAGE_LOCAL, 587 | BGP4MP_SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL: 588 | record = new(BGP4MPMessage) 589 | default: 590 | return nil, fmt.Errorf("unknown MRT record subtype: %d", hdrSubtype) 591 | } 592 | case TYPE_ISIS, TYPE_ISIS_ET: 593 | record = new(ISIS) 594 | case TYPE_OSPFv3, TYPE_OSPFv3_ET: 595 | record = new(OSPFv3) 596 | default: 597 | return nil, fmt.Errorf("unknown MRT record type: %d", hdrType) 598 | } 599 | 600 | data := make([]byte, len(hdrBytes)+int(hdrLength)) 601 | copy(data, hdrBytes) 602 | if _, err := io.ReadFull(r.reader, data[len(hdrBytes):]); err != nil { 603 | return nil, err 604 | } 605 | 606 | if err := record.DecodeBytes(data); err != nil { 607 | return nil, err 608 | } 609 | 610 | return record, nil 611 | } 612 | --------------------------------------------------------------------------------