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, 11),
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, 9),
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, 7, 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, 4),
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, 1),
117 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
121 BPF_STMT(BPF_RET + BPF_K, 0),
143 const uint16_t port,
const bool,
152 int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
159 if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
163 <<
" on the socket " << sock);
169 struct sock_fprog filter_program;
170 memset(&filter_program, 0,
sizeof(filter_program));
172 filter_program.filter = dhcp_sock_filter;
173 filter_program.len =
sizeof(dhcp_sock_filter) /
sizeof(
struct sock_filter);
178 dhcp_sock_filter[8].k = addr.
toUint32();
181 dhcp_sock_filter[11].k = port;
183 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter_program,
184 sizeof(filter_program)) < 0) {
188 <<
" on the socket " << sock);
193 if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &enable,
sizeof(enable))) {
194 const char* errmsg = strerror(errno);
196 <<
", error: " << errmsg);
200 struct sockaddr_ll sa;
201 memset(&sa, 0,
sizeof(sockaddr_ll));
202 sa.sll_family = AF_PACKET;
203 sa.sll_ifindex = iface.getIndex();
209 if (bind(sock,
reinterpret_cast<const struct sockaddr*
>(&sa),
214 <<
"' to interface '" << iface.getName() <<
"'");
218 if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) {
221 char* errmsg = strerror(errno);
225 " LPF socket '" << sock <<
"' to interface '"
226 << iface.getName() <<
"', reason: " << errmsg);
229 return (
SocketInfo(addr, port, sock, fallback));
252 datalen = recv(socket_info.fallbackfd_, raw_buf,
sizeof(raw_buf), 0);
253 }
while (datalen > 0);
258 int data_len = read(socket_info.sockfd_, raw_buf,
sizeof(raw_buf));
270 const size_t CONTROL_BUF_LEN = 512;
272 uint8_t control_buf[CONTROL_BUF_LEN];
274 memset(&control_buf[0], 0, CONTROL_BUF_LEN);
278 memset(&m, 0,
sizeof(m));
281 v.iov_base =
static_cast<void*
>(msg_buf);
292 m.msg_control = &control_buf[0];
293 m.msg_controllen = CONTROL_BUF_LEN;
295 int result = recvmsg(socket_info.sockfd_, &m, 0);
322 std::vector<uint8_t> dhcp_buf;
323 buf.readVector(dhcp_buf, buf.getLength() - buf.getPosition());
330 pkt->setIndex(iface.getIndex());
331 pkt->setIface(iface.getName());
332 pkt->setLocalAddr(dummy_pkt->getLocalAddr());
333 pkt->setRemoteAddr(dummy_pkt->getRemoteAddr());
334 pkt->setLocalPort(dummy_pkt->getLocalPort());
335 pkt->setRemotePort(dummy_pkt->getRemotePort());
336 pkt->setLocalHWAddr(dummy_pkt->getLocalHWAddr());
337 pkt->setRemoteHWAddr(dummy_pkt->getRemoteHWAddr());
340 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
341 while (cmsg != NULL) {
342 if ((cmsg->cmsg_level == SOL_SOCKET) &&
343 (cmsg->cmsg_type == SCM_TIMESTAMP)) {
345 struct timeval cmsg_time;
346 memcpy(&cmsg_time, CMSG_DATA(cmsg),
sizeof(cmsg_time));
351 cmsg = CMSG_NXTHDR(&m, cmsg);
371 if (iface.getMacLen() > 0) {
374 pkt->setLocalHWAddr(hwaddr);
387 buf.writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
390 memset(&sa, 0x0,
sizeof(sa));
391 sa.sll_family = AF_PACKET;
392 sa.sll_ifindex = iface.getIndex();
393 sa.sll_protocol = htons(ETH_P_IP);
397 int result = sendto(sockfd, buf.getData(), buf.getLength(), 0,
398 reinterpret_cast<const struct sockaddr*
>(&sa),
399 sizeof(sockaddr_ll));
402 << 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.
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.
#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.