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
45e29ee0
Commit
45e29ee0
authored
Apr 16, 2013
by
Marcin Siodelski
Browse files
[2902] Basic implementation to send packet over raw socket.
parent
f85cdd32
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/lib/dhcp/hwaddr.h
View file @
45e29ee0
...
...
@@ -27,6 +27,10 @@ namespace dhcp {
/// @brief Hardware type that represents information from DHCPv4 packet
struct
HWAddr
{
public:
/// @brief Size of an ethernet hardware address.
static
const
size_t
ETHERNET_HWADDR_LEN
=
6
;
/// @brief Maximum size of a hardware address.
static
const
size_t
MAX_HWADDR_LEN
=
20
;
...
...
src/lib/dhcp/iface_mgr.cc
View file @
45e29ee0
...
...
@@ -758,7 +758,7 @@ IfaceMgr::send(const Pkt4Ptr& pkt) {
// Skip checking if packet filter is non-NULL because it has been
// already checked when packet filter was set.
return
(
packet_filter_
->
send
(
getSocket
(
*
pkt
),
pkt
));
return
(
packet_filter_
->
send
(
*
iface
,
getSocket
(
*
pkt
),
pkt
));
}
...
...
src/lib/dhcp/pkt_filter.h
View file @
45e29ee0
...
...
@@ -16,6 +16,7 @@
#define PKT_FILTER_H
#include
<asiolink/io_address.h>
#include
<boost/shared_ptr.hpp>
namespace
isc
{
namespace
dhcp
{
...
...
@@ -71,13 +72,18 @@ public:
/// @brief Send packet over specified socket.
///
/// @param iface interface to be used to send packet
/// @param sockfd socket descriptor
/// @param pkt packet to be sent
///
/// @return result of sending the packet. It is 0 if successful.
virtual
int
send
(
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
)
=
0
;
virtual
int
send
(
const
Iface
&
iface
,
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
)
=
0
;
};
/// Pointer to a PktFilter object.
typedef
boost
::
shared_ptr
<
PktFilter
>
PktFilterPtr
;
}
// namespace isc::dhcp
}
// namespace isc
...
...
src/lib/dhcp/pkt_filter_inet.cc
View file @
45e29ee0
...
...
@@ -198,7 +198,8 @@ PktFilterInet::receive(const Iface& iface, const SocketInfo& socket_info) {
}
int
PktFilterInet
::
send
(
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
)
{
PktFilterInet
::
send
(
const
Iface
&
,
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
)
{
memset
(
&
control_buf_
[
0
],
0
,
control_buf_len_
);
// Set the target address we're sending to.
...
...
src/lib/dhcp/pkt_filter_inet.h
View file @
45e29ee0
...
...
@@ -57,11 +57,13 @@ public:
/// @brief Send packet over specified socket.
///
/// @param iface interface to be used to send packet
/// @param sockfd socket descriptor
/// @param pkt packet to be sent
///
/// @return result of sending a packet. It is 0 if successful.
virtual
int
send
(
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
);
virtual
int
send
(
const
Iface
&
iface
,
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
);
private:
/// Length of the control_buf_ array.
...
...
src/lib/dhcp/pkt_filter_lpf.cc
View file @
45e29ee0
...
...
@@ -16,16 +16,118 @@
#include
<dhcp/iface_mgr.h>
#include
<dhcp/pkt4.h>
#include
<dhcp/pkt_filter_lpf.h>
#include
<exceptions/exceptions.h>
#include
<linux/if_ether.h>
#include
<linux/if_packet.h>
#include
<netinet/ip.h>
#include
<netinet/udp.h>
using
namespace
isc
::
util
;
namespace
isc
{
namespace
dhcp
{
void
PktFilterLPF
::
assembleEthernetHeader
(
const
Iface
&
iface
,
const
Pkt4Ptr
&
pkt
,
util
::
OutputBuffer
&
out_buf
)
{
std
::
vector
<
uint8_t
>
dest_addr
=
pkt
->
getHWAddr
()
->
hwaddr_
;
if
(
dest_addr
.
empty
())
{
dest_addr
.
resize
(
HWAddr
::
ETHERNET_HWADDR_LEN
);
}
out_buf
.
writeData
(
&
dest_addr
[
0
],
dest_addr
.
size
());
out_buf
.
writeData
(
iface
.
getMac
(),
iface
.
getMacLen
());
out_buf
.
writeUint16
(
0x0800
);
}
void
PktFilterLPF
::
assembleIpUdpHeader
(
const
Pkt4Ptr
&
pkt
,
util
::
OutputBuffer
&
out_buf
)
{
struct
ip
ip_hdr
;
memset
(
&
ip_hdr
,
0
,
sizeof
(
ip_hdr
));
ip_hdr
.
ip_hl
=
(
ip_hdr
.
ip_hl
|
5
)
&
0xF
;
ip_hdr
.
ip_v
=
(
ip_hdr
.
ip_v
|
4
)
&
0xF
;
ip_hdr
.
ip_tos
=
IPTOS_LOWDELAY
;
ip_hdr
.
ip_len
=
htons
(
sizeof
(
ip
)
+
sizeof
(
udphdr
)
+
pkt
->
getBuffer
().
getLength
());
ip_hdr
.
ip_id
=
0
;
ip_hdr
.
ip_off
=
0
;
ip_hdr
.
ip_ttl
=
128
;
ip_hdr
.
ip_p
=
IPPROTO_UDP
;
ip_hdr
.
ip_src
.
s_addr
=
htonl
(
pkt
->
getLocalAddr
());
ip_hdr
.
ip_dst
.
s_addr
=
htonl
(
pkt
->
getRemoteAddr
());
ip_hdr
.
ip_sum
=
checksumFinish
(
checksum
(
reinterpret_cast
<
const
char
*>
(
&
ip_hdr
),
sizeof
(
ip_hdr
)));
out_buf
.
writeData
(
static_cast
<
void
*>
(
&
ip_hdr
),
sizeof
(
ip_hdr
));
struct
udphdr
udp_hdr
;
memset
(
&
udp_hdr
,
0
,
sizeof
(
udp_hdr
));
udp_hdr
.
source
=
htons
(
pkt
->
getLocalPort
());
udp_hdr
.
dest
=
htons
(
pkt
->
getRemotePort
());
udp_hdr
.
len
=
htons
(
sizeof
(
udp_hdr
)
+
pkt
->
getBuffer
().
getLength
());
udp_hdr
.
check
=
0
;
out_buf
.
writeData
(
static_cast
<
void
*>
(
&
udp_hdr
),
sizeof
(
udp_hdr
));
}
uint16_t
PktFilterLPF
::
checksum
(
const
char
*
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
];
sum
+=
chunk
;
if
(
sum
>
0xFFFF
)
{
sum
-=
0xFFFF
;
}
}
if
(
i
<
buf_size
)
{
sum
+=
buf
[
i
]
<<
8
;
if
(
sum
>
0xFFFF
)
{
sum
-=
0xFFFF
;
}
}
return
(
sum
);
}
uint16_t
PktFilterLPF
::
checksumFinish
(
uint16_t
sum
)
{
return
(
htons
(
~
sum
));
}
int
PktFilterLPF
::
openSocket
(
const
Iface
&
,
const
isc
::
asiolink
::
IOAddress
&
,
PktFilterLPF
::
openSocket
(
const
Iface
&
iface
,
const
isc
::
asiolink
::
IOAddress
&
,
const
uint16_t
,
const
bool
,
const
bool
)
{
isc_throw
(
isc
::
NotImplemented
,
"Linux Packet Filtering is not implemented yet"
);
int
sock
=
socket
(
AF_PACKET
,
SOCK_RAW
,
htons
(
ETH_P_ALL
));
if
(
sock
<
0
)
{
isc_throw
(
SocketConfigError
,
"Failed to create raw LPF socket"
);
}
struct
sockaddr_ll
sa
;
memset
(
&
sa
,
0
,
sizeof
(
sockaddr_ll
));
sa
.
sll_family
=
AF_PACKET
;
sa
.
sll_ifindex
=
iface
.
getIndex
();
if
(
bind
(
sock
,
reinterpret_cast
<
const
struct
sockaddr
*>
(
&
sa
),
sizeof
(
sa
))
<
0
)
{
close
(
sock
);
isc_throw
(
SocketConfigError
,
"Failed to bind LPF socket '"
<<
sock
<<
"' to interface '"
<<
iface
.
getName
()
<<
"'"
);
}
return
(
sock
);
}
Pkt4Ptr
...
...
@@ -35,9 +137,30 @@ PktFilterLPF::receive(const Iface&, const SocketInfo&) {
}
int
PktFilterLPF
::
send
(
uint16_t
,
const
Pkt4Ptr
&
)
{
isc_throw
(
isc
::
NotImplemented
,
"Linux Packet Filtering is not implemented yet"
);
PktFilterLPF
::
send
(
const
Iface
&
iface
,
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
)
{
OutputBuffer
buf
(
14
);
assembleEthernetHeader
(
iface
,
pkt
,
buf
);
assembleIpUdpHeader
(
pkt
,
buf
);
buf
.
writeData
(
pkt
->
getBuffer
().
getData
(),
pkt
->
getBuffer
().
getLength
());
sockaddr_ll
sa
;
sa
.
sll_family
=
AF_PACKET
;
sa
.
sll_ifindex
=
iface
.
getIndex
();
sa
.
sll_protocol
=
htons
(
ETH_P_IP
);
sa
.
sll_halen
=
6
;
int
result
=
sendto
(
sockfd
,
buf
.
getData
(),
buf
.
getLength
(),
0
,
reinterpret_cast
<
const
struct
sockaddr
*>
(
&
sa
),
sizeof
(
sockaddr_ll
));
if
(
result
<
0
)
{
isc_throw
(
SocketWriteError
,
"pkt4 send failed"
);
}
return
(
0
);
}
...
...
src/lib/dhcp/pkt_filter_lpf.h
View file @
45e29ee0
...
...
@@ -17,6 +17,8 @@
#include
<dhcp/pkt_filter.h>
#include
<util/buffer.h>
namespace
isc
{
namespace
dhcp
{
...
...
@@ -57,13 +59,29 @@ public:
/// @brief Send packet over specified socket.
///
/// @oaram iface interface to be used to send packet
/// @param sockfd socket descriptor
/// @param pkt packet to be sent
///
/// @throw isc::NotImplemented always
/// @return result of sending a packet. It is 0 if successful.
virtual
int
send
(
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
);
virtual
int
send
(
const
Iface
&
iface
,
uint16_t
sockfd
,
const
Pkt4Ptr
&
pkt
);
protected:
static
void
assembleEthernetHeader
(
const
Iface
&
iface
,
const
Pkt4Ptr
&
pkt
,
util
::
OutputBuffer
&
out_buf
);
static
void
assembleIpUdpHeader
(
const
Pkt4Ptr
&
pkt
,
util
::
OutputBuffer
&
out_buf
);
static
uint16_t
checksum
(
const
char
*
buf
,
const
uint32_t
buf_size
,
uint32_t
sum
=
0
);
static
uint16_t
checksumFinish
(
uint16_t
sum
);
};
}
// namespace isc::dhcp
...
...
src/lib/dhcp/tests/iface_mgr_unittest.cc
View file @
45e29ee0
...
...
@@ -19,6 +19,7 @@
#include
<dhcp/iface_mgr.h>
#include
<dhcp/pkt6.h>
#include
<dhcp/pkt_filter.h>
#include
<dhcp/pkt_filter_lpf.h>
#include
<boost/scoped_ptr.hpp>
#include
<gtest/gtest.h>
...
...
@@ -91,7 +92,7 @@ public:
}
/// Does nothing
virtual
int
send
(
uint16_t
,
const
Pkt4Ptr
&
)
{
virtual
int
send
(
const
Iface
&
,
uint16_t
,
const
Pkt4Ptr
&
)
{
return
(
0
);
}
...
...
@@ -103,7 +104,9 @@ public:
class
NakedIfaceMgr
:
public
IfaceMgr
{
// "naked" Interface Manager, exposes internal fields
public:
NakedIfaceMgr
()
{
}
NakedIfaceMgr
()
{
setPacketFilter
(
PktFilterPtr
(
new
PktFilterLPF
()));
}
IfaceCollection
&
getIfacesLst
()
{
return
ifaces_
;
}
};
...
...
@@ -725,14 +728,13 @@ TEST_F(IfaceMgrTest, sendReceive4) {
// let's assume that every supported OS have lo interface
IOAddress
loAddr
(
"127.0.0.1"
);
int
socket1
=
0
,
socket2
=
0
;
int
socket1
=
0
;
EXPECT_NO_THROW
(
socket1
=
ifacemgr
->
openSocket
(
LOOPBACK
,
loAddr
,
DHCP4_SERVER_PORT
+
10000
);
socket2
=
ifacemgr
->
openSocket
(
LOOPBACK
,
loAddr
,
DHCP4_SERVER_PORT
+
10000
+
1
);
);
EXPECT_GE
(
socket1
,
0
);
EXPECT_GE
(
socket2
,
0
);
//
EXPECT_GE(socket2, 0);
boost
::
shared_ptr
<
Pkt4
>
sendPkt
(
new
Pkt4
(
DHCPDISCOVER
,
1234
)
);
...
...
@@ -765,7 +767,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
boost
::
shared_ptr
<
Pkt4
>
rcvPkt
;
EXPECT_
EQ
(
true
,
ifacemgr
->
send
(
sendPkt
));
EXPECT_
NO_THROW
(
ifacemgr
->
send
(
sendPkt
));
ASSERT_NO_THROW
(
rcvPkt
=
ifacemgr
->
receive4
(
10
));
ASSERT_TRUE
(
rcvPkt
);
// received our own packet
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment