15#include <net/ethernet.h>
16#include <linux/filter.h>
17#include <linux/if_ether.h>
18#include <linux/if_packet.h>
46struct sock_filter dhcp_sock_filter [] = {
53 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_PACKET_TYPE_OFFSET),
55 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 13),
61 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
62 ETHERNET_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
64 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 11),
72 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_HEADER_LEN + IP_FLAGS_OFFSET),
74 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 9, 0),
84 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
85 ETHERNET_HEADER_LEN + IP_DEST_ADDR_OFFSET),
88 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
92 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 6),
98 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, ETHERNET_HEADER_LEN),
106 BPF_STMT(BPF_LD + BPF_H + BPF_IND, ETHERNET_HEADER_LEN + UDP_DEST_PORT),
113 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 3),
119 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, (u_int)SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
123 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1),
127 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
131 BPF_STMT(BPF_RET + BPF_K, 0),
153 const uint16_t port,
const bool,
162 int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
169 if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
173 <<
" on the socket " << sock);
178 if (setsockopt(sock, SOL_PACKET, PACKET_AUXDATA, &enable,
sizeof(enable))) {
179 const char* errmsg = strerror(errno);
181 <<
", error: " << errmsg);
185 if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &enable,
sizeof(enable))) {
186 const char* errmsg = strerror(errno);
188 <<
", error: " << errmsg);
192 struct sockaddr_ll sa;
193 memset(&sa, 0,
sizeof(sockaddr_ll));
194 sa.sll_family = AF_PACKET;
201 if (bind(sock,
reinterpret_cast<const struct sockaddr*
>(&sa),
206 <<
"' to interface '" << iface.
getName() <<
"'");
210 if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) {
213 char* errmsg = strerror(errno);
217 " LPF socket '" << sock <<
"' to interface '"
218 << iface.
getName() <<
"', reason: " << errmsg);
221 struct sock_filter zero_filter[] = { BPF_STMT(BPF_RET + BPF_K, 0) };
222 struct sock_fprog zero_filter_program;
223 memset(&zero_filter_program, 0,
sizeof(zero_filter_program));
225 zero_filter_program.filter = zero_filter;
226 zero_filter_program.len =
sizeof(zero_filter) /
sizeof(
struct sock_filter);
229 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &zero_filter_program,
230 sizeof(zero_filter_program)) < 0) {
234 <<
" on the socket " << sock);
242 datalen = recv(sock, &
data,
sizeof(
data), 0);
243 }
while (datalen > 0);
248 struct sock_fprog filter_program;
249 memset(&filter_program, 0,
sizeof(filter_program));
251 filter_program.filter = dhcp_sock_filter;
252 filter_program.len =
sizeof(dhcp_sock_filter) /
sizeof(
struct sock_filter);
257 dhcp_sock_filter[8].k = addr.
toUint32();
260 dhcp_sock_filter[11].k = port;
263 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter_program,
264 sizeof(filter_program)) < 0) {
268 <<
" on the socket " << sock);
271 return (
SocketInfo(addr, port, sock, fallback));
293 datalen = recv(socket_info.
fallbackfd_, raw_buf,
sizeof(raw_buf), 0);
294 }
while (datalen > 0);
299 int data_len = read(socket_info.
sockfd_, raw_buf,
sizeof(raw_buf));
311 const size_t CONTROL_BUF_LEN = 512;
313 uint8_t control_buf[CONTROL_BUF_LEN];
315 memset(&control_buf[0], 0, CONTROL_BUF_LEN);
319 memset(&m, 0,
sizeof(m));
322 v.iov_base =
static_cast<void*
>(msg_buf);
333 m.msg_control = &control_buf[0];
334 m.msg_controllen = CONTROL_BUF_LEN;
336 int result = recvmsg(socket_info.
sockfd_, &m, 0);
368 std::vector<uint8_t> dhcp_buf;
377 pkt->setIface(iface.
getName());
378 pkt->setLocalAddr(dummy_pkt->getLocalAddr());
379 pkt->setRemoteAddr(dummy_pkt->getRemoteAddr());
380 pkt->setLocalPort(dummy_pkt->getLocalPort());
381 pkt->setRemotePort(dummy_pkt->getRemotePort());
382 pkt->setLocalHWAddr(dummy_pkt->getLocalHWAddr());
383 pkt->setRemoteHWAddr(dummy_pkt->getRemoteHWAddr());
386 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
387 while (cmsg != NULL) {
388 if ((cmsg->cmsg_level == SOL_SOCKET) &&
389 (cmsg->cmsg_type == SCM_TIMESTAMP)) {
391 struct timeval cmsg_time;
392 memcpy(&cmsg_time, CMSG_DATA(cmsg),
sizeof(cmsg_time));
397 cmsg = CMSG_NXTHDR(&m, cmsg);
420 pkt->setLocalHWAddr(hwaddr);
433 buf.
writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
436 memset(&sa, 0x0,
sizeof(sa));
437 sa.sll_family = AF_PACKET;
439 sa.sll_protocol = htons(ETH_P_IP);
444 reinterpret_cast<const struct sockaddr*
>(&sa),
445 sizeof(sockaddr_ll));
448 << errno <<
" (check errno.h)");
The IOAddress class represents an IP addresses (version agnostic).
std::string toText() const
Convert the address to a string.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
static const uint32_t RCVBUFSIZE
Packet reception buffer size.
Represents a single network interface.
size_t getMacLen() const
Returns MAC length.
std::string getName() const
Returns interface name.
uint16_t getHWType() const
Returns hardware type of the interface.
unsigned int getIndex() const
Returns interface index.
const uint8_t * getMac() const
Returns pointer to MAC address.
Represents DHCPv4 packet.
static const std::string BUFFER_READ
Event that marks when a packet is read from the socket buffer by application.
static const std::string SOCKET_RECEIVED
Event that marks when a packet is placed in the socket buffer by the kernel.
static const std::string RESPONSE_SENT
Event that marks when a packet is been written to the socket by application.
virtual bool isSocketReceivedTimeSupported() const
Check if the socket received time is supported.
virtual int send(const Iface &iface, uint16_t sockfd, const Pkt4Ptr &pkt)
Send packet over specified socket.
virtual SocketInfo openSocket(Iface &iface, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool receive_bcast, const bool send_bcast)
Open primary and fallback socket.
virtual Pkt4Ptr receive(Iface &iface, const SocketInfo &socket_info)
Receive packet over specified socket.
virtual int openFallbackSocket(const isc::asiolink::IOAddress &addr, const uint16_t port)
Default implementation to open a fallback socket.
IfaceMgr exception thrown thrown when socket opening or configuration failed.
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
IfaceMgr exception thrown thrown when error occurred during sending data through socket.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
size_t getLength() const
Return the length of data written in the buffer.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
void decodeEthernetHeader(InputBuffer &buf, Pkt4Ptr &pkt)
Decode the Ethernet header.
void writeEthernetHeader(const Pkt4Ptr &pkt, OutputBuffer &out_buf)
Writes ethernet frame header into a buffer.
void decodeIpUdpHeader(InputBuffer &buf, Pkt4Ptr &pkt)
Decode IP and UDP header.
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
void writeIpUdpHeader(const Pkt4Ptr &pkt, util::OutputBuffer &out_buf)
Writes both IP and UDP header into output buffer.
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Holds information about socket.
int sockfd_
Socket descriptor (a.k.a. primary socket).
int fallbackfd_
Fallback socket descriptor.