Mobile Agents in Click

advertisement
Mobile Agents in Click
Tushar Mohan
School of Computing
University of Utah
tushar@cs.utah.edu
Abstract
Click is a modular, flexible and extensible router software architecture. It is designed to permit the
user to form router configurations to support their specific needs. Click’s unit of modularity is an element.
Different Click elements, each of which performs a specific task, are arranged in flow graphs to perform
customized packet processing. At the time of writing this paper, Click running on commodity Pentium III PCs
could achieve peak forwarding rate of 1.3 million 64-byte packets per second.
With time, numerous elements have been added to Click to perform specific functions such as IPv6
Neighborhood Advertisement etc. However the only form of mobile IP support in Click was, to manually
configure a Click router to encapsulate and forward packets to a particular mobile host. Registrations with
home agents could not be done automatically as specified in the mobile IP standard.
For a spring semester project, I have added elements in Click to perform the task of home and
foreign agents in Click. Click configurations can use these elements, like any other Click elements, in Click
graphs. The added elements support a subset of the features required for home and foreign agents as
mandated by the current Internet standard - RFC 2002.
In this paper I provide a brief introduction to Click (section I), followed by a brief description of the
Mobile IP protocol as specified in the current Internet standard (section II). Subsequently I provide a
detailed description of the elements I have added, along with their proper use in Click configurations (section
III). This is followed by a description of a configuration used to test the functionality of the elements (section
IV). The following section summarizes the features implemented by the added elements followed by an
outline on what remains to be done, for enhancing these elements (section V). A brief note regarding related
work and some observations regarding Click in general and the agent elements in particular conclude the
paper (section VI). The code for the newly added elements and sample Click configurations using them are
included in the Appendix.
1. Introduction
Few projects have been done in the area of developing flexible routers. The most prominent one
amongst Click developed at MIT. Click is a modular, flexible and extensible router software architecture,
developed by Eddie Kohler and others, at the LCS, MIT [1,2]
While the need for developing extensible and modular routers is recognized when one considers the
varied configurations required for practical networks, it becomes critical in deveoping, testing and
deployment of new network protocols. However a formidable obstacle in the development of modular
sofware routers has been the demand for high-speed routers. Even fast software router implementations in
Linux, achieve less than 500,000 packets per second on commodity hardware. Major improvements in
speed can be achieved by modifying the interface driver to run in polling mode in contrast to the customary
interrupt-driven mode [1,2]
Click, with polling mode interface drivers can achieve 1.3 million packets/second on a P-III with the
Intel gigabit driver. Perhaps more important than its high speed forwarding is the ease of writing Click
configurations to perform highly specialized packet processing.
1.1
Click Elements
The fundemental unit of configurablity in Click is an element. Each element in Click performs specific
tasks. These elements are arranged in flow graphs specified in a Click configuration file to achieve an
aggregation of tasks to suit one’s particular needs.
Examples of elements include:
DecIPTTL, LookupIPRoute, ARPResponder, IPClassifier
All elements follow the Element class interface. Currently this interface and all other existing elements
are written in C++. Examples of methods in this interface include: configure, initialize, push, pull. The act of
passing a packet down to a downstream element corresponds to invoking that element object’s push()
method through a virtual function call. The ability to connect diverse elements in differing configurations
arises from the virtual function call invocation, mechanism of C++.
1.1.1 Ports
Each element has zero or more input and output ports. Sources of packets like FromDevice have no
input ports, while packet sinks like Discard and ToDevice have no ouptut ports. Typical elements have a
single input port and 2 output ports. Often the second output port is used to emit error packets, which are
then passed to ICMP elements to create ICMP error messages. Each port is exactly one of: PUSH, PULL
and AGNOSTIC. A single PUSH input and output port means the element will be handed a packet down
from the upstream element. This element cannot request a packet from the upstream element. A pull port
implies that the element downstream requests the packet. The ToDevice element has a single PULL input,
for instance, since it has to see when the outoing line is free and then request a packet from above and send
it on the wire. PUSH outputs can only be connect to PUSH (or AGNOSTIC) inputs. PULL elements are
analogous. AGNOSTIC ports can connect to either.
A Queue element has a single PUSH input and a single PULL output. This corresponds to the notion
that a queue must accept all packets handed down to it and continue to keep them until the element
downstream requests a packet.
1.2
Click graphs
The Click configuration file is a specification of a packet flow graph in the Click language. The
language is simple and very intutive. Various tools are supplied with the Click toolkit to check that these
configurations (graphs) satify certain properties. As an illustration, below is a specification for a router which
checks each IP packet and then prints its contents
FromDevice(eth0)->Strip(14)->CheckIPHeader->IPPRint(“eth0 : “)->Discard
For more complex configurations and details on Click, see the Click homepage and refer to [1, 2]
2. Mobile-IP protocol
Mobile nodes MUST be able to keep their IP address(es) to maintain existing transport connections.
However the exisiting IP routing infrastructure assumes that IP datagrams should be routed based on their
network prefix. An implemented solution is to establish a home agent who forwards IP datagrams meant for
a mobile host, to a care-of-address on the visited foreign network. The datagram to be forwarded is first
encapsulated in an IP packet using encapsulation techniques like IP-in-IP, GRE, minimal encapsulation, etc.
The care-of-address may be a foreign agent on the foreign network or the mobile host itself, if has means of
obtaining a valid IP address on the visited network (valid here means, it can be reached by traditional IP
routing mechanisms). The care-of-address should be viewed as the endpoint of the IP tunnel. At the care-ofaddress, the packet is decapsulated and the internal datagram is retrieved. Subsequently if the care-ofaddress is different from the mobile host (foreign agent is the endpoint of the tunnel), the packet is sent over
a link-layer connection to the mobile host.
Operationally the protocol can be dissected into 3 portions.
i) Agent advertisements and Solicitations
ii) Registrations and Replies
iii) Routing considerations
2.1 Agent Advertisements and Solicitations
RFC 2002 (the specification of the Internet mobile-IP standard) requires home and foreign
agents periodically generate agent advertisements and broadcast them over their agent interface.
Agent interface, now and hereafter, will be used to refer to the interface on the agent, which is
connected to the link on which it provides the serivices of an agent.
The advertisements are actually extensions, appended to existing ICMP router
advertisements. These advertisements must be sent to the all hosts on the link, multicast address 224.0.0.1 if the link supports multicast or the limited braodcast address 255.255.255.255, if it
doesn’t. The standard recommends time intervals at which these advertisements should be
generated. These advertisements also serve to let the mobile node know, on which network (home
or foreign) it is, currently.
A mobile host, when visiting a foreign network, or when it wishes to know the home agent
address, may generate a Solicitation message. The agent solicitation message is identical to the
ICMP Router Solicitation request, except it MUST have a TTL=1. This request is sent to the ‘all
routers on link’ multicast address - 224.0.0.2 On receiving a solicitation, an agent MUST generate
an advertisement and broadcast it (or unicast it to the node which requested it).
2.2 Registration and Replies
A mobile host on discovering itself to be on a foreign network attempts to create a binding
(forwarding entry) at the home (and foreign agent, if it is using one). Henceforth, the term foreign
agent will be used mean an “actual” foreign agent, or the mobile host if it is performing the task of
the foreign agent itself. The mobile host creates a Registration Request packet. This is a UDP
packet with a registration extentsion appended after the UDP header (as the payload). This packet
is delivered to the foreign agent by a link layer connection. It is assumed that the mobile host has
means to discover the foreign agent address (either through advertisements or through link layer
mechanisms such as DHCP). The foreign agent validates the request and relays it to the home
agent.
The home agent on receiving the request, validates it and creates a binding (or replaces an
exisiting binding). At this point it MUST send a gratuitous ARP (see Routing Considerations 2.3). It
then creates a Registration Reply (similar in form to the Registration Request) and sends it to the
foreign agent (source of the request). The foreign agent then relays the reply to the mobile host. At
this point the registration process is complete. It is important to note that each registration has an
associated lifetime and automatically expires after its lifetime. Hence a mobile host MUST
periodically re-register with the home agent (via the foreign agent).
2.3 Routing Considerations :
The home agent must ensure that it receives packets destined for the mobile host. To this
end, it must do proxy ARP replies on its agent interface for the mobile host and serve as the
incoming router for outside packets that are destined for the mobile host. On receiving an
acceptable regsitration request the home agent MUST send a (possibly more than one) gratuitous
ARPs on its agent interface.
The foreign agent should have a link layer connection with the mobile host (though other
configrations where this is not true may work). All packets sent by the foreign agent to the mobile
host must use a destination IP address that is the same as the mobile host’s home address. The
mobile host must provide ARP replies to queries for its home address while visiting a foreign
network.
3. Design
To succesfully implement the protocol, I created the following elements:
i) RouterAdvertise
ii) AgentAdvertise
iii) Home/Foreign Agent
Central to the creation of new elements was Click’s philosophy on the role of elements. Click builds on
idea of having small simple elements that do specific tasks. It is contrary to Click’s philosophy to create an
unweildy sophisticated element. Small elements encourage element re-use at the userlevel, while enherited
elements support code re-use at the programmer level. Further Click encourages elements to have different
ports to serve different flows, for two reasons:
i)
ii)
3.1
Saving some time, from packet classification at each element
Easier to use in flow graphs at the user level.
RouterAdvertise [Appendix A] :
This element was NOT strictly needed for the purpose of a mobile-IP implementation.
However in tune with Click’s philosophy and with a view to strengthening the base for Click (since
routers should create ICMP router advertisments and respond to solicitation requests), I felt it
worthwile to create this element. Furthermore the AgentAdvertise was created as a sub-class of the
RouterAdvertise class and a significant portion of the code was reused.
The element code and design is simple. Since router advertisements should be generated
both asynchronously and on receving a request, it became apparent that the element should have
an optional single push input and necessary single PUSH output. In a fully compliant implementation
of the RFC 1256 (the current router advertisement standard), the input should be connected so as to
receive solicitation requests. On receiving a valid request an ICMP router advertisement packet is
emitted on output 0. Irrespective of whether the input is connected (ie. whether a solictation request
is received), an advertisement is generated periodically (of the order of a minute apart by default)
and emitted on output 0.
Schematically the element would be connected as follows :
Router/Agent Advertisement
Element
ToDevice
EtherEncap
FromDevice Classifier
AgentAdvertisement
Queue
A sample Click configuration file [Appendix A] uses this element with reasonable arguments to
create ICMP packets and print them on the console. The output is connected with the EtherEncap element
to create a link level broadcast packet. This packet is then sent on the agent interface.
Since periodic messages must be generated, this element has code to pro-actively schedule itself at
intervals. This is in addition to any scheduling which done implicitly as a result of solicitation requests.
3.2
AgentAdvertise :
This is very similar to the RouterAdvertisement element. It differs only to the extent that the agent
advertisement fields must be filled (RFC 1256) appropriately and appended to the ICMP message.
As a consequence, it uses methods from the RouterAdvertise class. (AgentAdvertise is derived from
RouterAdvertise).
3.3
Agents [Appendix B, C]:
The design of these elements was non-trivial. Ultimately the following observations factored in the
final design :
The agents needed to receive packets directly from their resepective agent interfaces. The
foreign agent didn’t nessarily need to receive packets directly from the interface since packets sent
by the mobile host would have the correct IP addresses. Yet I felt it would be appropriate to connect
one port directly to the interface, in case of the foreign agent, to parallel the case for the home
agent. For the home agent a direct connection was a must, since it needed to receive packets for
the mobile host on the local link using proxy ARPs. Since I could not reconfigure other elements, in
an existing graph, this was the simplest way out. With this design, the foreign agent would receive
registration requests on this port.
The agents needed to have an output directly connected to their agent interface. In this case
the home agent needed to send proxy ARPs on this interface. The foreign agent needed to send link
layer messages to the mobile host. These messages would only get delivered if they were sent
direcltly to the mobile host by a link layer connection, and bypassed the traditional IP routing
mechanism. In this design the foreign agent sent registration replies and decapsulated packets to
the mobile host, while the home agent sent proxy and gratuitous arps on this port.
Both agents needed to receive a subset of the IP packets passing through the router. The
home agent needed to receive registration requests and IP packets destined for the mobile host.
The foreign agent needed to receive registration replies and encapsulated packets forwarded by the
home agent.
Home/Foreign Agent Element
To Classifier
1
FromDevice
eth1
IP
0
Strip
FromDevice
eth0
Classifier
1
ToDevice
eth1
2
0
Agent
LookUpIPRoute
ARPResponder
The above observations implied both agent elements would have :
Input 0 (PUSH) : To receive ALL IP packets passing through the the router.
Output 1 (PUSH) : To pass down IP packets which are not for the agent and also IP packets, the
agent generates. Simply put, all outgoing IP packets are sent on this port.
Input 1 (PUSH) : Link-layer packets received from the agent interface.
Output 1(PUSH) : Un-processed link layer packets emitted from this port
Output 2(PUSH) : For emitting link-layer packets on the agent interface.
Since the elements were in the forwarding path of the router, it was imperative that the
case when the packet was not destined for processing by the agent needed to be done fast. To this
end, an early check is introduced to tackle this case. Two comparisons and one virtual function call
is the only overhead of the agent elements for unprocessed elements(by the agents).
4. Test Configuration :
For purposes of verifying the minimal functionality of the elements added, the following network was
modelled in Click. The Click configuration file for this setup alongwith the run output generated by the router
are provided in Appendix C.
Schematic for agent.click
InfiniteSource
0(in)
1(in)
(out)0
InfiniteSource
F
H
1(out)
Discard
0(out)
2 (out)
0(in)
1(out)
Discard
2(out)
Print
Print
Discard
Discard
The InfiniteSource element creates an initial registration request. This element simply passes the
data specified in the configuration string of the element - in this case an Ethernet packet containing a
registration request. The element was configured to send the request exactly once. The output of the
InfiniteSource element is connected to the foreign agent element’s input 1 (which is to receive Ethernet
packets from the agent interface). On receiving the request, the foreign agent element processes the
request, and creates a temporary binding. Then it relays the request as an IP packet and pushes it down
output 0. Recall, that output 0, was used to send all outgoing (non-local) IP packets by both agents. In our
configuration the output 0, of the foreign agent is connected to the input 0 of the home agent (and vice
versa). On receiving the registration request, the home agent creates a new binding for the mobile host, with
the care-of-address of the foreign agent. Then a Registration Reply is created and emitted on output 0 of
the home agent. This port, is connected to input 0 of the foreign agent. The foreign agent recognizes the
Registration Reply, makes its temporary binding permanent and relays the reply to the mobile host by
creating an Ethernet packet with the link layer address set to that, of the mobile host. This packet is then
pushed down output 2 (the direct outgoing connection to the agent’s interface). At this point the registration
is complete.
In the test, at this stage another InfiniteSource is used to send a packet to the mobile host. This
packet is intercepted by the home agent (on input 0); encapsulated and pushed on output 0. The foreign
agent on receiving the encapsulated packet, locates an existing binding and emits it after decapsulation on
output 2.
Admittedly this test is not an actually conducted experiment. Yet, it captures the essence of the
mobile-IP functionality required for the agents. Click provides in this case, an ideal inexpensive but reliable
means to test the elements. The tests could be made comprehensive though, by incorporating stray IP
packets for forwarding and invalid requests and replies.
5. Implementation features and limitations :
As of consequence of limited time, only minimally functional mobile agents are created. Specifically,
these elements should only be viewed as a starting point for a more rigourous implementation, befitting
Click. These agents are NOT currently fully standard (RFC 2002) compliant and are woefully inadequate in
terms of request reply validations and error messages generation. The agent code (in the source files) is
annotated by comments which mention specifics regarding which features are missing and at which section
of the code, changes need to be made. The following is a brief summary of the limitations.







