Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Adam Osuchowski
Kea
Commits
5162bd77
Commit
5162bd77
authored
May 21, 2013
by
Marcin Siodelski
Browse files
[2902] Changes as a result of the review.
parent
9c2f41d0
Changes
15
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_srv.cc
View file @
5162bd77
...
...
@@ -63,7 +63,7 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig, const bool use_bcast,
try
{
// First call to instance() will create IfaceMgr (it's a singleton)
// it may throw something if things go wrong.
// The 'true' value of
in
the call to setMatchingPacketFilter imposes
// The 'true' value of the call to setMatchingPacketFilter imposes
// that IfaceMgr will try to use the mechanism to respond directly
// to the client which doesn't have address assigned. This capability
// may be lacking on some OSes, so there is no guarantee that server
...
...
@@ -373,7 +373,12 @@ Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
}
// If src/dest HW addresses are used by the packet filtering class
// we need to copy them as well.
// we need to copy them as well. There is a need to check that the
// address being set is not-NULL because an attempt to set the NULL
// HW would result in exception. If these values are not set, the
// the default HW addresses (zeroed) should be generated by the
// packet filtering class when creating Ethernet header for
// outgoing packet.
HWAddrPtr
src_hw_addr
=
question
->
getLocalHWAddr
();
if
(
src_hw_addr
)
{
answer
->
setLocalHWAddr
(
src_hw_addr
);
...
...
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
View file @
5162bd77
...
...
@@ -48,12 +48,26 @@ public:
/// @brief Constructor.
///
/// It disables configuration of broadcast options on
/// sockets that are opened by the Dhcpv4Srv constructor.
/// Also, disables the Direct V4 traffic as it requires
/// use of raw sockets. Use of broadcast as well as raw
/// sockets require root privileges, thus can't be used
/// in unit testing.
/// This constructor disables default modes of operation used by the
/// Dhcpv4Srv class:
/// - Send/receive broadcast messages through sockets on interfaces
/// which support broadcast traffic.
/// - Direct DHCPv4 traffic - communication with clients which do not
/// have IP address assigned yet.
///
/// Enabling these modes requires root privilges so they must be
/// disabled for unit testing.
///
/// Note, that disabling broadcast options on sockets does not impact
/// the operation of these tests because they use local loopback
/// interface which doesn't have broadcast capability anyway. It rather
/// prevents setting broadcast options on other (broadcast capable)
/// sockets which are opened on other interfaces in Dhcpv4Srv constructor.
///
/// The Direct DHCPv4 Traffic capability can be disabled here because
/// it is tested with PktFilterLPFTest unittest. The tests which belong
/// to PktFilterLPFTest can be enabled on demand when root privileges can
/// be guaranteed.
NakedDhcpv4Srv
(
uint16_t
port
=
0
)
:
Dhcpv4Srv
(
port
,
"type=memfile"
,
false
,
false
)
{
}
...
...
@@ -373,26 +387,41 @@ public:
const
IOAddress
&
client_addr
,
const
IOAddress
&
relay_addr
)
{
// Create an instance of the tested class.
boost
::
scoped_ptr
<
NakedDhcpv4Srv
>
srv
(
new
NakedDhcpv4Srv
(
0
));
// Initialize the source HW address.
vector
<
uint8_t
>
mac
(
6
);
for
(
int
i
=
0
;
i
<
6
;
i
++
)
{
mac
[
i
]
=
i
*
10
;
mac
[
i
]
=
i
*
10
;
}
// Initialized the destination HW address.
vector
<
uint8_t
>
dst_mac
(
6
);
for
(
int
i
=
0
;
i
<
6
;
i
++
)
{
for
(
int
i
=
0
;
i
<
6
;
++
i
)
{
dst_mac
[
i
]
=
i
*
20
;
}
// Create a DHCP message. It will be used to simulate the
// incoming message.
boost
::
shared_ptr
<
Pkt4
>
req
(
new
Pkt4
(
msg_type
,
1234
));
// Create a response message. It will hold a reponse packet.
// Initially, set it to NULL.
boost
::
shared_ptr
<
Pkt4
>
rsp
;
// Set the name of the interface on which packet is received.
req
->
setIface
(
"eth0"
);
// Set the interface index. It is just a dummy value and will
// not be interprented.
req
->
setIndex
(
17
);
// Set the target HW address. This value is normally used to
// construct the data link layer header.
req
->
setRemoteHWAddr
(
1
,
6
,
dst_mac
);
// Set the HW address. This value is set on DHCP level (in chaddr).
req
->
setHWAddr
(
1
,
6
,
mac
);
// Set local HW address. It is used to construct the data link layer
// header.
req
->
setLocalHWAddr
(
1
,
6
,
mac
);
// Set target IP address.
req
->
setRemoteAddr
(
IOAddress
(
client_addr
));
// Set relay address.
req
->
setGiaddr
(
relay_addr
);
// We are going to test that certain options are returned
...
...
src/lib/dhcp/iface_mgr.cc
View file @
5162bd77
...
...
@@ -220,9 +220,10 @@ IfaceMgr::setPacketFilter(const boost::shared_ptr<PktFilter>& packet_filter) {
const
Iface
::
SocketCollection
&
sockets
=
iface
->
getSockets
();
for
(
Iface
::
SocketCollection
::
const_iterator
sock
=
sockets
.
begin
();
sock
!=
sockets
.
end
();
++
sock
)
{
// There is at least one socket open, so we have to fail.
if
(
sock
->
family_
==
AF_INET
)
{
isc_throw
(
PacketFilterChangeDenied
,
"it is not allowed to set new packet"
// There is at least one socket open, so we have to fail.
isc_throw
(
PacketFilterChangeDenied
,
"it is not allowed to set new packet"
<<
" filter when there are open IPv4 sockets - need"
<<
" to close them first"
);
}
...
...
src/lib/dhcp/iface_mgr.h
View file @
5162bd77
...
...
@@ -88,7 +88,7 @@ struct SocketInfo {
};
/// @brief
r
epresents a single network interface
/// @brief
R
epresents a single network interface
///
/// Iface structure represents network interface with all useful
/// information, like name, interface index, MAC address and
...
...
@@ -96,13 +96,20 @@ struct SocketInfo {
class
Iface
{
public:
///
m
aximum MAC address length (Infiniband uses 20 bytes)
///
M
aximum MAC address length (Infiniband uses 20 bytes)
static
const
unsigned
int
MAX_MAC_LEN
=
20
;
///
t
ype that defines list of addresses
///
T
ype that defines list of addresses
typedef
std
::
vector
<
isc
::
asiolink
::
IOAddress
>
AddressCollection
;
/// type that holds a list of socket informations
/// @brief Type that holds a list of socket information.
///
/// @warning The type of the container used here must guarantee
/// that the iterators do not invalidate when erase() is called.
/// This is because, the \ref closeSockets function removes
/// elements selectively by calling erase on the element to be
/// removed and further iterates through remaining elements.
///
/// @todo: Add SocketCollectionConstIter type
typedef
std
::
list
<
SocketInfo
>
SocketCollection
;
...
...
@@ -167,7 +174,7 @@ public:
/// @brief Sets flag_*_ fields based on bitmask value returned by OS
///
///
N
ote
:
Implementation of this method is OS-dependent as bits have
///
@n
ote Implementation of this method is OS-dependent as bits have
/// different meaning on each OS.
///
/// @param flags bitmask value returned by OS in interface detection
...
...
@@ -258,53 +265,53 @@ public:
const
SocketCollection
&
getSockets
()
const
{
return
sockets_
;
}
protected:
///
s
ocket used to send
ing
data
///
S
ocket used to send data
.
SocketCollection
sockets_
;
///
n
etwork interface name
///
N
etwork interface name
.
std
::
string
name_
;
///
i
nterface index (a value that uniquely indentifies an interface)
///
I
nterface index (a value that uniquely indentifies an interface)
.
int
ifindex_
;
///
l
ist of assigned addresses
///
L
ist of assigned addresses
.
AddressCollection
addrs_
;
///
l
ink-layer address
///
L
ink-layer address
.
uint8_t
mac_
[
MAX_MAC_LEN
];
///
l
ength of link-layer address (usually 6)
///
L
ength of link-layer address (usually 6)
.
size_t
mac_len_
;
///
h
ardware type
///
H
ardware type
.
uint16_t
hardware_type_
;
public:
/// @todo: Make those fields protected once we start supporting more
/// than just Linux
///
s
pecifies if selected interface is loopback
///
S
pecifies if selected interface is loopback
.
bool
flag_loopback_
;
///
s
pecifies if selected interface is up
///
S
pecifies if selected interface is up
.
bool
flag_up_
;
///
f
lag specifies if selected interface is running
/// (e.g. cable plugged in, wifi associated)
///
F
lag specifies if selected interface is running
/// (e.g. cable plugged in, wifi associated)
.
bool
flag_running_
;
///
f
lag specifies if selected interface is multicast capable
///
F
lag specifies if selected interface is multicast capable
.
bool
flag_multicast_
;
///
f
lag specifies if selected interface is broadcast capable
///
F
lag specifies if selected interface is broadcast capable
.
bool
flag_broadcast_
;
///
i
nterface flags (this value is as is returned by OS,
/// it may mean different things on different OSes)
///
I
nterface flags (this value is as is returned by OS,
/// it may mean different things on different OSes)
.
uint32_t
flags_
;
};
/// @brief
h
andles network interfaces, transmission and reception
/// @brief
H
andles network interfaces, transmission and reception
.
///
/// IfaceMgr is an interface manager class that detects available network
/// interfaces, configured addresses, link-local addresses, and provides
...
...
@@ -312,7 +319,7 @@ public:
///
class
IfaceMgr
:
public
boost
::
noncopyable
{
public:
///
d
efines callback used when commands are received over control session
///
D
efines callback used when commands are received over control session
.
typedef
void
(
*
SessionCallback
)
(
void
);
/// @brief Packet reception buffer size
...
...
@@ -328,7 +335,7 @@ public:
// 2 maps (ifindex-indexed and name-indexed) and
// also hide it (make it public make tests easier for now)
///
t
ype that holds a list of interfaces
///
T
ype that holds a list of interfaces
.
typedef
std
::
list
<
Iface
>
IfaceCollection
;
/// IfaceMgr is a singleton class. This method returns reference
...
...
@@ -401,11 +408,10 @@ public:
/// @return a socket descriptor
uint16_t
getSocket
(
const
isc
::
dhcp
::
Pkt4
&
pkt
);
///
d
ebugging method that prints out all available interfaces
///
D
ebugging method that prints out all available interfaces
.
///
/// @param out specifies stream to print list of interfaces to
void
printIfaces
(
std
::
ostream
&
out
=
std
::
cout
);
void
printIfaces
(
std
::
ostream
&
out
=
std
::
cout
);
/// @brief Sends an IPv6 packet.
///
...
...
@@ -563,7 +569,7 @@ public:
const
bool
use_bcast
=
true
);
/// @brief Closes all open sockets.
/// Is used in destructor, but also from Dhcpv4
_s
rv and Dhcpv6
_s
rv classes.
/// Is used in destructor, but also from Dhcpv4
S
rv and Dhcpv6
S
rv classes.
void
closeSockets
();
/// @brief Closes all IPv4 or IPv6 sockets.
...
...
@@ -587,7 +593,7 @@ public:
/// @throw BadValue if family value is different than AF_INET or AF_INET6.
void
closeSockets
(
const
uint16_t
family
);
/// @brief
r
eturns number of detected interfaces
/// @brief
R
eturns number of detected interfaces
.
///
/// @return number of detected interfaces
uint16_t
countIfaces
()
{
return
ifaces_
.
size
();
}
...
...
@@ -618,7 +624,7 @@ public:
///
/// @throw InvalidPacketFilter if provided packet filter object is NULL.
/// @throw PacketFilterChangeDenied if there are open IPv4 sockets
void
setPacketFilter
(
const
boost
::
shared_ptr
<
PktFilter
>
&
packet_filter
);
void
setPacketFilter
(
const
PktFilter
Ptr
&
packet_filter
);
/// @brief Set Packet Filter object to handle send/receive packets.
///
...
...
@@ -718,14 +724,14 @@ protected:
//int recvsock_; // TODO: should be fd_set eventually, but we have only
//int sendsock_; // 2 sockets for now. Will do for until next release
//
w
e can't use the same socket, as receiving socket
//
W
e can't use the same socket, as receiving socket
// is bound to multicast address. And we all know what happens
// to people who try to use multicast as source address.
///
l
ength of the control_buf_ array
///
L
ength of the control_buf_ array
size_t
control_buf_len_
;
///
c
ontrol-buffer, used in transmission and reception
///
C
ontrol-buffer, used in transmission and reception
.
boost
::
scoped_array
<
char
>
control_buf_
;
/// @brief A wrapper for OS-specific operations before sending IPv4 packet
...
...
@@ -745,10 +751,10 @@ protected:
/// @return true if successful, false otherwise
bool
os_receive4
(
struct
msghdr
&
m
,
Pkt4Ptr
&
pkt
);
///
s
ocket descriptor of the session socket
///
S
ocket descriptor of the session socket
.
int
session_socket_
;
///
a
callback that will be called when data arrives over session_socket_
///
A
callback that will be called when data arrives over session_socket_
.
SessionCallback
session_callback_
;
private:
...
...
@@ -795,7 +801,7 @@ private:
/// families, e.g. AF_INET, AF_PACKET etc. Another possible type of
/// Packet Filter is the one used for unit testing, which doesn't
/// open sockets but rather mimics their behavior (mock object).
boost
::
shared_ptr
<
PktFilter
>
packet_filter_
;
PktFilter
Ptr
packet_filter_
;
};
};
// namespace isc::dhcp
...
...
src/lib/dhcp/iface_mgr_bsd.cc
View file @
5162bd77
...
...
@@ -54,8 +54,7 @@ void
IfaceMgr
::
setMatchingPacketFilter
(
const
bool
/* direct_response_desired */
)
{
// @todo Currently we ignore the preference to use direct traffic
// because it hasn't been implemented for BSD systems.
boost
::
shared_ptr
<
PktFilter
>
pkt_filter
(
new
PktFilterInet
());
setPacketFilter
(
pkt_filter
);
setPacketFilter
(
PktFilterPtr
(
new
PktFilterInet
()));
}
...
...
src/lib/dhcp/iface_mgr_linux.cc
View file @
5162bd77
...
...
@@ -515,12 +515,10 @@ void Iface::setFlags(uint32_t flags) {
void
IfaceMgr
::
setMatchingPacketFilter
(
const
bool
direct_response_desired
)
{
if
(
direct_response_desired
)
{
boost
::
shared_ptr
<
PktFilter
>
pkt_filter
(
new
PktFilterLPF
());
setPacketFilter
(
pkt_filter
);
setPacketFilter
(
PktFilterPtr
(
new
PktFilterLPF
()));
}
else
{
boost
::
shared_ptr
<
PktFilter
>
pkt_filter
(
new
PktFilterInet
());
setPacketFilter
(
pkt_filter
);
setPacketFilter
(
PktFilterPtr
(
new
PktFilterInet
()));
}
}
...
...
src/lib/dhcp/iface_mgr_sun.cc
View file @
5162bd77
...
...
@@ -54,8 +54,7 @@ void
IfaceMgr
::
setMatchingPacketFilter
(
const
bool
/* direct_response_desired */
)
{
// @todo Currently we ignore the preference to use direct traffic
// because it hasn't been implemented for Solaris.
boost
::
shared_ptr
<
PktFilter
>
pkt_filter
(
new
PktFilterInet
());
setPacketFilter
(
pkt_filter
);
setPacketFilter
(
PktFilterPtr
(
new
PktFilterInet
()));
}
}
// end of isc::dhcp namespace
...
...
src/lib/dhcp/pkt4.cc
View file @
5162bd77
...
...
@@ -284,7 +284,8 @@ Pkt4::setHWAddr(uint8_t htype, uint8_t hlen,
void
Pkt4
::
setHWAddr
(
const
HWAddrPtr
&
addr
)
{
if
(
!
addr
)
{
isc_throw
(
BadValue
,
"Setting hw address to NULL is forbidden"
);
isc_throw
(
BadValue
,
"Setting DHCPv4 chaddr field to NULL"
<<
" is forbidden"
);
}
hwaddr_
=
addr
;
}
...
...
@@ -315,7 +316,8 @@ Pkt4::setLocalHWAddr(const uint8_t htype, const uint8_t hlen,
void
Pkt4
::
setLocalHWAddr
(
const
HWAddrPtr
&
addr
)
{
if
(
!
addr
)
{
isc_throw
(
BadValue
,
"Setting HW address to NULL is forbidden"
);
isc_throw
(
BadValue
,
"Setting local HW address to NULL is"
<<
" forbidden."
);
}
local_hwaddr_
=
addr
;
}
...
...
@@ -329,7 +331,8 @@ Pkt4::setRemoteHWAddr(const uint8_t htype, const uint8_t hlen,
void
Pkt4
::
setRemoteHWAddr
(
const
HWAddrPtr
&
addr
)
{
if
(
!
addr
)
{
isc_throw
(
BadValue
,
"Setting HW address to NULL is forbidden"
);
isc_throw
(
BadValue
,
"Setting remote HW address to NULL is"
<<
" forbidden."
);
}
remote_hwaddr_
=
addr
;
}
...
...
src/lib/dhcp/pkt_filter.h
View file @
5162bd77
...
...
@@ -29,6 +29,7 @@ public:
isc
::
Exception
(
file
,
line
,
what
)
{
};
};
/// Forward declaration to the structure describing a socket.
struct
SocketInfo
;
/// Forward declaration to the class representing interface
...
...
src/lib/dhcp/pkt_filter_inet.cc
View file @
5162bd77
...
...
@@ -53,7 +53,7 @@ int PktFilterInet::openSocket(const Iface& iface,
}
#ifdef SO_BINDTODEVICE
if
(
receive_bcast
)
{
if
(
receive_bcast
&&
iface
.
flag_broadcast_
)
{
// Bind to device so as we receive traffic on a specific interface.
if
(
setsockopt
(
sock
,
SOL_SOCKET
,
SO_BINDTODEVICE
,
iface
.
getName
().
c_str
(),
iface
.
getName
().
length
()
+
1
)
<
0
)
{
...
...
src/lib/dhcp/pkt_filter_lpf.cc
View file @
5162bd77
...
...
@@ -26,45 +26,66 @@
namespace
{
/// Socket filter program, used to filter out all traffic other
/// then DHCP. In particular, it allows receipt of UDP packets
using
namespace
isc
::
dhcp
;
/// The socket filter program, used to filter out all traffic other
/// than DHCP. In particular, it allows receipt of UDP packets
/// on a specific (customizable) port. It does not allow fragmented
/// packets.
///
/// Socket filter program is platform independent code which is
/// executed on the kernel level when new packet arrives. This concept
/// origins from the Berkeley Packet Filtering supported on BSD systems.
/// origin
ate
s from the Berkeley Packet Filtering supported on BSD systems.
///
/// @todo We may want to extend the filter to receive packets sent
/// to the particular IP address assigned to the interface or
/// broadcast address.
struct
sock_filter
dhcp_sock_filter
[]
=
{
// Make sure this is an IP packet...
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_ABS
,
12
),
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
ETHERTYPE_IP
,
0
,
8
),
// Make sure it's a UDP packet...
BPF_STMT
(
BPF_LD
+
BPF_B
+
BPF_ABS
,
23
),
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
IPPROTO_UDP
,
0
,
6
),
// Make sure this isn't a fragment...
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_ABS
,
20
),
// Make sure this is an IP packet: check the half-word (two bytes)
// at offset 12 in the packet (the Ethernet packet type). If it
// is, advance to the next instruction. If not, advance 8
// instructions (which takes execution to the last instruction in
// the sequence: "drop it").
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_ABS
,
ETHERNET_PACKET_TYPE_OFFSET
),
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
ETHERTYPE_IP
,
0
,
8
),
// Make sure it's a UDP packet. The IP protocol is at offset
// 9 in the IP header so, adding the Ethernet packet header size
// of 14 bytes gives an absolute byte offset in the packet of 23.
BPF_STMT
(
BPF_LD
+
BPF_B
+
BPF_ABS
,
ETHERNET_HEADER_LEN
+
IP_PROTO_TYPE_OFFSET
),
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
IPPROTO_UDP
,
0
,
6
),
// Make sure this isn't a fragment by checking that the fragment
// offset field in the IP header is zero. This field is the
// least-significant 13 bits in the bytes at offsets 6 and 7 in
// the IP header, so the half-word at offset 20 (6 + size of
// Ethernet header) is loaded and an appropriate mask applied.
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_ABS
,
ETHERNET_HEADER_LEN
+
IP_FLAGS_OFFSET
),
BPF_JUMP
(
BPF_JMP
+
BPF_JSET
+
BPF_K
,
0x1fff
,
4
,
0
),
// Get the IP header length...
BPF_STMT
(
BPF_LDX
+
BPF_B
+
BPF_MSH
,
14
),
// Make sure it's to the right port...
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_IND
,
16
),
// Use default DHCP server port, but it can be
// replaced if neccessary.
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
isc
::
dhcp
::
DHCP4_SERVER_PORT
,
0
,
1
),
// Get the IP header length. This is achieved by the following
// (special) instruction that, given the offset of the start
// of the IP header (offset 14) loads the IP header length.
BPF_STMT
(
BPF_LDX
+
BPF_B
+
BPF_MSH
,
ETHERNET_HEADER_LEN
),
// Make sure it's to the right port. The following instruction
// adds the previously extracted IP header length to the given
// offset to locate the correct byte. The given offset of 16
// comprises the length of the Ethernet header (14) plus the offset
// of the UDP destination port (2) within the UDP header.
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_IND
,
ETHERNET_HEADER_LEN
+
UDP_DEST_PORT
),
// The following instruction tests against the default DHCP server port,
// but the action port is actually set in PktFilterLPF::openSocket().
// N.B. The code in that method assumes that this instruction is at
// offset 8 in the program. If this is changed, openSocket() must be
// updated.
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
DHCP4_SERVER_PORT
,
0
,
1
),
// If we passed all the tests, ask for the whole packet.
BPF_STMT
(
BPF_RET
+
BPF_K
,
(
u_int
)
-
1
),
BPF_STMT
(
BPF_RET
+
BPF_K
,
(
u_int
)
-
1
),
// Otherwise, drop it.
BPF_STMT
(
BPF_RET
+
BPF_K
,
0
),
BPF_STMT
(
BPF_RET
+
BPF_K
,
0
),
};
}
...
...
@@ -107,6 +128,10 @@ PktFilterLPF::openSocket(const Iface& iface, const isc::asiolink::IOAddress&,
sa
.
sll_family
=
AF_PACKET
;
sa
.
sll_ifindex
=
iface
.
getIndex
();
// For raw sockets we construct IP headers on our own, so we don't bind
// socket to IP address but to the interface. We will later use the
// Linux Packet Filtering to filter out these packets that we are
// interested in.
if
(
bind
(
sock
,
reinterpret_cast
<
const
struct
sockaddr
*>
(
&
sa
),
sizeof
(
sa
))
<
0
)
{
close
(
sock
);
...
...
@@ -120,9 +145,13 @@ PktFilterLPF::openSocket(const Iface& iface, const isc::asiolink::IOAddress&,
Pkt4Ptr
PktFilterLPF
::
receive
(
const
Iface
&
iface
,
const
SocketInfo
&
socket_info
)
{
// @todo: implement this function
uint8_t
raw_buf
[
IfaceMgr
::
RCVBUFSIZE
];
int
data_len
=
read
(
socket_info
.
sockfd_
,
raw_buf
,
sizeof
(
raw_buf
));
// If negative value is returned by read(), it indicates that an
// error occured. If returned value is 0, no data was read from the
// socket. In both cases something has gone wrong, because we expect
// that a chunk of data is there. We signal the lack of data by
// returing an empty packet.
if
(
data_len
<=
0
)
{
return
Pkt4Ptr
();
}
...
...
@@ -131,9 +160,12 @@ PktFilterLPF::receive(const Iface& iface, const SocketInfo& socket_info) {
// @todo: This is awkward way to solve the chicken and egg problem
// whereby we don't know the offset where DHCP data start in the
// received buffer when we create the packet object. The dummy
// object is created so as we can pass it to the functions which
// decode IP stack and find actual offset of the DHCP packet.
// received buffer when we create the packet object. In general case,
// the IP header has variable length. The information about its length
// is stored in one of its fields. Therefore, we have to decode the
// packet to get the offset of the DHCP data. The dummy object is
// created so as we can pass it to the functions which decode IP stack
// and find actual offset of the DHCP data.
// Once we find the offset we can create another Pkt4 object from
// the reminder of the input buffer and set the IP addresses and
// ports from the dummy packet. We should consider doing it
...
...
@@ -180,11 +212,17 @@ PktFilterLPF::send(const Iface& iface, uint16_t sockfd, const Pkt4Ptr& pkt) {
// are valid because they are checked by the function called.
writeEthernetHeader
(
pkt
,
buf
);
// This object represents broadcast address. We will compare the
// local packet address with it a few lines below. Having static
// variable guarantees that this object is created only once, not
// every time this function is called.
static
const
isc
::
asiolink
::
IOAddress
bcast_addr
(
"255.255.255.255"
);
// It is likely that the local address in pkt object is set to
// broadcast address. This is the case if server received the
// client's packet on broadcast address. Therefore, we need to
// correct it here and assign the actual source address.
if
(
pkt
->
getLocalAddr
()
.
toText
()
==
"255.255.255.255"
)
{
if
(
pkt
->
getLocalAddr
()
==
bcast_addr
)
{
const
Iface
::
SocketCollection
&
sockets
=
iface
.
getSockets
();
for
(
Iface
::
SocketCollection
::
const_iterator
it
=
sockets
.
begin
();
it
!=
sockets
.
end
();
++
it
)
{
...
...
src/lib/dhcp/protocol_util.cc
View file @
5162bd77
...
...
@@ -16,6 +16,7 @@
#include
<dhcp/dhcp6.h>
#include
<dhcp/protocol_util.h>
#include
<boost/static_assert.hpp>
#include
<net/ethernet.h>
// in_systm.h is required on some some BSD systems
// complaining that n_time is undefined but used
// in ip.h.
...
...
@@ -34,7 +35,8 @@ decodeEthernetHeader(InputBuffer& buf, Pkt4Ptr& pkt) {
// then the size of the Ethernet frame header.
if
(
buf
.
getLength
()
-
buf
.
getPosition
()
<
ETHERNET_HEADER_LEN
)
{
isc_throw
(
InvalidPacketHeader
,
"size of ethernet header in received "
<<
"packet is invalid, expected at least 14 bytes, received "
<<
"packet is invalid, expected at least "
<<
ETHERNET_HEADER_LEN
<<
" bytes, received "
<<
buf
.
getLength
()
-
buf
.
getPosition
()
<<
" bytes"
);
}
// Packet object must not be NULL. We want to output some values
...
...
@@ -92,7 +94,9 @@ decodeIpUdpHeader(InputBuffer& buf, Pkt4Ptr& pkt) {
// IP length is the number of 4 byte chunks that construct IPv4 header.
// It must not be lower than 5 because first 20 bytes are fixed.
if
(
ip_len
<
5
)
{
ip_len
=
5
;
isc_throw
(
InvalidPacketHeader
,
"Value of the length of the IP header must not be"
<<
" lower than 5 words. The length of the received header is "
<<
ip_len
<<
"."
);
}
// Seek to the position of source IP address.
...
...
@@ -102,7 +106,8 @@ decodeIpUdpHeader(InputBuffer& buf, Pkt4Ptr& pkt) {
// Read destination address.
pkt
->
setLocalAddr
(
IOAddress
(
buf
.
readUint32
()));
// Skip IP header options (if any).
// Skip IP header options (if any) to start of the
// UDP header.
buf
.
setPosition
(
start_pos
+
ip_len
*
4
);
// Read source port from UDP header.
...
...
@@ -110,7 +115,8 @@ decodeIpUdpHeader(InputBuffer& buf, Pkt4Ptr& pkt) {
// Read destination port from UDP header.
pkt
->
setLocalPort
(
buf
.
readUint16
());
// Set the pointer position to the tail of UDP header.
// Set the pointer position to the first byte o the
// UDP payload (DHCP packet).
buf
.
setPosition
(
start_pos
+
ip_len
*
4
+
UDP_HEADER_LEN
);
}
...
...
@@ -156,7 +162,7 @@ writeEthernetHeader(const Pkt4Ptr& pkt, OutputBuffer& out_buf) {
}
// Type IP.
out_buf
.
writeUint16
(
0x0800
);
out_buf
.
writeUint16
(
ETHERTYPE_IP
);
}
void
...
...
@@ -216,7 +222,7 @@ uint16_t
calcChecksum
(
const
uint8_t
*
buf
,
const
uint32_t
buf_size
,
uint32_t
sum
)
{
uint32_t
i
;
for
(
i
=
0
;
i
<
(
buf_size
&
~
1U
);
i
+=
2
)
{
uint16_t
chunk
=
buf
[
i
]
<<
8
|
buf
[
i
+
1
];
uint16_t
chunk
=
buf
[
i
]
<<
8
|
buf
[
i
+
1
];
sum
+=
chunk
;
if
(
sum
>
0xFFFF
)
{
sum
-=
0xFFFF
;
...
...
src/lib/dhcp/protocol_util.h
View file @
5162bd77
...
...
@@ -35,19 +35,31 @@ public: