2017-04-17 10:33:09 +05:30

393 lines
8.7 KiB
Go

// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rtr
import (
"encoding/binary"
"fmt"
"net"
)
const (
RPKI_DEFAULT_PORT = 323
)
const (
RTR_SERIAL_NOTIFY = iota
RTR_SERIAL_QUERY
RTR_RESET_QUERY
RTR_CACHE_RESPONSE
RTR_IPV4_PREFIX
_
RTR_IPV6_PREFIX
RTR_END_OF_DATA
RTR_CACHE_RESET
_
RTR_ERROR_REPORT
)
const (
RTR_SERIAL_NOTIFY_LEN = 12
RTR_SERIAL_QUERY_LEN = 12
RTR_RESET_QUERY_LEN = 8
RTR_CACHE_RESPONSE_LEN = 8
RTR_IPV4_PREFIX_LEN = 20
RTR_IPV6_PREFIX_LEN = 32
RTR_END_OF_DATA_LEN = 12
RTR_CACHE_RESET_LEN = 8
RTR_MIN_LEN = 8
RTR_ERROR_REPORT_ERR_PDU_LEN = 4
RTR_ERROR_REPORT_ERR_TEXT_LEN = 4
)
const (
WITHDRAWAL uint8 = iota
ANNOUNCEMENT
)
const (
CORRUPT_DATA uint16 = iota
INTERNAL_ERROR
NO_DATA_AVAILABLE
INVALID_REQUEST
UNSUPPORTED_PROTOCOL_VERSION
UNSUPPORTED_PDU_TYPE
WITHDRAWAL_OF_UNKNOWN_RECORD
DUPLICATE_ANNOUNCEMENT_RECORD
)
type RTRMessage interface {
DecodeFromBytes([]byte) error
Serialize() ([]byte, error)
}
type RTRCommon struct {
Version uint8
Type uint8
SessionID uint16
Len uint32
SerialNumber uint32
}
func (m *RTRCommon) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.SessionID = binary.BigEndian.Uint16(data[2:4])
m.Len = binary.BigEndian.Uint32(data[4:8])
m.SerialNumber = binary.BigEndian.Uint32(data[8:12])
return nil
}
func (m *RTRCommon) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint16(data[2:4], m.SessionID)
binary.BigEndian.PutUint32(data[4:8], m.Len)
binary.BigEndian.PutUint32(data[8:12], m.SerialNumber)
return data, nil
}
type RTRSerialNotify struct {
RTRCommon
}
func NewRTRSerialNotify(id uint16, sn uint32) *RTRSerialNotify {
return &RTRSerialNotify{
RTRCommon{
Type: RTR_SERIAL_NOTIFY,
SessionID: id,
Len: RTR_SERIAL_NOTIFY_LEN,
SerialNumber: sn,
},
}
}
type RTRSerialQuery struct {
RTRCommon
}
func NewRTRSerialQuery(id uint16, sn uint32) *RTRSerialQuery {
return &RTRSerialQuery{
RTRCommon{
Type: RTR_SERIAL_QUERY,
SessionID: id,
Len: RTR_SERIAL_QUERY_LEN,
SerialNumber: sn,
},
}
}
type RTRReset struct {
Version uint8
Type uint8
Len uint32
}
func (m *RTRReset) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.Len = binary.BigEndian.Uint32(data[4:8])
return nil
}
func (m *RTRReset) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint32(data[4:8], m.Len)
return data, nil
}
type RTRResetQuery struct {
RTRReset
}
func NewRTRResetQuery() *RTRResetQuery {
return &RTRResetQuery{
RTRReset{
Type: RTR_RESET_QUERY,
Len: RTR_RESET_QUERY_LEN,
},
}
}
type RTRCacheResponse struct {
Version uint8
Type uint8
SessionID uint16
Len uint32
}
func (m *RTRCacheResponse) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.SessionID = binary.BigEndian.Uint16(data[2:4])
m.Len = binary.BigEndian.Uint32(data[4:8])
return nil
}
func (m *RTRCacheResponse) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint16(data[2:4], m.SessionID)
binary.BigEndian.PutUint32(data[4:8], m.Len)
return data, nil
}
func NewRTRCacheResponse(id uint16) *RTRCacheResponse {
return &RTRCacheResponse{
Type: RTR_CACHE_RESPONSE,
SessionID: id,
Len: RTR_CACHE_RESPONSE_LEN,
}
}
type RTRIPPrefix struct {
Version uint8
Type uint8
Len uint32
Flags uint8
PrefixLen uint8
MaxLen uint8
Prefix net.IP
AS uint32
}
func (m *RTRIPPrefix) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.Len = binary.BigEndian.Uint32(data[4:8])
m.Flags = data[8]
m.PrefixLen = data[9]
m.MaxLen = data[10]
if m.Type == RTR_IPV4_PREFIX {
m.Prefix = net.IP(data[12:16]).To4()
m.AS = binary.BigEndian.Uint32(data[16:20])
} else {
m.Prefix = net.IP(data[12:28]).To16()
m.AS = binary.BigEndian.Uint32(data[28:32])
}
return nil
}
func (m *RTRIPPrefix) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint32(data[4:8], m.Len)
data[8] = m.Flags
data[9] = m.PrefixLen
data[10] = m.MaxLen
if m.Type == RTR_IPV4_PREFIX {
copy(data[12:16], m.Prefix.To4())
binary.BigEndian.PutUint32(data[16:20], m.AS)
} else {
copy(data[12:28], m.Prefix.To16())
binary.BigEndian.PutUint32(data[28:32], m.AS)
}
return data, nil
}
func NewRTRIPPrefix(prefix net.IP, prefixLen, maxLen uint8, as uint32, flags uint8) *RTRIPPrefix {
var pduType uint8
var pduLen uint32
if prefix.To4() != nil && prefixLen <= 32 {
pduType = RTR_IPV4_PREFIX
pduLen = RTR_IPV4_PREFIX_LEN
} else {
pduType = RTR_IPV6_PREFIX
pduLen = RTR_IPV6_PREFIX_LEN
}
return &RTRIPPrefix{
Type: pduType,
Len: pduLen,
Flags: flags,
PrefixLen: prefixLen,
MaxLen: maxLen,
Prefix: prefix,
AS: as,
}
}
type RTREndOfData struct {
RTRCommon
}
func NewRTREndOfData(id uint16, sn uint32) *RTREndOfData {
return &RTREndOfData{
RTRCommon{
Type: RTR_END_OF_DATA,
SessionID: id,
Len: RTR_END_OF_DATA_LEN,
SerialNumber: sn,
},
}
}
type RTRCacheReset struct {
RTRReset
}
func NewRTRCacheReset() *RTRCacheReset {
return &RTRCacheReset{
RTRReset{
Type: RTR_CACHE_RESET,
Len: RTR_CACHE_RESET_LEN,
},
}
}
type RTRErrorReport struct {
Version uint8
Type uint8
ErrorCode uint16
Len uint32
PDULen uint32
PDU []byte
TextLen uint32
Text []byte
}
func (m *RTRErrorReport) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.ErrorCode = binary.BigEndian.Uint16(data[2:4])
m.Len = binary.BigEndian.Uint32(data[4:8])
m.PDULen = binary.BigEndian.Uint32(data[8:12])
m.PDU = make([]byte, m.PDULen)
copy(m.PDU, data[12:12+m.PDULen])
m.TextLen = binary.BigEndian.Uint32(data[12+m.PDULen : 16+m.PDULen])
m.Text = make([]byte, m.TextLen)
copy(m.Text, data[16+m.PDULen:])
return nil
}
func (m *RTRErrorReport) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint16(data[2:4], m.ErrorCode)
binary.BigEndian.PutUint32(data[4:8], m.Len)
binary.BigEndian.PutUint32(data[8:12], m.PDULen)
copy(data[12:], m.PDU)
binary.BigEndian.PutUint32(data[12+m.PDULen:16+m.PDULen], m.TextLen)
copy(data[16+m.PDULen:], m.Text)
return data, nil
}
func NewRTRErrorReport(errCode uint16, errPDU []byte, errMsg []byte) *RTRErrorReport {
pdu := &RTRErrorReport{Type: RTR_ERROR_REPORT, ErrorCode: errCode}
if errPDU != nil {
if errPDU[1] == RTR_ERROR_REPORT {
return nil
}
pdu.PDULen = uint32(len(errPDU))
pdu.PDU = errPDU
}
if errMsg != nil {
pdu.Text = errMsg
pdu.TextLen = uint32(len(errMsg))
}
pdu.Len = uint32(RTR_MIN_LEN) + uint32(RTR_ERROR_REPORT_ERR_PDU_LEN) + pdu.PDULen + uint32(RTR_ERROR_REPORT_ERR_TEXT_LEN) + pdu.TextLen
return pdu
}
func SplitRTR(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 || len(data) < RTR_MIN_LEN {
return 0, nil, nil
}
totalLen := binary.BigEndian.Uint32(data[4:8])
if totalLen < RTR_MIN_LEN {
return 0, nil, fmt.Errorf("Invalid length: %d", totalLen)
}
if uint32(len(data)) < totalLen {
return 0, nil, nil
}
return int(totalLen), data[0:totalLen], nil
}
func ParseRTR(data []byte) (RTRMessage, error) {
var msg RTRMessage
switch data[1] {
case RTR_SERIAL_NOTIFY:
msg = &RTRSerialNotify{}
case RTR_SERIAL_QUERY:
msg = &RTRSerialQuery{}
case RTR_RESET_QUERY:
msg = &RTRResetQuery{}
case RTR_CACHE_RESPONSE:
msg = &RTRCacheResponse{}
case RTR_IPV4_PREFIX:
msg = &RTRIPPrefix{}
case RTR_IPV6_PREFIX:
msg = &RTRIPPrefix{}
case RTR_END_OF_DATA:
msg = &RTREndOfData{}
case RTR_CACHE_RESET:
msg = &RTRCacheReset{}
case RTR_ERROR_REPORT:
msg = &RTRErrorReport{}
default:
return nil, fmt.Errorf("unknown RTR message type %d:", data[1])
}
err := msg.DecodeFromBytes(data)
return msg, err
}