No authentication : RFC 2002 mandates minimally a keyed-MD5 authentication between the mobile
host and the home agent.
Simultaneous bindings unsupported : The standard doesn’t require simultaneous bindings.
Error responses not generated : The standard requires and in some case recommends ICMP and UDP
error messages in cases of unreachable home agents and invalid requests/replies.
Time-out of bindings not performed : This is REQUIRED by the standard.
Proxy and gratuitous ARPs by the home agent not generated : this is required by the standard, on
creation of a new binding.
The element code needs external documentation in form of man pages etc.
Speed optmizations need to be performed : Such as using hash container classes and reducing the
number of function calls to standard libraries.
6. Conclusions
6.1
Related Work :
Mobile-IP agent and host implementations exist for Solaris and Linux. The Linux implementation by
the MosquitoNet group at Berkeley provides enhancements to the protocol. More information regarding
the standards themselves can be found in the appropriate RFCs 2002, 1256 Details regarding Click and
the current release details can be found at the Click home page.
6.2
Final Observations :
Much needs to be done to complete this mobile agent implementation. It is important to evaluate
the cost of including these agents in the forwarding path of the router.
Click provides an elegant and easy to use platform for both developing implementations for new
protocols, as well as a higly configurable working router configuration. As of writing this paper, 1.2 was
the latest release. It provides SMP support in the form of multiple threads of execution within the kernel
module. In its current form, writing elements can be both fast and pleasurable.
Bibliography
1.
2.
3.
4.
Click - TOCS ’00 paper (ACM Transactions on Computer Systems 18(3), August 2000, pages 263-297).
Eddie Kohler's thesis -This has more detail and examples of using Click than the TOCS paper
IP Mobility Support – RFC 2002
ICMP Router Discovery Messages – RFC 1256
Appendix A
RouterAdvertisement Element Code
/*
* Element periodically creates ICMP Router Discovery Advertisements and pushes
* them on output 0. Can additionally also accept solicitation requests
* on input 0.
* Copyright (c) 2000-2001 University of Utah
*
* 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 following
* conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Further elaboration of this license, including a DISCLAIMER OF ANY
* WARRANTY, EXPRESS OR IMPLIED, is provided in the LICENSE file, which is
* also accessible at http://www.pdos.lcs.mit.edu/click/license.html
*/
#include <iostream.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <click/config.h>
#include <click/package.hh>
#include "routeradvertise.hh"
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/glue.hh>
#include <click/click_ip.h>
#include <click/click_icmp.h>
#include <click/packet_anno.hh>
RouterAdvertise::RouterAdvertise()
: Element(0, 1),
_max_interval(600),
_id(1),
_timer(this)
{
MOD_INC_USE_COUNT;
}
RouterAdvertise::~RouterAdvertise()
{
MOD_DEC_USE_COUNT;
}
RouterAdvertise *
RouterAdvertise::clone() const
{
return new RouterAdvertise;
}
void
RouterAdvertise::notify_ninputs(int i)
{
if (i)
add_input();
return ;
}
int
RouterAdvertise::configure(const Vector<String> &conf, ErrorHandler *errh)
{
Vector<String> rest_conf ;
unsigned int tlife = 0 ;
unsigned int tmin = 0 ; /* temporaries */
int before = errh->nerrors();
for (int i = 0; i < conf.size(); i++) {
IPAddress rip ;
int pref ;
Vector<String> words;
cp_spacevec(conf[i], words);
if (words.size() == 2) {
if (cp_ip_address(words[0], &rip, this) && cp_integer(words[1],
&pref)) {
_ip_pref_t
*ip_pref = new _ip_pref_t ;
ip_pref->ip = rip ;
ip_pref->pref = pref ;
_router_pref.push_back(ip_pref);
}
else
errh->error("argument %d, in incorrect format : should be IPADDR
Preference", i);
}
else {
// finished
processing address preference pairs
for (int j = i ; j < conf.size() ; j++)
rest_conf.push_back(conf[j]);
break ;
}
}
if (cp_va_parse(rest_conf, this, errh,
cpIPAddress, "source address for adverisements", &_src_ip,
cpIPAddress, "Advertisement IP address - multicast/briadcast
address of interface", &_dst_ip,
cpOptional,
cpKeywords,
"LIFE", cpUnsigned, "lifetime (in seconds)", &tlife,
"MAX", cpUnsigned, "max. interval (in seconds)",
&_max_interval,
"MIN", cpUnsigned, "min. interval (in seconds)", &tmin,
0) < 0)
errh->error("Arguments given incorrectly");
if (_max_interval > 1800 || _max_interval < 4)
errh->error("max. interval should lie between 4 and 1800 (refer RFC.
1256)");
// default values for these (RFC 1256)
_min_interval = static_cast <unsigned int> (0.75 * _max_interval);
_life = 3 * _max_interval ;
if (tmin)
_min_interval = tmin ;
if (tlife)
_life = tlife ;
if (_min_interval > _max_interval || _min_interval < 3)
errh->error("min. interval should lie between 3 and MAX_INTERVAL (%d)
(refer RFC. 1256)", _max_interval);
if (_life > 9000 || _life < _max_interval )
errh->error("LIFE should lie between MAX_INTERVAL (%d) and 9000s (refer
RFC. 1256)", _max_interval);
return (before==errh->nerrors() ? 0 : -1);
}
int
RouterAdvertise::initialize(ErrorHandler *)
{
// technically, this should be randomized uniformly within the
// the interval [_min_interval, _max_interval] - see RFC 1256
if (_max_interval > _min_interval)
_interval = _min_interval + static_cast <unsigned int>(random() %
(_max_interval-_min_interval+1));
else
_interval = _max_interval ;
for (int i=0 ; i< _router_pref.size() ; i++)
cout << _router_pref[i]->ip.s().mutable_c_str() << "(" <<
_router_pref[i]->pref << ")" << endl ;
cout << "lifetime=" << _life << "\t" << "max=" << _max_interval << "\t" <<
"min=" << _min_interval << endl ;
cout << "src=" << _src_ip.s().mutable_c_str() << "\t" << "dst=" <<
_dst_ip.s().mutable_c_str() << endl ;
_timer.attach(this);
_timer.schedule_after_ms(_interval*1000);
return 0;
}
void
RouterAdvertise::uninitialize()
{
_timer.unschedule();
}
void
RouterAdvertise::run_scheduled()
{
WritablePacket *q = Packet::make(sizeof(click_ip) +
sizeof(struct icmp_router_advertisement) +
_router_pref.size()*8);
memset(q->data(), '\0', q->length());
click_ip *nip = reinterpret_cast<click_ip *>(q->data());
nip->ip_v = 4;
nip->ip_hl = sizeof(click_ip) >> 2;
nip->ip_len = htons(q->length());
nip->ip_id = htons(_id++);
nip->ip_p = IP_PROTO_ICMP; /* icmp */
nip->ip_ttl = 1;
/* all advertisements have TTL 1
(RFC 1256) */
nip->ip_src = _src_ip;
nip->ip_dst = _dst_ip;
nip->ip_sum = in_cksum((unsigned char *)nip, sizeof(click_ip));
struct icmp_router_advertisement *icp = (struct icmp_router_advertisement *)
(nip + 1);
icp->icmp_type = ICMP_ROUTER_ADVERTISEMENT;
icp->icmp_code = 0;
icp->num_addrs = _router_pref.size();
icp->addr_entry_size = 2 ;
/* size of each pair : RFC
1256 */
icp->lifetime = htons(_life);
// stuff in the router:pref pairs
_ip_pref_t *rpref = reinterpret_cast<_ip_pref_t *> (icp+1);
for (int i = 0 ; i < _router_pref.size() ; i++) {
rpref->ip
= _router_pref[i]->ip ;
rpref->pref = htonl(_router_pref[i]->pref) ;
rpref++ ;
}
icp->icmp_cksum = in_cksum((unsigned char *)icp,
(sizeof(struct
icmp_router_advertisement) + _router_pref.size()));
q->set_dst_ip_anno(IPAddress(_dst_ip));
q->set_ip_header(nip, sizeof(click_ip));
output(0).push(q);
// generate a random interval
if (_max_interval > _min_interval)
_interval = _min_interval + static_cast <unsigned int>(random() %
(_max_interval-_min_interval+1));
else
_interval = _max_interval ;
_timer.schedule_after_ms(_interval*1000);
}
// Actually we should be checking, that this is a valid solicitation
void
RouterAdvertise::push(int, Packet *p)
{
if (p) p->kill();
_timer.unschedule();
this->run_scheduled();
return ;
}
EXPORT_ELEMENT(RouterAdvertise)
#ifndef ROUTERADVERTISE_HH
#define ROUTERADVERTISE_HH
#include <click/element.hh>
#include <click/timer.hh>
class RouterAdvertise : public Element {
typedef struct {
IPAddress ip ;
int pref ;
} _ip_pref_t ;
Vector <_ip_pref_t *>_router_pref ;
protected :
unsigned int _max_interval;
unsigned int _min_interval;
unsigned int _life ;
unsigned int _interval ;
unsigned int _id ;
IPAddress _src_ip ;
IPAddress _dst_ip ;
Timer _timer;
public:
RouterAdvertise();
~RouterAdvertise();
const char *class_name() const
const char *processing() const
{ return "RouterAdvertise"; }
{ return PUSH; }
RouterAdvertise *clone() const;
void notify_ninputs(int);
int configure(const Vector<String> &, ErrorHandler *);
int initialize(ErrorHandler *);
void uninitialize();
void run_scheduled();
void push(int, Packet*);
};
#endif
AgentAdvertise Element Code
/*
* agentadvertise.cc
*
* Element periodically emits agent advertisements on output 0. Additionally
* It can also accept solicitations on input 0
*
* Copyright (c) 2000-2001 University of Utah
*
* 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 following
* conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Further elaboration of this license, including a DISCLAIMER OF ANY
* WARRANTY, EXPRESS OR IMPLIED, is provided in the LICENSE file, which is
* also accessible at http://www.pdos.lcs.mit.edu/click/license.html
*/
#include <iostream.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <click/config.h>
#include <click/package.hh>
#include "agentadvertise.hh"
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/glue.hh>
#include <click/click_ip.h>
#include <click/click_icmp.h>
#include <click/packet_anno.hh>
#include <click/ipaddressset.hh>
AgentAdvertise::AgentAdvertise()
: RouterAdvertise(),
_reg_life(0xffff),
_encap(IP_in_IP),
_pad(true),
_router(true),
_seq(0),
_reg_req(false)
{
MOD_INC_USE_COUNT;
}
AgentAdvertise::~AgentAdvertise()
{
MOD_DEC_USE_COUNT;
}
/* infinity - RFC 2002 */
AgentAdvertise *
AgentAdvertise::clone() const
{
return new AgentAdvertise;
}
int
AgentAdvertise::configure(const Vector<String> &conf, ErrorHandler *errh)
{
String agent, encap ;
IPAddressSet care_set ;
unsigned int tlife = 0 ;
unsigned int tmin = 0 ; /* temporaries */
int before = errh->nerrors();
if (cp_va_parse(conf, this, errh,
cpWord, "HOME/FOREIGN (agent)", &agent,
cpIPAddress, "source address for adverisements", &_src_ip,
cpIPAddress, "Advertisement IP address - multicast/briadcast
address of interface", &_dst_ip,
cpIPAddressSet, "one or more care-of-addresses, in case of
foreign agents ONLY\n"
"In case of home agents give 0.0.0.0", &care_set,
cpOptional,
cpKeywords,
"REG_LIFE", cpUnsigned, "registration lifetime (in
seconds)", &_reg_life,
"REG_REQ", cpBool, "registration required ? in case of
foreign agents ONLY", &_reg_req,
"ENCAP", cpWord, "MINIMAL/GRE encapsulation of tunelled
packets", &encap,
"PAD", cpBool, "pad ? (to even bytes for ICMP message)",
&_pad,
"DEFAULT_ROUTER", cpBool, "can the agent be used as a
default router ?", &_router,
"ADV_LIFE", cpUnsigned, "advertisement lifetime (in
seconds)", &tlife,
"MAX", cpUnsigned, "max. interval (in seconds)",
&_max_interval,
"MIN", cpUnsigned, "min. interval (in seconds)", &tmin,
0) < 0)
errh->error("Arguments given incorrectly");
// set values for ICMP Router advertisement portion
if (_max_interval > 1800 || _max_interval < 4)
errh->error("max. interval should lie between 4 and 1800 (refer RFC.
2002)");
// default values for these (RFC 2002)
_min_interval = static_cast <unsigned int> (0.75 * _max_interval);
_life = 3 * _max_interval ;
if (tmin)
_min_interval = tmin ;
if (tlife)
_life = tlife ;
if (_min_interval > _max_interval || _min_interval < 3)
errh->error("min. interval should lie between 3 and MAX_INTERVAL (%d)
(refer RFC. 2002)", _max_interval);
if (_life > 9000 || _life < _max_interval )
errh->error("LIFE should lie between MAX_INTERVAL (%d) and 9000s (refer
RFC. 2002)", _max_interval);
/* agent advertisement portion */
if (agent.upper() == "HOME")
_agent = HOME ;
else if (agent.upper() == "FOREIGN")
_agent = FOREIGN ;
else errh->error("Agent should either be HOME or FOREIGN");
if (_agent == FOREIGN) {
if (!care_set.size())
errh->error("Foreign agents MUST have one or more care-ofaddresses");
else {
_care_of_addrs = care_set.list_copy();
_num_care_of_addrs = care_set.size();
}
}
if (_agent == HOME) {
if (_reg_req)
errh->error("REG_REQD is ONLY for foreign agents");
if (care_set.size() > 1)
errh->error("care-of-addresses are ONLY for foreign agents, apart
from 0.0.0.0");
_care_of_addrs = NULL ;
_num_care_of_addrs = 0;
}
if (encap.upper() == "GRE")
_encap = GRE ;
else if (encap.upper() == "MINIMAL")
_encap = MINIMAL ;
return (before==errh->nerrors() ? 0 : -1);
}
int
AgentAdvertise::initialize(ErrorHandler *)
{
// technically, this should be randomized uniformly within the
// the interval [_min_interval, _max_interval] - see RFC 1256
if (_max_interval > _min_interval)
_interval = _min_interval + static_cast <unsigned int>(random() %
(_max_interval-_min_interval+1));
else
_interval = _max_interval ;
_timer.attach(this);
_timer.schedule_after_ms(_interval*1000);
return 0;
}
void
AgentAdvertise::uninitialize()
{
_timer.unschedule();
}
void
AgentAdvertise::run_scheduled()
{
WritablePacket *q = Packet::make(sizeof(click_ip) +
sizeof(struct icmp_router_advertisement) +
sizeof(agent_adv_ext_t) +
_num_care_of_addrs*4);
memset(q->data(), '\0', q->length());
/* IP fields */
click_ip *nip = reinterpret_cast<click_ip *>(q->data());
nip->ip_v = 4;
nip->ip_hl = sizeof(click_ip) >> 2;
nip->ip_len = htons(q->length());
nip->ip_id = htons(_id++);
nip->ip_p = IP_PROTO_ICMP; /* icmp */
nip->ip_ttl = 1;
/* all advertisements have TTL 1
(RFC 2002) */
nip->ip_src = _src_ip;
nip->ip_dst = _dst_ip;
nip->ip_sum = in_cksum((unsigned char *)nip, sizeof(click_ip));
/* ICMP router advertisement fields */
struct icmp_router_advertisement *icp = reinterpret_cast <struct
icmp_router_advertisement *> (nip + 1);
icp->icmp_type = ICMP_ROUTER_ADVERTISEMENT;
if (_router)
icp->icmp_code = 0;
else
icp->icmp_code = 16;
/* we could have added router addresses, see RFC 2002 */
icp->num_addrs = 0;
icp->addr_entry_size = 2 ;
/* size of each pair : RFC
1256 */
icp->lifetime = htons(_life) ;
/* Agent advertisement extension fields : RFC 2002 */
agent_adv_ext_t *ext = reinterpret_cast <agent_adv_ext_t *> (icp+1);
ext->type
= 16 ;
ext->length = 6 + 4*_num_care_of_addrs ;
ext->seq
= htons(_seq) ;
if (_seq == 0xffff)
different from boot time */
_seq = 256 ;
else
_seq++ ;
ext->lifetime = htons(_reg_life);
ext->req
= _reg_req ;
ext->busy
= 0;
ext->home
= (_agent==HOME ? 1 : 0);
ext->foreign = (_agent==FOREIGN ? 1:0);
ext->minimal = (_encap==MINIMAL);
ext->gre
= (_encap==GRE);
ext->vj
= 0;
enabled */
ext->reserved = 0;
uint *addr = reinterpret_cast <uint *> (ext+1);
for (int i=0; i<_num_care_of_addrs ; i++)
*(addr++) = _care_of_addrs[i];
/* after roll-over,
/* this could be
/* now compute the ICMP checksum */
icp->icmp_cksum =
in_cksum((unsigned char *)icp,
(sizeof(struct icmp_router_advertisement)) +
(sizeof(agent_adv_ext_t)) +
_num_care_of_addrs*4);
q->set_dst_ip_anno(IPAddress(_dst_ip));
q->set_ip_header(nip, sizeof(click_ip));
output(0).push(q);
// generate a random interval
if (_max_interval > _min_interval)
_interval = _min_interval + static_cast <unsigned int>(random() %
(_max_interval-_min_interval+1));
else
_interval = _max_interval ;
_timer.schedule_after_ms(_interval*1000);
}
// Actually we should be checking, that this is a valid solicitation
void
AgentAdvertise::push(int, Packet *p)
{
if (p) p->kill();
_timer.unschedule();
this->run_scheduled();
return ;
}
EXPORT_ELEMENT(AgentAdvertise)
/* agentadvertise.hh */
#ifndef AGENTADVERTISE_HH
#define AGENTADVERTISE_HH
#include <click/element.hh>
#include <click/timer.hh>
#include "routeradvertise.hh"
class AgentAdvertise : public RouterAdvertise {
private :
typedef enum {
HOME, FOREIGN
} agent_t ;
typedef enum {
IP_in_IP, MINIMAL, GRE
} encap_t ;
typedef struct {
unsigned char type ;
unsigned char length ;
unsigned short seq ;
unsigned short lifetime ;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned char req:1 ;
/* registration required */
unsigned char busy:1 ;
unsigned char home:1;
unsigned char foreign:1;
unsigned char minimal:1;
/* encapsulation */
unsigned char gre:1;
unsigned char vj:1;
/* Van Jacobson compression */
unsigned char fill:1;
/* 0 */
#else
unsigned char fill:1;
/* 0 */
unsigned char vj:1;
/* Van Jacobson compression */
unsigned char gre:1;
unsigned char minimal:1;
/* encapsulation */
unsigned char foreign:1;
unsigned char home:1;
unsigned char busy:1 ;
unsigned char req:1 ;
/* registration required */
#endif
unsigned char reserved ; /* 0 */
/* zero or more care-of-addresses follow */
} agent_adv_ext_t ;
agent_t _agent ;
ushort _reg_life ;
encap_t _encap ;
bool _pad ;
bool _router ;
unsigned short _seq ;
/* used only for foreign agents */
/* default router ? */
/* agent advertisement number */
uint *_care_of_addrs ;
ushort _num_care_of_addrs ;
bool _reg_req ;
public:
AgentAdvertise();
~AgentAdvertise();
const char *class_name() const
const char *processing() const
{ return "AgentAdvertise"; }
{ return PUSH; }
AgentAdvertise *clone() const;
int configure(const Vector<String> &, ErrorHandler *);
int initialize(ErrorHandler *);
void uninitialize();
void run_scheduled();
void push(int, Packet*);
};
#endif
Sample Click Configuration File Using Advertisements
/* adv.click */
/*
RouterAdvertise(192.168.123.116 255,
10.0.0.31 65535,
192.168.123.116,
224.0.0.1,
MAX=10,
LIFE=100,
MIN=3)
*/
AgentAdvertise(
HOME,
192.168.123.116,
224.0.0.1,
0.0.0.0,
REG_LIFE=255,
MAX=5,
ENCAP=GRE,
DEFAULT_ROUTER=false,
MIN=5 )
->IPPrint("Adv", CONTENTS=hex, ID=true)
->Discard;
Appendix B
HomeAgent Element Code
/*
* homeagent.cc
*
* HomeAgent implements a mobile home agent.
* Expects IP packets on input 0 and Ethernet frames from agent interface on
input 1
* Emits unprocessed and newly created IP packets on output 0
* Emits unprocessed Ethernet frames from input 1, on output
* Creates Proxy and Gratuitous ARPs on output 1
*
* Copyright (c) 2000-2001 University of Utah
*
* 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 following
* conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Further elaboration of this license, including a DISCLAIMER OF ANY
* WARRANTY, EXPRESS OR IMPLIED, is provided in the LICENSE file, which is
* also accessible at http://www.pdos.lcs.mit.edu/click/license.html
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <click/config.h>
#include <click/package.hh>
#include <click/ipaddress.hh>
#include <click/ipaddressset.hh>
#include <click/etheraddress.hh>
#include <click/click_ether.h>
#include <click/click_ip.h>
#include <click/click_udp.h>
#include "homeagent.hh"
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/glue.hh>
#include "elements/standard/alignmentinfo.hh"
#ifdef __KERNEL__
# include <net/checksum.h>
#endif
#include <iostream>
// input 0 - IP packets from the outside world
// input 1 - Ethernet packets from the interface, where we are a home agent
// output 0 - IP packets created by us, and ALSO those passed from above
// output 1 - Ethernet packets from the home agent interface, which we
//
don't process
// output 2 - Proxy/gratuitous ARPs sent on this interface
//
// Limitations :
//
Only IP-in-IP encapsulation supported for the time being (Not a MUST)
//
VJ header compression unsupported (not a MUST)
//
Mobile-Home auth. not performed - keyed-MD5 (MUST)
//
No response sent to mobile node/foreign agent
//
denying the registration request (for whatever ground) (SHOULD/MUST)
//
No Home-Foreign auth. supported (not a MUST)
// Dynamic Home Agent resolution not supported (MAY)
// Multiple simultaneous bindings not supported
// Do not check if the packet is a mis-routed packet
//
sent by the foreign agent. In such a case the packet
//
will be an encapsulated one with the outer IP dst
//
address == inner dst address == mobile node's home address
// Broadcast packets not forwarded (SHOULD)
//
//
//
//
//
//
//
//
//
//
//
Misc. things TO DO (NOW)
Set timer to expire bindings - both requested ones and ones
which have been setup (MUST)
Make it possible to specify the list of IPs which can
register with us, using a mask.
Gratuitous ARP to be performed (MUST), for successful
registrations AND deregistrations (sender link layer
address should be set to our agent interface link address)
The ARPs must be broadcast over the local link
and SHOULD be retransmitted a small number of times
Proxy ARP MUST be performed
const int HomeAgent::UDP_DST_PORT = 434 ;
HomeAgent::HomeAgent()
: Element(2, 3),
_reg_ips(NULL), _n_reg_ips(0),
_our_ips(NULL), _n_our_ips(0),
_life_max(1800),
_check_reg_ips(true), _verbose(false)
{
MOD_INC_USE_COUNT;
}
HomeAgent::~HomeAgent()
{
MOD_DEC_USE_COUNT;
delete [] _reg_ips ;
delete [] _our_ips ;
for (int i=0; i<_mh_list.size(); i++)
delete [] _mh_list[i];
}
HomeAgent *
HomeAgent::clone() const
{
// RFC 2002
return new HomeAgent;
}
// Add arguments to filter out IP/masks and/or accept IP/masks
//
for registration requests
int
HomeAgent::configure(const Vector<String> &conf, ErrorHandler *errh)
{
int before = errh->nerrors();
if (cp_va_parse
(conf, this, errh,
cpIPAddressSet, "Acceptable mobile IP addresses", &_reg_ipsset,
cpIPAddress, "outgoing IP address (IP src field)", &_canonical_out_ip,
cpIPAddress, "IP address for agent interface", &_agent_ip,
cpEthernetAddress, "ethernet for agent interface", &_agent_ether,
cpOptional,
cpIPAddressSet, "Our unicast addresses", &_our_ipsset,
cpKeywords,
"LIFE", cpUnsigned, "max. registration lifetime(in seconds)",&_life_max,
"VERBOSE", cpBool, "display what's going on ?", &_verbose,
0) < 0)
return -1;
_n_reg_ips = _reg_ipsset.size();
_reg_ips
= _reg_ipsset.list_copy();
if (_n_reg_ips==1 && !_reg_ips[0])
_check_reg_ips = false ;
if (!_canonical_out_ip)
errh->error("Outgoing IP cannot be 0.0.0.0 !!!");
if (!_agent_ip)
errh->error("Agent IP cannot be 0.0.0.0 !!!");
if (!_agent_ether)
errh->error("Agent ethernet address cannot be 00:00:00:00:00:00 !!!");
// make sure our canonical outgoing IP is in this
if (!_our_ipsset.contains(_canonical_out_ip))
_our_ipsset.insert(_canonical_out_ip);
_n_our_ips = _our_ipsset.size();
_our_ips
= _our_ipsset.list_copy();
return (errh->nerrors() == before ? 0 : -1);
}
int
HomeAgent::initialize(ErrorHandler *)
{
print_config();
return 0;
}
// IP packtes and registration requests (UDP )
// arive on input port 0. Other IP packets also come from here
// and those MUST be passed down on output port 0, ASAP.
//
// de-registration (and possibly other) Ethernet packet arrive on input port 1
// Those of these which are destined for the mobile host MUST be forwarded
void
HomeAgent::push(int port, Packet *p)
{
bool for_us = false ;
// could be a request/some passing packet
bool for_mh = false ;
// for mobile host
click_ip *ip ;
click_ether *ether;
// packet destination
switch (port) {
case 0 :
// Only IP packets come here
ip = reinterpret_cast <click_ip *>(p->data());
// is the packet for us ?
for_us = _our_ipsset.contains(IPAddress(ip->ip_dst));
for_mh = _mobile_ipsset.contains(IPAddress(ip->ip_dst));
// If it isn't for us, just forward it.
if (!for_us && !for_mh) break ;
if (for_mh) {
mk_ipip(p);
return ;
}
if (for_us && ip->ip_p == IP_PROTO_UDP) {
click_udp *udp = reinterpret_cast <click_udp *>(ip+1);
if (udp->uh_dport == htons(UDP_DST_PORT)) {
handle_request(p);
return ;
}
}
break ;
case 1 :
// Following packets (ONLY Ethernet packets) come here :
// a) packets to be forwarded to the MH
// b) de-registration requests by MH
// c) passing packets to be sent on output(1)
// For (a) and (b), we strip the header and handle as for case `0'
ether = reinterpret_cast <click_ether *> (p->data());
// is it an IPv4 packet ?
if (ether->ether_type != htons(ETHERTYPE_IP))
goto PUSH_ETH ;
ip = reinterpret_cast <click_ip *>(ether+1);
for_us = _our_ipsset.contains(IPAddress(ip->ip_dst));
for_mh = _mobile_ipsset.contains(IPAddress(ip->ip_dst));
// If it isn't for us, just forward it.
if (!for_us && !for_mh)
goto PUSH_ETH ;
if (for_mh) {
// strip the ethernet header
p->pull(14);
mk_ipip(p);
return ;
}
if (for_us && ip->ip_p == IP_PROTO_UDP) {
click_udp *udp = reinterpret_cast <click_udp *>(ip+1);
if (udp->uh_dport == htons(UDP_DST_PORT)) {
// ALL packets sent to this port are ASSUMED to
// be registration requests - see Assigned Numbers (rfc 790)
// strip ethernet header
p->pull(14);
handle_request(p);
return ;
}
}
PUSH_ETH :
// If control reaches here, then it is an Ethernet packet, but
// not for us
cerr << "Ethernet packet, but not for us. Forwarding it" << endl;
output(1).push(p);
return ;
} // switch
// if the packet comes till here, means it isn't a packet for us
cerr << "forwarding IP packet - ain't for us" << endl ;
output(0).push(p);
return ;
}
/************************ Private Methods ***************************/
/********************************************************************/
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
If care-of-address == home_address of mobile node and lifetime==0
delete ALL bindings of this host
If care-of-address != home address and lifetime==0 then only delete
the specific entry
If the lifetime!=0, then add new entry (/replace old entries)
Currently we don't support simultaneous bindings, so we SHOULD
generate a successful reply with code=1
If an old entry is being replaced, DON'T send a (de-)registration
message to the earlier foreign agent. The RFC allows a message
of this sort to be sent, only if we share security information
with the foreign agent
If the lifetime requested than our maximum permissible, send
a successful reply with a lifetime set to our maximum
If the registration is a duplicate (home_addr, cof, id match),
then we MUST not extend the lifetime
New bindings require that the ARP procedures MUST be followed
// MUST generate a reply in the above cases
// Registration replies :
// -------------------// IP src : Copied from IP dst of request, provided it is not
//
not a broadcast/multicast address. In such a case
//
set it to our unicast address
//
NOTE : right now we are using our canonical outgoing IP
//
since we don't want to check if the address
//
is unicast/multicast
// IP dst : Copied from IP src of request
//
If the mobile host has returned to his home network,
//
then the de-registering request will have the IP src
//
field set, to the home address of the mobile host
//
In such a case the reply must be sent directly on the
//
home network and all bindings MUST be ignored.
//
Even if request is rejected, the reject message MUST
//
ignore the binding
// UDP src : Copied from UDP dst of request
// UDP dst : Copied from UDP src of request
// Lifetime : Copied from request, unless it is greater than our max.
// Home Address : Copied from request
// Home Agent : Copied from request, unless it is a multicast address,
//
in which case the request is rejected
// MUST Re-do the UDP checksum calculation since we modify the UDP
//
source port
// Expects an IP packet to UDP port 434
void
HomeAgent::handle_request(Packet *p)
{
click_ip *ip
= reinterpret_cast <click_ip *>(p->data());
click_udp *udp = reinterpret_cast <click_udp *>(ip+1);
reg_req_t *req = reinterpret_cast <reg_req_t *>(udp+1);
if (validate_req(p) <0) return ;
// control reaches here only if this is a valid registration request
if (_verbose) {
click_chatter("Received the following REGISTRATION REQUEST");
dump_packet(p, IP_T);
}
// if we supported multiple bindings the we'd also need
// to pass the cof_addr to get_entry()
mh_entry_t *mh = get_entry(req->home_addr);
if (mh) {
if (_verbose)
click_chatter("(H) : Existing entry found : %s -> %s, life=%d",
IPAddress(mh->home_addr).s().mutable_c_str(),
IPAddress(mh->cof_addr).s().mutable_c_str(),
mh->life);
// this could be one of 3 requests
// a) de-registering
// b) re-registering to renew lifetime
// c) change of care-of-address
// De-registering
if (req->lifetime==0 &&
((IPAddress(req->cof_addr))==mh->cof_addr
|| (IPAddress(req->cof_addr)==mh->home_addr))) {
// MUST send gratuitous ARP here !!
// remove the binding
remove_entry(mh->home_addr);
_mobile_ipsset.remove(mh->home_addr);
if (_verbose)
click_chatter("(H) : Request to de-register : REMOVED binding\n"
"%s->%s DEAD !!!",
IPAddress(mh->home_addr).s().mutable_c_str(),
IPAddress(mh->cof_addr).s().mutable_c_str());
goto PUSH_REPLY ;
}
// renewing life
if ((req->lifetime>0) && (IPAddress(req->cof_addr) == mh->cof_addr)) {
mh->life = min(_life_max, ntohs(req->lifetime));
if (_verbose)
click_chatter("(H) : Re-registering : %s->%s | Lifetime set to %d",
IPAddress(mh->home_addr).s().mutable_c_str(),
IPAddress(mh->cof_addr).s().mutable_c_str(),
mh->life);
goto PUSH_REPLY ;
}
// replacing entry
if ((req->lifetime>0) && (IPAddress(req->cof_addr) != mh->cof_addr)) {
mh->life = min(_life_max, ntohs(req->lifetime));
mh->cof_addr = req->cof_addr ;
if (_verbose)
click_chatter("(H) : Changed binding : %s->%s (new) | Life = %d",
IPAddress(mh->home_addr).s().mutable_c_str(),
IPAddress(mh->cof_addr).s().mutable_c_str(),
mh->life);
goto PUSH_REPLY ;
}
}
else {
/* new binding needs to be created */
mh = new mh_entry_t ;
mh->life = min(_life_max, ntohs(req->lifetime));
mh->home_addr = req->home_addr ;
mh->cof_addr = req->cof_addr ;
_mobile_ipsset.insert(mh->home_addr);
mh->id = req->id ;
_mh_list.push_back(mh);
if (_verbose)
click_chatter("(H) : Created NEW binding : %s->%s | Life = %d",
IPAddress(mh->home_addr).s().mutable_c_str(),
IPAddress(mh->cof_addr).s().mutable_c_str(),
mh->life);
// Send gratuitous ARP here !!!
// send packet ...
}
PUSH_REPLY :
// send the reply
u_short tport = udp->uh_dport ;
udp->uh_dport = udp->uh_sport ;
udp->uh_sport = tport ;
// MUST recompute the UDP checksum !
ip->ip_dst = ip->ip_src ;
ip->ip_src = _canonical_out_ip ;
ip->ip_ttl = (ip->ip_ttl < 5 ? 64 : ip->ip_ttl-1);
// ip->ip_len unchanged
ip->ip_sum = 0;
ip->ip_sum = in_cksum((u_char *)ip, sizeof(click_ip));
p->clear_annotations();
p->set_dst_ip_anno(IPAddress(ip->ip_dst)) ;
if (_verbose) {
click_chatter("(H) : Sending the following registration REPLY");
dump_packet(p, IP_T);
}
output(0).push(p);
return ;
}
// expects IP-in-IP encapsulated packets
// ip_len
void
HomeAgent::mk_ipip(Packet *p) const
{
if (validate_ipip(p) <0) return ;
if (_verbose) {
click_chatter("(H) : Received the following packet to be forwarded to
MH");
dump_packet(p, IP_T);
}
click_ip *ip = reinterpret_cast <click_ip *> (p->data());
mh_entry_t *mh = get_entry(IPAddress(ip->ip_dst));
assert(mh);
if (_verbose)
click_chatter("(H) : Using binding to encapsulate: %s -> %s",
IPAddress(mh->home_addr).s().mutable_c_str(),
IPAddress(mh->cof_addr).s().mutable_c_str());
// wrap in an IP packet
WritablePacket *q = Packet::make(sizeof(click_ip) + p->length());
memcpy((q->data()+sizeof(click_ip)), p->data(), p->length());
ip = reinterpret_cast <click_ip *> (q->data());
ip->ip_dst = mh->cof_addr ;
ip->ip_src = _canonical_out_ip ;
ip->ip_p
= IP_PROTO_IPIP ;
ip->ip_ttl = 255 ;
ip->ip_tos = 0;
ip->ip_len = htons(p->length()+sizeof(click_ip));
ip->ip_off = 0;
ip->ip_sum = 0;
ip->ip_sum = in_cksum((u_char *)ip, sizeof(click_ip));
q->set_dst_ip_anno(mh->cof_addr);
p->kill();
if (_verbose) {
click_chatter("(H) : Sending the following packet AFTER encapsulation");
dump_packet(q, IPIP_T);
}
// send the packet on our agent inteface
output(0).push(q);
return ;
}
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Silently discard, if non-zero UDP checksum
Check the Mobile-Home authentication. Rejects SHOULD generate replies
with code 131
Validate the `id' using the SPI field. Rejects SHOULD generate
replies with code 133
If Foreign-Home authentication is supported and fails, reply with 132
If the request is to the subnet broadcast address, reply with 136
AND our unicast address - see dynamic agent resolution, RFC 2002
Until we support, multiple simultaneous bindings, any requests
with the `S' bit set, should make us send the REPLY with code 1
Is it within our ACCEPT set ?
Destination UDP port == 434 ?
Deny request if :
i) Requested lifetime too long (denial contains the acceptable value, 69)
ii) poorly formed request/reply
iii) Requested encapsulation/compression unavailable
v) Non-zero reserved field (return status code 70)
The registration fields from the original request must be copied.
IP source address for denials, is copied from the request(destination)
IP dest address for denials, is copied from the request(src)
UDP source port for denials is 434
UDP dest port for denials, is the src UDP port of request
For co-located COF, the IP source address MUST be the COF
Otherwise the IP source address MUST be the home address
The link layer destination address MUST be the agent's unicast address
//
//
//
//
//
//
//
IP destination address is either agent's interface IP address/224.0.0.11
If IP destination address is 224.0.0.11 then TTL MUST be 1.
`D' bit set iff a co-located COF address is used.
Requested lifetime, MUST not exceed that, which was advertised by the agent
Encapsulation MUST be supported.
Type MUST be 1
int validate_req(Packet *p);
// Silently discard if low-order 32-bits of `id' don't match
// UDP destination, should match the outgoing port the request
//
was relayed from
// reply->type == 3 (for Registration Reply)
// Act upon the denial codes
// Discard, if invalid non-zero UDP checksum
// Replies to non-pending requests must be silently discarded
//int validate_reply(Packet *p);
// Used to retrieve the entry from the visitor list, whose
// home address matches `ip'
// This should be implemented using C++ hash_map container class
//mh_entry_t *
HomeAgent::mh_entry_t *
HomeAgent::get_entry(IPAddress ip) const
{
for (int i = 0; i< _mh_list.size() ; i++)
if (_mh_list[i]->home_addr == ip)
return _mh_list[i];
return NULL ;
}
int
HomeAgent::remove_entry(IPAddress ip)
{
for (int i = 0; i< _mh_list.size() ; i++)
if (_mh_list[i]->home_addr == ip) {
_mh_list[i]=_mh_list[_mh_list.size()-1];
_mh_list.pop_back();
return 0;
}
return -1 ;
}
void
HomeAgent::print_config(void) const
{
cerr << class_name() << endl
<< "-----------------" << endl ;
for (int i=0 ; i<_n_reg_ips ; i++)
cerr << "_reg_ips[" << i << "]="
<< IPAddress(_reg_ips[i]).s().mutable_c_str()<< endl ;
for (int i=0 ; i<_n_our_ips ; i++)
cerr << "_our_ips[" << i << "]="
<< IPAddress(_our_ips[i]).s().mutable_c_str()<< endl ;
cerr << "Agent IP : "
<< _agent_ip.s().mutable_c_str() << endl
<< "Agent Ethernet Address : "
<< _agent_ether.s().mutable_c_str() << endl
<< "Canonical outgoing IP : "
<< _canonical_out_ip.s().mutable_c_str() << endl
<< "Lifetime = " << _life_max << endl
<< "Check mobile host IPs ? " << _check_reg_ips << endl
<< "Verbose = " << _verbose << endl
<< "-----------------" << endl ;
return ;
}
void
HomeAgent::dump_packet(const Packet *p, packet_t type) const
{
click_ether *eth = NULL ;
click_ip *ip = NULL ;
click_ip *ipip = NULL ;
click_udp *udp = NULL ;
reg_req_t *reg = NULL ;
click_chatter("(H) : ************* PACKET DUMP *****************");
switch(type)
{
case IPIP_T :
ip = reinterpret_cast<click_ip *>(p->data());
assert(ip->ip_p == IP_PROTO_IPIP);
click_chatter("(H) : IP-in-IP encapsulated packet\n"
"
----------------------------");
click_chatter("(H) : Outer-IP\n"
"
--------");
click_chatter("(H) : Length=%d | id=%d | off=%d | ttl=%d | "
"Proto=%d | Chksum=%d\n"
"
src=%s | dst=%s",
htons(ip->ip_len), htons(ip->ip_id),
htons(ip->ip_off), ip->ip_ttl,
ip->ip_p, htons(ip->ip_sum),
IPAddress(ip->ip_src).s().mutable_c_str(),
IPAddress(ip->ip_dst).s().mutable_c_str());
ipip = reinterpret_cast <click_ip *>(ip+1);
click_chatter("(H) : Inner-IP\n"
"
--------");
click_chatter("(H) : Length=%d | id=%d | off=%d | ttl=%d | "
"Proto=%d | Chksum=%d\n"
"
src=%s | dst=%s",
htons(ipip->ip_len), htons(ipip->ip_id),
htons(ipip->ip_off), ipip->ip_ttl,
ipip->ip_p, htons(ipip->ip_sum),
IPAddress(ipip->ip_src).s().mutable_c_str(),
IPAddress(ipip->ip_dst).s().mutable_c_str());
break ;
case ETHER_T :
eth = reinterpret_cast<click_ether *>(p->data());
click_chatter("(H) : Ethernet\n"
"
--------");
click_chatter("(H) : src=%s | dst=%s | type=%d",
EtherAddress(eth->ether_shost).s().mutable_c_str(),
EtherAddress(eth->ether_dhost).s().mutable_c_str(),
ntohs(eth->ether_type));
if (ntohs(eth->ether_type)!= ETHERTYPE_IP)
break;
ip = reinterpret_cast <click_ip *> (eth+1);
case IP_T :
if (!ip)
ip = reinterpret_cast <click_ip *>(p->data());
click_chatter("(H) : IP\n"
"
--");
click_chatter("(H) : Length=%d | id=%d | off=%d | ttl=%d | "
"Proto=%d | Chksum=%d\n"
"
src=%s | dst=%s",
htons(ip->ip_len), htons(ip->ip_id),
htons(ip->ip_off), ip->ip_ttl,
ip->ip_p, htons(ip->ip_sum),
IPAddress(ip->ip_src).s().mutable_c_str(),
IPAddress(ip->ip_dst).s().mutable_c_str());
if (ip->ip_p == IP_PROTO_UDP)
udp = reinterpret_cast<click_udp*> (ip+1);
case UDP_T :
if (!udp) break ;
click_chatter("(H) : UDP\n"
"
---");
click_chatter("(H) : uh_sport=%d | uh_dport=%d | len=%d | chksum=%d",
htons(udp->uh_sport), htons(udp->uh_dport),
htons(udp->uh_ulen), htons(udp->uh_sum));
if (htons(udp->uh_ulen) > 20)
reg = reinterpret_cast<reg_req_t *>(udp+1);
case REG_T :
if (!reg) break ;
if (reg->type!=1 && reg->type!=3) break;
click_chatter("(H) : Registration details\n"
"
--------------------");
click_chatter("(H) : type=%d | code=SKIPPED | life=%d | "
"home_addr=%s | home_agent=%s",
reg->type, htons(reg->lifetime),
IPAddress(reg->home_addr).s().mutable_c_str(),
IPAddress(reg->home_agent).s().mutable_c_str());
if (reg->type == 1) /* registration request */
click_chatter("(H) : cof=%s",
IPAddress(reg->cof_addr).s().mutable_c_str());
}
click_chatter("(H) : *******************************************");
return;
}
EXPORT_ELEMENT(HomeAgent)
/* homeagent.hh */
#ifndef HOMEAGENT_HH
#define HOMEAGENT_HH
#include
#include
#include
#include
#include
<click/element.hh>
<click/ipaddress.hh>
<click/ipaddressset.hh>
<click/etheraddress.hh>
<click/glue.hh>
#ifndef min(a,b)
#define min(a,b) (((a) > (b)) ? (b) : (a))
#endif
class HomeAgent : public Element {
typedef struct {
u_char type ;
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_char
rsv:2 ;
u_char
vj:1;
u_char
gre:1;
u_char minim:1;
u_char decap:1;
u_char bcast:1;
u_char simul:1;
#else
u_char simul:1;
u_char bcast:1;
u_char decap:1;
u_char minim:1;
u_char
gre:1;
u_char
vj:1;
u_char
rsv:2 ;
#endif
u_short lifetime ; // 0xffff indicates infinity
u_int home_addr;
u_int home_agent;
u_int cof_addr;
// end-of-tunnel
double id;
/* extentions go here */
/* Mobile-Home authentication MUST be sent here */
} reg_req_t;
typedef struct {
u_char type ;
u_char code ;
u_short lifetime ;
u_int home_addr;
u_int home_agent;
double id;
/* extentions go here */
/* Mobile-Home authentication MUST be sent here */
/* Foreign-Home authentication MAY be present */
} reg_reply_t;
typedef struct {
IPAddress home_addr ;
IPAddress cof_addr ;
double id;
u_short life ;
} mh_entry_t ;
typedef enum {
IPIP_T, ETHER_T, IP_T, UDP_T, REG_T
} packet_t;
Vector <mh_entry_t *> _mh_list ;
u_int *_reg_ips ;
// list of IP addresses for which we accept
// registration requests
u_short _n_reg_ips ;
// number of IPs in above list
u_int *_our_ips ;
// Our unicast IP addresses
// _canonical_out MUST be one of these
u_short _n_our_ips ;
IPAddress _agent_ip ;
// IP on our home agent interface
IPAddress _canonical_out_ip ; // Used in ALL our outgoing relays
// except replies to requests
// which were addressed to our unicast
// In the above case, we just copy
// the address from the reply
//
// Packets addressed to this IP
// (by the foreign agent) must be received
// by us.
EtherAddress _agent_ether ;
// Ethernet address of interface where
// we receive link layer
// mobile (de)registration requests
u_short _life_max ;
// maximum lifetime of registration (in sec.)
// defaults to 1800s - see RFC2002
static const int UDP_DST_PORT ;
bool _check_reg_ips ;
bool _verbose ;
// cross-check against list ?
IPAddressSet _reg_ipsset ;
IPAddressSet _our_ipsset ;
IPAddressSet _mobile_ipsset ;
void handle_request(Packet *);
// process registration request
void mk_ipip(Packet *) const;// validate -> encapsulate -> forward
// need to write these procedures.
// The validate_* are a MUST.
// auth_* are optional
int validate_req(Packet *) const { return 0; }
void auth_req(Packet *) const {}
int validate_ipip(Packet *) const { return 0; }
mh_entry_t *get_entry(IPAddress) const;
int remove_entry(IPAddress);
void print_config(void) const;
void dump_packet(const Packet *, packet_t) const;
public:
HomeAgent();
~HomeAgent();
const char *class_name() const
const char *processing() const
{ return "HomeAgent"; }
{ return PUSH; }
HomeAgent *clone() const;
int configure(const Vector<String> &, ErrorHandler *);
int initialize(ErrorHandler *);
void push(int, Packet *);
};
#endif
ForeignAgent Element Code
/*
* foreignagent.cc
* Implements a foreign agent.
*
* Copyright (c) 2000-2001 University of Utah
*
* 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 following
* conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Further elaboration of this license, including a DISCLAIMER OF ANY
* WARRANTY, EXPRESS OR IMPLIED, is provided in the LICENSE file, which is
* also accessible at http://www.pdos.lcs.mit.edu/click/license.html
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <click/config.h>
#include <click/package.hh>
#include <click/ipaddress.hh>
#include <click/ipaddressset.hh>
#include <click/etheraddress.hh>
#include <click/click_ether.h>
#include <click/click_ip.h>
#include <click/click_udp.h>
#include "foreignagent.hh"
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/glue.hh>
#include "elements/standard/alignmentinfo.hh"
#ifdef __KERNEL__
# include <net/checksum.h>
#endif
#include <iostream>
//
//
//
//
//
//
//
//
//
//
input 0 - IP packets from the outside world
input 1 - Ethernet packets from the interface, where we are a foreign agent
output 0 - IP packets created by us, and ALSO those passed from above
output 1 - Ethernet packets from foreign agent interface, which we
don't process
output 2 - Ethernet packets which we create to send to the mobile host
This MUST be connected (via a queue or a similar element)
to the interface on which we interact with the mobile
host. And the mobile host MUST have a link-layer connection
on this interface.
// Limitations :
//
Only IP-in-IP encapsulation supported for the time being (Not a MUST)
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
VJ header compression unsupported (not a MUST)
Mobile-Home auth. not performed - keyed-MD5 (MUST)
No response sent to mobile node for the foreign agent
denying the registration request (for whatever ground) (MUST)
No Mobile-Foreign auth. supported (not a MUST)
No Home-Foreign auth. supported (not a MUST)
Minimum registration delay, not enforced between
successive registration requests. (not a MUST)
Relayed registration have their source IP address
set to an ougoing pre-configured IP address. Ideally
this should have been the IP address of the interface on which
this request is actually relayed. Problem is, we have no means
of knowing it before-hand in such a case. Since the home agent
will respond to this address, we MUST be able to receive packets
sent to this address and MUST also recognize it to be one of our
unicast IP addresses.
Unreachable home agent not handled (SHOULD be handled)
Misc. things TO DO (NOW)
Set timer to expire bindings - both requested ones and ones
which have been setup (MUST)
Make it possible to specify the list of IPs which can
register with us, using a mask.
const int ForeignAgent::UDP_DST_PORT = 434 ;
ForeignAgent::ForeignAgent()
: Element(2, 3),
_reg_ips(NULL), _n_reg_ips(0),
_our_ips(NULL), _n_our_ips(0),
_cof_ips(NULL), _n_cof_ips(0),
_life_max(1800),_relay_udp(1024),
_check_reg_ips(true), _verbose(false)
{
MOD_INC_USE_COUNT;
}
ForeignAgent::~ForeignAgent()
{
MOD_DEC_USE_COUNT;
delete [] _reg_ips ;
delete [] _our_ips ;
delete [] _cof_ips ;
for (int i=0; i<_visitor_list.size(); i++)
delete [] _visitor_list[i];
}
ForeignAgent *
ForeignAgent::clone() const
{
return new ForeignAgent;
}
// RFC 2002
// Add arguments to filter out IP/masks and/or accept IP/masks
//
for registration requests
int
ForeignAgent::configure(const Vector<String> &conf, ErrorHandler *errh)
{
int before = errh->nerrors();
if (cp_va_parse
(conf, this, errh,
cpIPAddressSet, "Acceptable mobile IP addresses", &_reg_ipsset,
cpIPAddress, "outgoing IP address (IP src field)", &_canonical_out_ip,
cpIPAddress, "IP address for agent interface", &_agent_ip,
cpEthernetAddress, "ethernet for agent interface", &_agent_ether,
cpOptional,
cpIPAddressSet, "Set of care-of-addresses", &_cof_ipsset,
cpIPAddressSet, "Our unicast addresses", &_our_ipsset,
cpKeywords,
"LIFE", cpUnsigned, "max. registration lifetime(in seconds)",&_life_max,
"RELAY_UDP_PORT", cpUnsigned, "request relayed from here", &_relay_udp,
"VERBOSE", cpBool, "display what's going on ?", &_verbose,
0) < 0)
return -1;
_n_reg_ips = _reg_ipsset.size();
_reg_ips
= _reg_ipsset.list_copy();
if (_n_reg_ips==1 && !_reg_ips[0])
_check_reg_ips = false ;
if (!_canonical_out_ip)
errh->error("Outgoing IP cannot be 0.0.0.0 !!!");
if (!_agent_ip)
errh->error("Agent IP cannot be 0.0.0.0 !!!");
if (!_agent_ether)
errh->error("Agent ethernet address cannot be 00:00:00:00:00:00 !!!");
// make sure our canonical outgoing IP is in this
if (!_our_ipsset.contains(_canonical_out_ip))
_our_ipsset.insert(_canonical_out_ip);
if (!_cof_ipsset.size())
_cof_ipsset.insert(_canonical_out_ip);
_n_our_ips = _our_ipsset.size();
_our_ips
= _our_ipsset.list_copy();
_n_cof_ips = _cof_ipsset.size();
_cof_ips
= _cof_ipsset.list_copy();
return (errh->nerrors() == before ? 0 : -1);
}
int
ForeignAgent::initialize(ErrorHandler *)
{
print_config();
return 0;
}
// Incoming encapuslated IP packtes and registration requests (UDP )
// arive on input port 0. Other IP packets also come from here
// and those MUST be passed down on output port 0, ASAP.
//
// Registration (and possibly other) Ethernet packet arrive on input port 1
void
ForeignAgent::push(int port, Packet *p)
{
bool for_us = false ;
click_ip *ip ;
click_ether *ether;
// packet destination
switch (port) {
case 0 :
ip = reinterpret_cast <click_ip *>(p->data());
// is the packet for us ?
for_us = _our_ipsset.contains(IPAddress(ip->ip_dst));
// If it isn't for us, just forward it.
if (!for_us) break ;
if (ip->ip_p == IP_PROTO_IPIP) {
ip_in_ip(p);
return ;
}
if (ip->ip_p == IP_PROTO_UDP) {
click_udp *udp = reinterpret_cast <click_udp *>(ip+1);
if (udp->uh_dport == htons(_relay_udp)) {
reg_reply(p);
return ;
}
}
break ;
case 1 :
ether = reinterpret_cast <click_ether *> (p->data());
// is it an IPv4 packet ?
if (ether->ether_type != htons(ETHERTYPE_IP)) break ;
ip = reinterpret_cast <click_ip *>(ether+1);
// registration requests may be sent to the all agents' multicast
// address = 224.0.0.11
if (_agent_ip == IPAddress(ip->ip_dst) ||
IPAddress(ip->ip_dst) == IPAddress("224.0.0.11")) { // for us ?
if (ip->ip_p == IP_PROTO_UDP) {
click_udp *udp = reinterpret_cast <click_udp *>(ip+1);
if (udp->uh_dport == htons(UDP_DST_PORT)) {
// validate and process request.
// If the request is to be relayed, then relay and return
reg_request(p);
return ;
}
}
}
// If control reaches here, then it is an Ethernet packet, but
// not for us
cerr << "Ethernet packet, but not for us. Forwarding it" << endl;
output(1).push(p);
return ;
} // switch
// if the packet comes till here, means it isn't a packet for us
cerr << "forwarding it" << endl ;
output(0).push(p);
return ;
}
/************************ Private Methods ***************************/
/********************************************************************/
// Make sure any existing entries for this mobile node are
//
not affected. The new entry should be made seperately
// MUST Re-do the UDP checksum calculation since we modify the UDP
//
source port
// Expects an Ethernet packet, which is IP/UDP port 434
void
ForeignAgent::reg_request(Packet *p)
{
if (validate_req(p) <0) return ;
// control reaches here only if this is a valid registration request
if (_verbose) {
click_chatter("(F) : Received the following REGISTRATION REQUEST");
dump_packet(p, ETHER_T);
}
// extract needed fields from the request
click_ether *ether = reinterpret_cast <click_ether *> (p->data());
click_ip *ip
= reinterpret_cast <click_ip *> (ether+1);
click_udp *udp
= reinterpret_cast <click_udp *> (ip+1);
reg_req_t *req
= reinterpret_cast <reg_req_t *> (udp+1);
// populate our data structures, so we are prepared to
// to receive the reply when and if, it comes. If it doesn't
// we have to timeout and update our structures
visitor_entry_t *v = new visitor_entry_t;
memcpy(v->link_addr_mobile, ether->ether_shost, 6);
v->home_addr = IPAddress(req->home_addr);
v->dst_addr = IPAddress(ip->ip_src);
v->udp_src_port = htons(udp->uh_sport);
v->home_agent
= IPAddress(req->home_agent);
v->id = req->id ;
// should be converted to host order
v->req_life = htons(req->lifetime);
v->rem_life = htons(req->lifetime);
v->pending = true;
_visitor_list.push_back(v);
if (_verbose) {
click_chatter("(F) : \nCreated registration request entry :\n"
"home_addr=%s | home_agent=%s | link=%s | Pending ? %d",
IPAddress(v->home_addr).s().mutable_c_str(),
IPAddress(v->home_agent).s().mutable_c_str(),
EtherAddress(v->link_addr_mobile).s().mutable_c_str(),
v->pending);
}
// remove the ethernet header from p
p->pull(14);
p->clear_annotations();
p->set_dst_ip_anno(v->home_agent);
ip = reinterpret_cast <click_ip *>(p->data());
ip->ip_src = _canonical_out_ip ;
ip->ip_dst = v->home_agent ;
ip->ip_ttl = 255;
// ip->ip_len remains same
ip->ip_tos = 0;
ip->ip_off = 0;
ip->ip_sum = 0 ;
// for recomputing the checksum
ip->ip_sum = in_cksum((u_char *) ip, sizeof(click_ip));
// right now, to avoid computing the UDP checksum, we
// are avoiding changing the UDP source port to `_relay_udp'
// Later, we'd like to use the _relay port, which is set
// up during the element configuration
udp= reinterpret_cast <click_udp *>(ip+1);
udp->uh_sport = htons(_relay_udp);
// do the UDP checksum computation
// do any post-processing of the registration request
// such as adding a Home-Foreign authentication appending
// send the packet on its way
if (_verbose) {
click_chatter("(F) : RELAYING the following registration REQUEST ... ");
dump_packet(p, IP_T);
}
output(0).push(p);
return ;
}
// Expects an IP packet to our UDP port : _relay_udp
// ip_len ?
void
ForeignAgent::reg_reply(Packet *p)
{
if (validate_reply(p) <0) return ;
if (_verbose) {
click_chatter("(F) : Received the following REGISTRATION REPLY");
dump_packet(p, IP_T);
}
// control reaches here only if this is a valid registration reply
// extract needed fields from the request
click_ip *ip
= reinterpret_cast <click_ip *> (p->data());
click_udp *udp
= reinterpret_cast <click_udp *> (ip+1);
reg_reply_t *reply
= reinterpret_cast <reg_reply_t *> (udp+1);
// we MUST be having a mapping, if we have gotten so far
visitor_entry_t *v = get_entry(IPAddress(reply->home_addr));
assert(v);
if (_verbose)
click_chatter("(F) : Found binding :\n"
"home_addr=%s | home_agent=%s",
IPAddress(v->home_addr).s().mutable_c_str(),
IPAddress(v->home_agent).s().mutable_c_str());
// now check the reply code
// we would want to move these magic numbers to a header
switch (reply->code) {
case 0 :
case 1 :
if (reply->lifetime == 0) {
// remove the binding
remove_entry(v->home_addr);
if (_verbose)
click_chatter("(F) : Reply Code=0/1, Lifetime=0 => removing entry :"
"home_addr=%s | home_agent=%s\n",
IPAddress(v->home_addr).s().mutable_c_str(),
IPAddress(v->home_agent).s().mutable_c_str());
}
else {
// issue a warning if reply->lifetime > v->req_life
v->rem_life = min(htons(reply->lifetime), v->req_life);
v->pending = false;
assert(v->rem_life);
if (_verbose)
click_chatter("(F) : Reply Code=0/1, reply says life remaining=%d\n"
"Using life=%d, updating entry, setting"
" pending status of entry to FALSE\n",
htons(reply->lifetime), v->rem_life);
}
break ;
// process the error codes - create the registration
// entry, but NOT the visitor list entry
// and return
}
// relay the correct and successful registration request
// add the ethernet header to p
WritablePacket *q = Packet::make(sizeof(click_ether)+p->length());
click_ether *ether = reinterpret_cast <click_ether *>(q->data());
ip = reinterpret_cast <click_ip *>(ether+1);
memcpy(ip, p->data(), p->length());
q->set_dst_ip_anno(v->dst_addr);
memcpy(ether->ether_dhost, (u_char *)v->link_addr_mobile, 6);
memcpy(ether->ether_shost, _agent_ether.data(), 6);
ether->ether_type = htons(ETHERTYPE_IP);
// set the
ip->ip_src
ip->ip_dst
ip->ip_ttl
ip->ip_tos
ip->ip_off
ip->ip_sum
ip->ip_sum
IP fields to the right values
= _agent_ip ;
= v->dst_addr ;
= 1 ;
= 0;
= 0;
= 0 ;
// for recomputing the checksum
= in_cksum((u_char *) ip, sizeof(click_ip));
udp= reinterpret_cast <click_udp *>(ip+1);
udp->uh_sport = htons(_relay_udp);
udp->uh_dport = htons(v->udp_src_port) ;
// MUST do the UDP checksum computation
p->kill();
if (_verbose) {
click_chatter("(F) : RELAYING the following registration REPLY ... ");
dump_packet(q, ETHER_T);
}
// send the packet on our agent inteface
output(2).push(q);
return ;
}
// expects IP-in-IP encapsulated packets
// ip_len
void
ForeignAgent::ip_in_ip(Packet *p) const
{
if (validate_ipip(p) <0) return ;
if (_verbose) {
click_chatter("(F) : Received the following IP-in-IP encapsulated
packet");
dump_packet(p, IPIP_T);
}
// decapsulate packet
// assuming only a 20 byte header. This should be generalized
// using ip_header()
click_ip *ip = reinterpret_cast <click_ip *> (p->data()+sizeof(click_ip));
visitor_entry_t *v = get_entry(IPAddress(ip->ip_dst));
if (_verbose) {
click_chatter("(F) : Using existing binding :\n"
"
Sending to -> %s using the link address %s",
IPAddress(v->home_addr).s().mutable_c_str(),
EtherAddress(v->link_addr_mobile).s().mutable_c_str());
}
assert(v);
// wrap in an ethernet packet
WritablePacket *q = Packet::make(sizeof(click_ether)
+ (static_cast<u_short>(p->length()))
- sizeof(click_ip));
click_ether *ether = reinterpret_cast <click_ether *>(q->data());
memcpy(ether->ether_dhost, v->link_addr_mobile, 6);
memcpy(ether->ether_shost, _agent_ether.data(), 6);
ether->ether_type = htons(ETHERTYPE_IP);
memcpy((q->data()+sizeof(click_ether)),
(p->data()+sizeof(click_ip)),
(p->length()-sizeof(click_ip)));
q->set_dst_ip_anno(v->dst_addr);
p->kill();
if (_verbose) {
click_chatter("(F) : Sending the following packet AFTER decapsulation");
dump_packet(q, ETHER_T);
}
// send the packet on our agent inteface
output(2).push(q);
return ;
}
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Silently discard, if non-zero UDP checksum
Is it within our ACCEPT set ?
Destination UDP port == 434 ?
Deny request if :
i) Requested lifetime too long (denial contains the acceptable value, 69)
ii) poorly formed request/reply
iii) Requested encapsulation/compression unavailable
iv) Home agent unreachable
v) Non-zero reserved field (return status code 70)
Denials SHOULD be sent to the agent interface.
The registration fields from the original request must be copied.
IP source address for denials, is copied from the request(destination)
IP dest address for denials, is copied from the request(src)
UDP source port for denials is 434
UDP dest port for denials, is the src UDP port of request
For co-located COF, the IP source address MUST be the COF
Otherwise the IP source address MUST be the home address
The link layer destination address MUST be the agent's unicast address
IP destination address is either agent's interface IP address/224.0.0.11
If IP destination address is 224.0.0.11 then TTL MUST be 1.
`D' bit set iff a co-located COF address is used.
Requested lifetime, MUST not exceed that, which was advertised by the agent
Encapsulation MUST be supported.
Type MUST be 1
int validate_req(Packet *p);
// Silently discard if low-order 32-bits of `id' don't match
// UDP destination, should match the outgoing port the request
//
was relayed from
// reply->type == 3 (for Registration Reply)
// Act upon the denial codes
// Discard, if invalid non-zero UDP checksum
// Replies to non-pending requests must be silently discarded
//int validate_reply(Packet *p);
// Used to retrieve the entry from the visitor list, whose
// home address matches `ip'
// This should be implemented using C++ hash_map container class
//visitor_entry_t *
ForeignAgent::visitor_entry_t *
ForeignAgent::get_entry(IPAddress ip) const
{
for (int i = 0; i< _visitor_list.size() ; i++)
if (_visitor_list[i]->home_addr == ip)
return _visitor_list[i];
return NULL ;
}
int
ForeignAgent::remove_entry(IPAddress ip)
{
for (int i = 0; i< _visitor_list.size() ; i++)
if (_visitor_list[i]->home_addr == ip) {
_visitor_list[i]=_visitor_list[_visitor_list.size()-1];
_visitor_list.pop_back();
return 0;
}
return -1 ;
}
void
ForeignAgent::print_config(void) const
{
cerr << class_name() << endl
<< "-----------------" << endl ;
for (int i=0 ; i<_n_reg_ips ; i++)
cerr << "_reg_ips[" << i << "]="
<< IPAddress(_reg_ips[i]).s().mutable_c_str()<< endl ;
for (int i=0 ; i<_n_our_ips ; i++)
cerr << "_our_ips[" << i << "]="
<< IPAddress(_our_ips[i]).s().mutable_c_str()<< endl ;
for (int i=0 ; i<_n_cof_ips ; i++)
cerr << "_cof_ips[" << i << "]="
<< IPAddress(_cof_ips[i]).s().mutable_c_str()<< endl ;
cerr << "Agent IP : "
<< _agent_ip.s().mutable_c_str() << endl
<< "Agent Ethernet Address : "
<< _agent_ether.s().mutable_c_str() << endl
<< "Canonical outgoing IP : "
<< _canonical_out_ip.s().mutable_c_str() << endl
<< "Lifetime = " << _life_max << endl
<< "Relay UDP port = " << _relay_udp << endl
<< "Check mobile host IPs ? " << _check_reg_ips << endl
<< "Verbose = " << _verbose << endl
<< "-----------------" << endl ;
return ;
}
void
ForeignAgent::dump_packet(const Packet *p, packet_t type) const
{
click_ether *eth = NULL ;
click_ip *ip = NULL ;
click_ip *ipip = NULL ;
click_udp *udp = NULL ;
reg_req_t *reg = NULL ;
click_chatter("(F) : ************* PACKET DUMP *****************");
switch(type)
{
case IPIP_T :
ip = reinterpret_cast<click_ip *>(p->data());
assert(ip->ip_p == IP_PROTO_IPIP);
click_chatter("(F) : IP-in-IP encapsulated packet\n"
"
----------------------------");
click_chatter("(F) : Outer-IP\n"
"
--------");
click_chatter("(F) : Length=%d | id=%d | off=%d | ttl=%d | "
"Proto=%d | Chksum=%d\n"
"
src=%s | dst=%s",
htons(ip->ip_len), htons(ip->ip_id),
htons(ip->ip_off), ip->ip_ttl,
ip->ip_p, htons(ip->ip_sum),
IPAddress(ip->ip_src).s().mutable_c_str(),
IPAddress(ip->ip_dst).s().mutable_c_str());
ipip = reinterpret_cast <click_ip *>(ip+1);
click_chatter("(F) : Inner-IP\n"
"
--------");
click_chatter("(F) : Length=%d | id=%d | off=%d | ttl=%d | "
"Proto=%d | Chksum=%d\n"
"
src=%s | dst=%s",
htons(ipip->ip_len), htons(ipip->ip_id),
htons(ipip->ip_off), ipip->ip_ttl,
ipip->ip_p, htons(ipip->ip_sum),
IPAddress(ipip->ip_src).s().mutable_c_str(),
IPAddress(ipip->ip_dst).s().mutable_c_str());
break ;
case ETHER_T :
eth = reinterpret_cast<click_ether *>(p->data());
click_chatter("(F) : Ethernet\n"
"
--------");
click_chatter("(F) : src=%s | dst=%s | type=%d",
EtherAddress(eth->ether_shost).s().mutable_c_str(),
EtherAddress(eth->ether_dhost).s().mutable_c_str(),
ntohs(eth->ether_type));
if (ntohs(eth->ether_type)!= ETHERTYPE_IP)
break;
ip = reinterpret_cast <click_ip *> (eth+1);
case IP_T :
if (!ip)
ip = reinterpret_cast <click_ip *>(p->data());
click_chatter("(F) : IP\n"
"
--");
click_chatter("(F) : Length=%d | id=%d | off=%d | ttl=%d | "
"Proto=%d | Chksum=%d\n"
"
src=%s | dst=%s",
htons(ip->ip_len), htons(ip->ip_id),
htons(ip->ip_off), ip->ip_ttl,
ip->ip_p, htons(ip->ip_sum),
IPAddress(ip->ip_src).s().mutable_c_str(),
IPAddress(ip->ip_dst).s().mutable_c_str());
if (ip->ip_p == IP_PROTO_UDP)
udp = reinterpret_cast<click_udp*> (ip+1);
case UDP_T :
if (!udp) break ;
click_chatter("(F) : UDP\n"
"
---");
click_chatter("(F) : uh_sport=%d | uh_dport=%d | len=%d | chksum=%d",
htons(udp->uh_sport), htons(udp->uh_dport),
htons(udp->uh_ulen), htons(udp->uh_sum));
if (htons(udp->uh_ulen) > 20)
reg = reinterpret_cast<reg_req_t *>(udp+1);
case REG_T :
if (!reg) break ;
if (reg->type!=1 && reg->type!=3) break;
click_chatter("(F) : Registration details\n"
"
--------------------");
click_chatter("(F) : type=%d | code=SKIPPED | life=%d | "
"home_addr=%s | home_agent=%s",
reg->type, htons(reg->lifetime),
IPAddress(reg->home_addr).s().mutable_c_str(),
IPAddress(reg->home_agent).s().mutable_c_str());
if (reg->type == 1) /* registration request */
click_chatter("(F) : cof=%s",
IPAddress(reg->cof_addr).s().mutable_c_str());
}
click_chatter("(F) : *******************************************");
return;
}
EXPORT_ELEMENT(ForeignAgent)
/* foreignagent.hh */
#ifndef FOREIGNAGENT_HH
#define FOREIGNAGENT_HH
#include
#include
#include
#include
#include
<click/element.hh>
<click/ipaddress.hh>
<click/ipaddressset.hh>
<click/etheraddress.hh>
<click/glue.hh>
#ifndef min(a,b)
#define min(a,b) (((a) > (b)) ? (b) : (a))
#endif
class ForeignAgent : public Element {
typedef struct {
u_char type ;
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_char
rsv:2 ;
u_char
vj:1;
u_char
gre:1;
u_char minim:1;
u_char decap:1;
u_char bcast:1;
u_char simul:1;
#else
u_char simul:1;
u_char bcast:1;
u_char decap:1;
u_char minim:1;
u_char
gre:1;
u_char
vj:1;
u_char
rsv:2 ;
#endif
u_short lifetime ; // 0xffff indicates infinity
u_int home_addr;
u_int home_agent;
u_int cof_addr;
// end-of-tunnel
double id;
/* extentions go here */
/* Mobile-Home authentication MUST be sent here */
} reg_req_t;
typedef struct {
u_char type ;
u_char code ;
u_short lifetime ;
u_int home_addr;
u_int home_agent;
double id;
/* extentions go here */
/* Mobile-Home authentication MUST be sent here */
/* Foreign-Home authentication MAY be present */
} reg_reply_t;
typedef struct {
u_char link_addr_mobile[6] ;
IPAddress home_addr ;
IPAddress dst_addr ;
u_short udp_src_port ;
IPAddress home_agent ;
double id;
u_short req_life ;
u_short rem_life ;
bool pending ; // true, if the registration hasn't been accepted yet
} visitor_entry_t ;
typedef enum {
IPIP_T, ETHER_T, IP_T, UDP_T, REG_T
} packet_t;
Vector <visitor_entry_t *> _visitor_list ;
u_int *_reg_ips ;
// list of IP addresses for which we accept
// registration requests
u_short _n_reg_ips ;
// number of IPs in above list
u_int *_our_ips ;
// Our unicast IP addresses
// _canonical_out MUST be one of these
u_short _n_our_ips ;
u_int *_cof_ips ;
u_short _n_cof_ips ;
// MUST be a subset of _our_ips
IPAddress _agent_ip ;
// IP on our foreign agent interface
IPAddress _canonical_out_ip ; // Used in ALL our outgoing relays
// Packets addressed to this IP
// (by the home agent) must be received
// by us. Registration replies will
// come to this address.
// This need not be one of our COF addresses
EtherAddress _agent_ether ;
// Ethernet address of interface where
// we receive mobile registration requests
u_short _life_max ;
// maximum lifetime of registration (in sec.)
// defaults to 1800s - see RFC2002
ushort _relay_udp ;
static const int UDP_DST_PORT ;
bool _check_reg_ips ;
bool _verbose ;
// cross-check against list ?
IPAddressSet _reg_ipsset ;
IPAddressSet _our_ipsset ;
IPAddressSet _cof_ipsset ;
void reg_request(Packet *);
void reg_reply(Packet *);
// process registration request
// process registration reply
void ip_in_ip(Packet *) const;// validate and decapsulate/forward
// need to write these procedures.
// The validate_* are a MUST.
// auth_* are optional
int validate_req(Packet *) const { return 0; }
void auth_req(Packet *) const {}
int validate_reply(Packet *) const { return 0; }
void auth_reply(Packet *) const {}
int validate_ipip(Packet *) const { return 0; }
visitor_entry_t *get_entry(IPAddress) const;
int remove_entry(IPAddress);
void print_config(void) const;
void dump_packet(const Packet *, packet_t) const;
public:
ForeignAgent();
~ForeignAgent();
const char *class_name() const
const char *processing() const
{ return "ForeignAgent"; }
{ return PUSH; }
ForeignAgent *clone() const;
int configure(const Vector<String> &, ErrorHandler *);
int initialize(ErrorHandler *);
void push(int, Packet *);
};
#endif
Appendix C
Sample Agent Test Configuration File
f::ForeignAgent(0.0.0.0,
// accept all registration requests
192.168.0.1,
// outgoing IP
192.168.15.1,
// agent interface address
45:56:a4:d0:ef:3f, // agent interface
192.168.0.1,
// cof address
192.168.0.1 192.168.15.1,
// our unicast addresses
LIFE 900, RELAY_UDP_PORT 1024, VERBOSE true);
h::
HomeAgent(0.0.0.0,
// accept all registration requests
202.54.1.1,
// outgoing IP
202.54.15.10,
// agent interface address
de:34:09:ab:65:70, // agent interface
202.54.1.1 202.54.15.10,
// our unicast addresses
LIFE 900, VERBOSE true);
// Ethernet packet containing a valid registration request
request::InfiniteSource(\<
// ethernet header
45 56 a4 d0 ef 3f // agent ethernet
01 ef 23 cd 45 ab // our ethernet
08 00
// ETHERTYPE_IP
// IP header
45 00 00 34
// v4/header_len/tos/ip_len=52
00 01 00 00
// id/offset
01 11 00 00
// ttl/prot_udp/checksum
ca 36 0f 01
// home address - 202.54.15.1
c0 a8 0f 01
// agent address- 192.168.15.1
// udp
00 ff 01 b2
// src_port=255, dest_port=434
00 20 00 00
// head_len/checksum
// reg
01 00 01 00
// type/flags/256s lifetime
ca 36 0f 01
// home address
ca 36 01 01
// home agent - 202.54.1.1
c0 a8 00 01
// cof address- 192.168.0.1
01 12 23 34
// 8-byte id
45 56 67 78
>, 1, 1);
// send it once
// IP packet containing registration reply
reply::InfiniteSource(\<
// IP header
45 00 00 30
// v4/header_len/tos/ip_len=52
00 05 00 00
// id/offset
01 11 2d d8
// ttl/prot_udp/checksum
ca 36 01 01
// src IP = home agent=202.54.15.1
c0 a8 00 01
// dst IP
// = canonical out IP=192.168.0.1
// udp
00 fa 04 00
// src_port=250, dest_port=434
00 20 00 00
// head_len/checksum
// reg reply
03 00 00 80
ca 36 0f 01
ca 36 01 01
01 12 23 34
45 56 67 78
>, 1, 1);
//
//
//
//
// IP-in-IP encapsulated packet
ipip::InfiniteSource(\<
// IP header
45 00 00 38
//
00 07 00 00
//
06 04 28 db
//
ca 36 01 01
c0 a8 00 01
//
// inner-ip
45 00 00 24
//
00 33 00 00
//
45 11 3d f4
//
9b 63 c3 01
ca 36 0f 01
//
type/flags/128s lifetime
home address
home agent - 202.54.1.1
8-byte id
// send it once
v4/header_len/tos/ip_len=56
id/offset
ttl/prot_ipip/checksum
// src IP = home agent=202.54.15.1
dst IP = cof address=192.168.0.1
v4/header_len/tos/ip_len=36
id/offset
ttl/prot_udp/checksum
// src IP = 155.99.195.1
dst IP = home address = 202.54.15.1
// inner IP payload
// udp headers
00 fa 00 c0
// src_port=250, dest_port=192
00 10 00 00
// head_len/checksum
// UDP payload
01 02 03 04
04 05 06 07
>, 1, 1);
// Random IP packet sent to
ToMH::InfiniteSource(\<
//
45 00 00
00 07 00
06 06 c9
0c
ca 36 0f
//
34
10
09
>, 1,
// send it once
the home address of the mobile host
IP header
20
//
00
//
21
//
23 06 56
01
//
v4/header_len/tos/ip_len=32
id/offset
ttl/prot_tcp/checksum
// src IP = 12.35.6.86
dst IP = home address = 202.54.15.1
random IP payload
54 98 f0
02 7a bc
a9 b2 f3
1);
//InfiniteSource(0,0,1,false) -> f ;
//InfiniteSource(0,0,1,false) -> f ;
request->[1]f[1]->Discard;
f[2]->Print("Foreign-OUT(2)", 100)->Discard;
InfiniteSource(0,0,1,false)
-> [1]h[1]
-> Print("Home-OUT(1)", 100)
-> Discard ;
h[2]->Print("Home-OUT(2)", 100)
->Discard;
// n :: Null ;
reply ->Discard ;
ipip ->Discard ;
f ->
->
->
->
->
CheckIPHeader(,0,VERBOSE true)
IPPrint("Foreign-OUT(0)/Home-IN(0) ", CONTENTS hex, ID true)
h
IPPrint("Home-OUT(0)/Foreign-IN(0) ", CONTENTS hex, ID true)
f ;
ToMH->h ;
Run Output for Agent Test
ForeignAgent
----------------_reg_ips[0]=0.0.0.0
_our_ips[0]=192.168.0.1
_our_ips[1]=192.168.15.1
_cof_ips[0]=192.168.0.1
Agent IP : 192.168.15.1
Agent Ethernet Address : 45:56:a4:d0:ef:3f
Canonical outgoing IP : 192.168.0.1
Lifetime = 900
Relay UDP port = 1024
Check mobile host IPs ? 0
Verbose = 1
----------------HomeAgent
----------------_reg_ips[0]=0.0.0.0
_our_ips[0]=202.54.1.1
_our_ips[1]=202.54.15.10
Agent IP : 202.54.15.10
Agent Ethernet Address : de:34:09:ab:65:70
Canonical outgoing IP : 202.54.1.1
Lifetime = 900
Check mobile host IPs ? 0
Verbose = 1
----------------(F) : Received the following REGISTRATION REQUEST
(F) : ************* PACKET DUMP *****************
(F) : Ethernet
-------(F) : src=01:ef:23:cd:45:ab | dst=45:56:a4:d0:ef:3f | type=2048
(F) : IP
-(F) : Length=52 | id=1 | off=0 | ttl=1 | Proto=17 | Chksum=0
src=202.54.15.1 | dst=192.168.15.1
(F) : UDP
--(F) : uh_sport=255 | uh_dport=434 | len=32 | chksum=0
(F) : Registration details
-------------------(F) : type=1 | code=SKIPPED | life=256 | home_addr=202.54.15.1 |
home_agent=202.54.1.1
(F) : cof=192.168.0.1
(F) : *******************************************
(F) :
Created registration request entry :
home_addr=202.54.15.1 | home_agent=202.54.1.1 | link=01:ef:23:cd:45:ab | Pending
? 1
(F) : RELAYING the following registration REQUEST ...
(F) : ************* PACKET DUMP *****************
(F) : IP
-(F) : Length=52 | id=1 | off=0 | ttl=255 | Proto=17 | Chksum=12247
src=192.168.0.1 | dst=202.54.1.1
(F) : UDP
--(F) : uh_sport=1024 | uh_dport=434 | len=32 | chksum=0
(F) : Registration details
-------------------(F) : type=1 | code=SKIPPED | life=256 | home_addr=202.54.15.1 |
home_agent=202.54.1.1
(F) : cof=192.168.0.1
(F) : *******************************************
Foreign-OUT(0)/Home-IN(0) : id 1: 192.168.0.1.1024 > 202.54.1.1.434: udp 32
45000034 00010000 ff112fd7 c0a80001 ca360101 040001b2
00200000 01000100 ca360f01 ca360101 c0a80001 01122334
45566778
Received the following REGISTRATION REQUEST
(H) : ************* PACKET DUMP *****************
(H) : IP
-(H) : Length=52 | id=1 | off=0 | ttl=255 | Proto=17 | Chksum=12247
src=192.168.0.1 | dst=202.54.1.1
(H) : UDP
--(H) : uh_sport=1024 | uh_dport=434 | len=32 | chksum=0
(H) : Registration details
-------------------(H) : type=1 | code=SKIPPED | life=256 | home_addr=202.54.15.1 |
home_agent=202.54.1.1
(H) : cof=192.168.0.1
(H) : *******************************************
(H) : Created NEW binding : 202.54.15.1->192.168.0.1 | Life = 256
(H) : Sending the following registration REPLY
(H) : ************* PACKET DUMP *****************
(H) : IP
-(H) : Length=52 | id=1 | off=0 | ttl=254 | Proto=17 | Chksum=12503
src=202.54.1.1 | dst=192.168.0.1
(H) : UDP
--(H) : uh_sport=434 | uh_dport=1024 | len=32 | chksum=0
(H) : Registration details
-------------------(H) : type=1 | code=SKIPPED | life=256 | home_addr=202.54.15.1 |
home_agent=202.54.1.1
(H) : cof=192.168.0.1
(H) : *******************************************
(F) : Received the following REGISTRATION REPLY
(F) : ************* PACKET DUMP *****************
(F) : IP
-(F) : Length=52 | id=1 | off=0 | ttl=254 | Proto=17 | Chksum=12503
src=202.54.1.1 | dst=192.168.0.1
(F) : UDP
--(F) : uh_sport=434 | uh_dport=1024 | len=32 | chksum=0
(F) : Registration details
-------------------(F) : type=1 | code=SKIPPED | life=256 | home_addr=202.54.15.1 |
home_agent=202.54.1.1
(F) : cof=192.168.0.1
(F) : *******************************************
(F) : Found binding :
home_addr=202.54.15.1 | home_agent=202.54.1.1
(F) : Reply Code=0/1, reply says life remaining=256
Using life=256, updating entry, setting pending status of entry to FALSE
(F) : RELAYING the following registration REPLY ...
(F) : ************* PACKET DUMP *****************
(F) : Ethernet
-------(F) : src=45:56:a4:d0:ef:3f | dst=01:ef:23:cd:45:ab | type=2048
(F) : IP
-(F) : Length=52 | id=1 | off=0 | ttl=1 | Proto=17 | Chksum=4312
src=192.168.15.1 | dst=202.54.15.1
(F) : UDP
--(F) : uh_sport=1024 | uh_dport=255 | len=32 | chksum=0
(F) : Registration details
-------------------(F) : type=1 | code=SKIPPED | life=256 | home_addr=202.54.15.1 |
home_agent=202.54.1.1
(F) : cof=192.168.0.1
(F) : *******************************************
Print Foreign-OUT(2) | 66 : 01ef23cd 45ab4556 a4d0ef3f 08004500 00340001
00000111 10d8c0a8 0f01ca36 0f010400 00ff0020 00000100 0100ca36 0f01ca36 0101c0a8
00010112 23344556 6778
(H) : Received the following packet to be forwarded to MH
(H) : ************* PACKET DUMP *****************
(H) : IP
-(H) : Length=32 | id=7 | off=0 | ttl=6 | Proto=6 | Chksum=51489
src=12.35.6.86 | dst=202.54.15.1
(H) : *******************************************
(H) : Using binding to encapsulate: 202.54.15.1 -> 192.168.0.1
(H) : Sending the following packet AFTER encapsulation
(H) : ************* PACKET DUMP *****************
(H) : IP-in-IP encapsulated packet
---------------------------(H) : Outer-IP
-------(H) : Length=52 | id=1024 | off=0 | ttl=255 | Proto=4 | Chksum=28133
src=202.54.1.1 | dst=192.168.0.1
(H) : Inner-IP
-------(H) : Length=32 | id=7 | off=0 | ttl=6 | Proto=6 | Chksum=51489
src=12.35.6.86 | dst=202.54.15.1
(H) : *******************************************
(F) : Received the following IP-in-IP encapsulated packet
(F) : ************* PACKET DUMP *****************
(F) : IP-in-IP encapsulated packet
---------------------------(F) : Outer-IP
-------(F) : Length=52 | id=1024 | off=0 | ttl=255 | Proto=4 | Chksum=28133
src=202.54.1.1 | dst=192.168.0.1
(F) : Inner-IP
-------(F) : Length=32 | id=7 | off=0 | ttl=6 | Proto=6 | Chksum=51489
src=12.35.6.86 | dst=202.54.15.1
(F) : *******************************************
(F) : Using existing binding :
Sending to -> 202.54.15.1 using the link address 01:ef:23:cd:45:ab
(F) : Sending the following packet AFTER decapsulation
(F) : ************* PACKET DUMP *****************
(F) : Ethernet
-------(F) : src=45:56:a4:d0:ef:3f | dst=01:ef:23:cd:45:ab | type=2048
(F) : IP
-(F) : Length=32 | id=7 | off=0 | ttl=6 | Proto=6 | Chksum=51489
src=12.35.6.86 | dst=202.54.15.1
(F) : *******************************************
Print Foreign-OUT(2) | 46 : 01ef23cd 45ab4556 a4d0ef3f 08004500 00200007
00000606 c9210c23 0656ca36 0f013454 98f01002 7abc09a9 b2f3
Download