Source: ../../rip/packets.hh
|
|
|
|
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2003 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.
// $XORP: xorp/rip/packets.hh,v 1.11 2003/09/30 18:27:07 pavlin Exp $
#ifndef __RIP_PACKET_ENTRIES_HH__
#define __RIP_PACKET_ENTRIES_HH__
#include "libxorp/ipv4.hh"
#include "libxorp/ipv4net.hh"
#include "libxorp/ipv6.hh"
#include "libxorp/ipv6net.hh"
#include "constants.hh"
/**
* @short Header appearing at the start of each RIP packet.
*/
struct RipPacketHeader {
uint8_t command; // 1 - request, 2 - response
uint8_t version; // 1 - IPv4 RIPv1/IPv6 RIPng, 2 - IPv4 RIP v2
uint8_t unused[2];
inline void initialize(uint8_t cmd, uint8_t vers);
inline bool valid_command() const;
inline bool valid_version(uint8_t v) const { return version == v; }
inline bool valid_padding() const;
static const uint8_t REQUEST = 1;
static const uint8_t RESPONSE = 2;
static const uint8_t IPv4_VERSION = 1;
static const uint8_t IPv6_VERSION = 2;
};
inline void
RipPacketHeader::initialize(uint8_t cmd, uint8_t vers)
{
command = cmd;
version = vers;
unused[0] = unused[1] = 0;
}
inline bool
RipPacketHeader::valid_command() const
{
return command == REQUEST || command == RESPONSE;
}
inline bool
RipPacketHeader::valid_padding() const
{
return (unused[0] | unused[1]) == 0;
}
/**
* @short Route Entry as it appears in a RIP Packet.
*
* This structure is useful only it's specialized forms
* @ref PacketRouteEntry<IPv4> and @ref PacketRouteEntry<IPv6>.
*/
template <typename A>
struct PacketRouteEntry {
};
/**
* Smallest RIPv2 packet size.
*/
static const size_t RIPv2_MIN_PACKET_BYTES = 4;
/**
* Smallest authenticated RIPv2 packet size.
*/
static const size_t RIPv2_MIN_AUTH_PACKET_BYTES = 4 + 20;
/**
* Largest RIPv2 packet size.
*/
static const size_t RIPv2_MAX_PACKET_BYTES = 4 + 20 * RIPv2_ROUTES_PER_PACKET;
/**
* @short Route Entry appearing in RIP packets on IPv4.
*
* This payload is carried in RIP packets on IPv4. The entry contains
* all the fields for RIPv2. RIPv1 and RIPv2 use the same size
* structure, except RIPv1 treats the route tag, subnet mask and
* nexthop fields as Must-Be-Zero (MBZ) items. The interpretation of
* the fields is described in RFC2453.
*
* All items in the route entry are stored in network order. The
* accessor methods provide values in host order, and the modifiers
* take arguments in host order.
*/
struct PacketRouteEntry<IPv4> {
protected:
uint16_t _af;
uint16_t _tag;
uint32_t _addr;
uint32_t _mask;
uint32_t _nh;
uint32_t _metric;
public:
/**
* Initialize fields as a regular routing entry.
*/
inline void initialize(uint16_t tag,
const IPv4Net& net,
IPv4 nh,
uint32_t cost);
/**
* Initialize fields as a route table request.
*/
inline void initialize_table_request();
inline uint16_t addr_family() const { return ntohs(_af); }
inline uint16_t tag() const { return ntohs(_tag); }
inline IPv4Net net() const;
inline IPv4 nexthop() const { return IPv4(_nh); }
inline uint32_t metric() const { return ntohl(_metric); }
/**
* @return true if route entry has properties of a table request.
*/
inline bool is_table_request() const;
/**
* @return true if route entry has properties of an authentication entry.
*/
inline bool is_auth_entry() const;
static const uint16_t ADDR_FAMILY = 2;
static const uint16_t ADDR_FAMILY_DUMP = 0;
static const uint16_t ADDR_FAMILY_AUTH = 0xffff;
};
inline void
PacketRouteEntry<IPv4>::initialize(uint16_t tag,
const IPv4Net& net,
IPv4 nh,
uint32_t cost)
{
_af = htons(ADDR_FAMILY);
_tag = htons(tag);
_addr = net.masked_addr().addr();
_mask = net.netmask().addr();
_nh = nh.addr();
_metric = htonl(cost);
}
inline IPv4Net
PacketRouteEntry<IPv4>::net() const
{
return IPv4Net(IPv4(_addr), IPv4(_mask).mask_len());
}
inline bool
PacketRouteEntry<IPv4>::is_table_request() const
{
return addr_family() == ADDR_FAMILY_DUMP && metric() == RIP_INFINITY;
}
inline bool
PacketRouteEntry<IPv4>::is_auth_entry() const
{
return addr_family() == ADDR_FAMILY_AUTH;
}
inline void
PacketRouteEntry<IPv4>::initialize_table_request()
{
_af = htons(ADDR_FAMILY_DUMP);
_tag = 0;
_addr = 0;
_mask = 0;
_nh = 0;
_metric = htonl(RIP_INFINITY);
}
/**
* @short Route Entry for Plaintext password.
*
* The PlaintextPacketRouteEntry4 may appear as the first route entry
* in a RIPv2 packet. It has the same size as an @ref
* PacketRouteEntry<IPv4>. The address family has the special value
* 0xffff which imples authentication. The authentication type is
* overlaid in the route tag field and takes the special value 2.
*
* All items in the route entry are stored in network order. The
* accessor methods provide values in host order, and the modifiers
* take arguments in host order.
*/
struct PlaintextPacketRouteEntry4 {
protected:
uint16_t _af;
uint16_t _auth;
char _pw[16];
public:
inline uint16_t addr_family() const { return ntohs(_af); }
inline uint16_t auth_type() const { return ntohs(_auth); }
inline string password() const { return string(_pw, 0, 16); }
inline void initialize(const string& s)
{
_af = ADDR_FAMILY;
_auth = htons(AUTH_TYPE);
memset(_pw, 0, sizeof(_pw));
s.copy(_pw, 16);
}
static const uint16_t ADDR_FAMILY = 0xffff;
static const uint16_t AUTH_TYPE = 2;
};
/**
* @short Route Entry for MD5 data.
*
* The MD5PacketRouteEntry4 may appear as the first route entry
* in a RIPv2 packet. It has the same size as an @ref
* PacketRouteEntry<IPv4>. The address family has the special value
* 0xffff which imples authentication. The authentication type is
* overlaid in the route tag field and takes the special value 3. With
* MD5 the authentication data appears after the remaining route entries.
* Details are disclosed in RFC2082.
*
* All items in the route entry are stored in network order. The
* accessor methods provide values in host order, and the modifiers
* take arguments in host order.
*
* NB We describe the field labelled as "RIP-2 Packet Length" on page 5 of
* RFC 2082 as the "auth_offset". This matches the textual description in
* the RFC.
*/
struct MD5PacketRouteEntry4 {
protected:
uint16_t _af; // 0xffff - Authentication header
uint16_t _auth; // authentication type
uint16_t _auth_offset; // Offset of authentication data
uint8_t _key_id; // Key number used
uint8_t _auth_bytes; // auth data length at end of packet
uint32_t _seqno; // monotonically increasing seqno
uint32_t _mbz[2]; // must-be-zero
public:
inline uint16_t addr_family() const { return ntohs(_af); }
inline uint16_t auth_type() const { return ntohs(_auth); }
inline uint16_t auth_offset() const { return ntohs(_auth_offset); }
inline uint8_t key_id() const { return _key_id; }
inline uint8_t auth_bytes() const { return _auth_bytes; }
inline uint32_t seqno() const { return htonl(_seqno); }
inline void set_auth_offset(uint16_t b) { _auth_offset = htons(b); }
inline void set_key_id(uint8_t id) { _key_id = id; }
inline void set_auth_bytes(uint8_t b) { _auth_bytes = b; }
inline void set_seqno(uint32_t sno) { _seqno = htonl(sno); }
inline void initialize(uint16_t pkt_bytes,
uint8_t key_id,
uint8_t auth_bytes,
uint32_t seqno);
static const uint16_t ADDR_FAMILY = 0xffff;
static const uint16_t AUTH_TYPE = 3;
};
inline void
MD5PacketRouteEntry4::initialize(uint16_t auth_offset,
uint8_t key_id,
uint8_t auth_bytes,
uint32_t seqno)
{
_af = ADDR_FAMILY;
_auth = htons(AUTH_TYPE);
_mbz[0] = _mbz[1] = 0;
set_auth_offset(auth_offset);
set_key_id(key_id);
set_auth_bytes(auth_bytes);
set_seqno(seqno);
}
/**
* @short Container for MD5 trailer.
*/
class MD5PacketTrailer {
public:
inline void initialize();
inline uint8_t* data() { return _data; }
inline const uint8_t* data() const { return _data; }
inline uint32_t data_bytes() const { return 16; }
inline bool valid() const;
protected:
uint16_t _af; // 0xffff - Authentication header
uint16_t _one; // 0x01 - RFC2082 defined
uint8_t _data[16]; // 16 bytes of data
};
inline void
MD5PacketTrailer::initialize()
{
_af = 0xffff;
_one = htons(1);
}
bool
MD5PacketTrailer::valid() const
{
return _af == 0xffff && htons(_one) == 1;
}
/**
* @short Route Entry appearing in RIP packets on IPv6.
*
* This payload is carried in RIP packets on IPv6. The interpretation
* of the fields is defined in RFC2080.
*
* All fields in this structure are stored in network order.
*/
struct PacketRouteEntry<IPv6> {
protected:
uint8_t _prefix[16];
uint16_t _tag;
uint8_t _prefix_length;
uint8_t _metric;
public:
/**
* Initialize fields as a route entry.
*/
inline void initialize_route(uint16_t route_tag,
const IPv6Net& net,
uint8_t cost);
/**
* Initialize fields as a nexthop entry.
*/
inline void initialize_nexthop(const IPv6& nexthop);
/**
* Initialize fields as a route table request.
*/
inline void initialize_table_request();
inline bool is_nexthop() const;
inline bool is_table_request() const;
inline IPv6 nexthop() const;
inline uint16_t tag() const;
inline IPv6Net net() const;
inline uint8_t metric() const;
static const uint8_t NEXTHOP_METRIC = 0xff;
};
inline void
PacketRouteEntry<IPv6>::initialize_route(uint16_t tag,
const IPv6Net& net,
uint8_t cost)
{
_tag = htons(tag);
_prefix_length = net.prefix_len();
_metric = cost;
net.masked_addr().copy_out(_prefix);
}
inline void
PacketRouteEntry<IPv6>::initialize_nexthop(const IPv6& nexthop)
{
_tag = 0;
_prefix_length = 0;
_metric = NEXTHOP_METRIC;
nexthop.copy_out(_prefix);
}
inline void
PacketRouteEntry<IPv6>::initialize_table_request()
{
memset(this, 0, sizeof(*this));
_metric = RIP_INFINITY;
}
inline bool
PacketRouteEntry<IPv6>::is_table_request() const
{
if (_metric != RIP_INFINITY) {
return false;
}
const uint32_t* p = reinterpret_cast<const uint32_t*>(_prefix);
return (p[0] == 0) && (p[1] == 0) && (p[2] == 0) && (p[3] == 0);
}
inline bool
PacketRouteEntry<IPv6>::is_nexthop() const
{
return _metric == NEXTHOP_METRIC;
}
inline IPv6
PacketRouteEntry<IPv6>::nexthop() const
{
return IPv6(_prefix);
}
inline uint16_t
PacketRouteEntry<IPv6>::tag() const
{
return ntohs(_tag);
}
inline IPv6Net
PacketRouteEntry<IPv6>::net() const
{
return IPv6Net(IPv6(_prefix), _prefix_length);
}
inline uint8_t
PacketRouteEntry<IPv6>::metric() const
{
return _metric;
}
/**
* @short RIP Packet class.
*
* A container for RIP packet, provides easy to use accessors and modifiers.
*/
template <typename A>
class RipPacket
{
public:
typedef A Addr;
protected:
Addr _addr; // Src addr on inbound, dst address on outbound
uint16_t _port; // Src port on inbound, dst port on outbound
vector<uint8_t> _data; // Data buffer
uint32_t _max_entries; // Maximum number of route entries in packet
protected:
const uint8_t* base_ptr() const { return &(_data[0]); }
uint8_t* base_ptr() { return &(_data[0]); }
public:
/**
* @return destination address of packet.
*/
inline const Addr& address() const { return _addr; }
/**
* @return destination port of packet.
*/
inline uint16_t port() const { return _port; }
/**
* @return the maximum number of route entries packet may have.
*/
inline uint32_t max_entries() const { return _max_entries; }
/**
* Set the maximum number of route entries a packet may have.
* This method should be called before using @ref append_data
* methods as it resizes the internal storage and will cause
* appended data to be lost.
*/
inline void set_max_entries(uint32_t max_entries);
RipPacket(const Addr& addr,
uint16_t port,
uint32_t max_entries = RIPv2_ROUTES_PER_PACKET)
: _addr(addr), _port(port), _max_entries(0)
{
set_max_entries(max_entries);
}
/**
* @return const pointer to RipPacketHeader.
*/
inline const RipPacketHeader* header() const;
/**
* @return pointer to RipPacketHeader.
*/
inline RipPacketHeader* header();
/**
* Route entry accessor.
*
* @param entry_no index of route entry to retrive
* @return const pointer to route entry, or 0 if entry_no is greater than
* the maximum route entries associated with packet.
*/
inline const PacketRouteEntry<A>* route_entry(uint32_t entry_no) const;
/**
* Route entry accessor.
*
* @param entry_no index of route entry to retrive
* @return const pointer to route entry, or 0 if entry_no is greater than
* the maximum route entries associated with packet.
*/
inline PacketRouteEntry<A>* route_entry(uint32_t entry_no);
void append_data(const uint8_t* data, uint32_t data_bytes);
void append_data(const vector<uint8_t>& data);
inline vector<uint8_t>& data() { return _data; }
inline const vector<uint8_t>& data() const { return _data; }
inline uint32_t data_bytes() const { return _data.size(); }
inline const uint8_t* data_ptr() const { return base_ptr(); }
inline uint8_t* data_ptr() { return base_ptr(); }
};
template <typename A>
const RipPacketHeader*
RipPacket<A>::header() const
{
return reinterpret_cast<const RipPacketHeader*>(base_ptr());
}
template <typename A>
RipPacketHeader*
RipPacket<A>::header()
{
return reinterpret_cast<RipPacketHeader*>(base_ptr());
}
template <typename A>
const PacketRouteEntry<A>*
RipPacket<A>::route_entry(uint32_t entry_no) const
{
if (entry_no >= _max_entries)
return 0;
const uint8_t* p = base_ptr() + sizeof(RipPacketHeader) +
entry_no * sizeof(PacketRouteEntry<A>);
return reinterpret_cast<const PacketRouteEntry<A>*>(p);
}
template <typename A>
PacketRouteEntry<A>*
RipPacket<A>::route_entry(uint32_t entry_no)
{
if (entry_no >= _max_entries)
return 0;
uint8_t* p = base_ptr() + sizeof(RipPacketHeader) +
entry_no * sizeof(PacketRouteEntry<A>);
return reinterpret_cast<PacketRouteEntry<A>*>(p);
}
template <typename A>
void
RipPacket<A>::append_data(const uint8_t* data, uint32_t data_bytes)
{
_data.insert(_data.end(), data, data + data_bytes);
}
template <typename A>
void
RipPacket<A>::append_data(const vector<uint8_t>& data)
{
_data.insert(_data.end(), data.begin(), data.end());
}
template <typename A>
void
RipPacket<A>::set_max_entries(uint32_t max_entries)
{
if (max_entries != _max_entries) {
_data.resize(sizeof(PacketRouteEntry<A>) * max_entries
+ sizeof(RipPacketHeader));
_max_entries = max_entries;
}
}
#endif // __RIP_PACKETS_HH__
Generated by: pavlin on possum.icir.org on Thu Nov 6 23:47:08 2003, using kdoc 2.0a54+XORP. |