14#include <netinet/in.h>
21const size_t PktFilterInet::CONTROL_BUF_LEN = 512;
36 const bool receive_bcast,
37 const bool send_bcast) {
38 struct sockaddr_in addr4;
39 memset(&addr4, 0,
sizeof(sockaddr));
40 addr4.sin_family = AF_INET;
41 addr4.sin_port = htons(port);
46 addr4.sin_addr.s_addr = INADDR_ANY;
48 addr4.sin_addr.s_addr = htonl(addr.
toUint32());
51 int sock = socket(AF_INET, SOCK_DGRAM, 0);
57 if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
60 <<
" on socket " << sock);
65 if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &enable,
sizeof(enable))) {
66 const char* errmsg = strerror(errno);
68 <<
", error: " << errmsg);
75 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, iface.
getName().c_str(),
76 iface.
getName().length() + 1) < 0) {
79 <<
" on socket " << sock);
88 if (setsockopt(sock, IPPROTO_IP, IP_DONTFRAG, &enable,
sizeof(enable))) {
89 const char* errmsg = strerror(errno);
91 << addr.
toText() <<
", error: " << errmsg);
98 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &flag,
sizeof(flag)) < 0) {
101 <<
" on socket " << sock);
105 if (bind(sock, (
struct sockaddr *)&addr4,
sizeof(addr4)) < 0) {
109 <<
"/port=" << port);
114#if defined (IP_PKTINFO) && defined (OS_LINUX)
116 if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag,
sizeof(flag)) != 0) {
122#elif defined (IP_RECVDSTADDR) && defined (OS_BSD)
124 if (setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR, &flag,
sizeof(flag)) != 0) {
135 struct sockaddr_in from_addr;
137 uint8_t control_buf[CONTROL_BUF_LEN];
139 memset(&control_buf[0], 0, CONTROL_BUF_LEN);
140 memset(&from_addr, 0,
sizeof(from_addr));
144 memset(&m, 0,
sizeof(m));
147 m.msg_name = &from_addr;
148 m.msg_namelen =
sizeof(from_addr);
151 v.iov_base =
static_cast<void*
>(buf);
162 m.msg_control = &control_buf[0];
163 m.msg_controllen = CONTROL_BUF_LEN;
165 int result = recvmsg(socket_info.
sockfd_, &m, 0);
173 pkt->updateTimestamp();
175 unsigned int ifindex = iface.
getIndex();
177 IOAddress from(htonl(from_addr.sin_addr.s_addr));
178 uint16_t from_port = htons(from_addr.sin_port);
183 pkt->setIndex(ifindex);
184 pkt->setIface(iface.
getName());
185 pkt->setRemoteAddr(from);
186 pkt->setRemotePort(from_port);
187 pkt->setLocalPort(socket_info.
port_);
192#if defined (IP_PKTINFO) && defined (OS_LINUX)
193 struct in_pktinfo* pktinfo;
194 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
196 while (cmsg != NULL) {
197 if ((cmsg->cmsg_level == IPPROTO_IP) &&
198 (cmsg->cmsg_type == IP_PKTINFO)) {
199 pktinfo =
reinterpret_cast<struct in_pktinfo*
>(CMSG_DATA(cmsg));
201 pkt->setIndex(pktinfo->ipi_ifindex);
202 pkt->setLocalAddr(
IOAddress(htonl(pktinfo->ipi_addr.s_addr)));
215 }
else if ((cmsg->cmsg_level == SOL_SOCKET) &&
216 (cmsg->cmsg_type == SCM_TIMESTAMP)) {
218 struct timeval cmsg_time;
219 memcpy(&cmsg_time, CMSG_DATA(cmsg),
sizeof(cmsg_time));
224 cmsg = CMSG_NXTHDR(&m, cmsg);
227#elif defined (IP_RECVDSTADDR) && defined (OS_BSD)
228 struct in_addr* to_addr;
229 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
231 while (cmsg != NULL) {
232 if ((cmsg->cmsg_level == IPPROTO_IP) &&
233 (cmsg->cmsg_type == IP_RECVDSTADDR)) {
234 to_addr =
reinterpret_cast<struct in_addr*
>(CMSG_DATA(cmsg));
235 pkt->setLocalAddr(
IOAddress(htonl(to_addr->s_addr)));
240 }
else if ((cmsg->cmsg_level == SOL_SOCKET) &&
241 (cmsg->cmsg_type == SCM_TIMESTAMP)) {
243 struct timeval cmsg_time;
244 memcpy(&cmsg_time, CMSG_DATA(cmsg),
sizeof(cmsg_time));
248 cmsg = CMSG_NXTHDR(&m, cmsg);
252 pkt->addPktEvent(PktEvent::BUFFER_READ);
259 uint8_t control_buf[CONTROL_BUF_LEN];
260 memset(&control_buf[0], 0, CONTROL_BUF_LEN);
264 memset(&to, 0,
sizeof(to));
265 to.sin_family = AF_INET;
266 to.sin_port = htons(pkt->getRemotePort());
267 to.sin_addr.s_addr = htonl(pkt->getRemoteAddr().toUint32());
271 memset(&m, 0,
sizeof(m));
273 m.msg_namelen =
sizeof(to);
279 memset(&v, 0,
sizeof(v));
282 v.iov_base =
const_cast<void *
>(pkt->getBuffer().getDataAsVoidPtr());
283 v.iov_len = pkt->getBuffer().getLength();
290#if defined (IP_PKTINFO) && defined (OS_LINUX)
296 m.msg_control = &control_buf[0];
297 m.msg_controllen = CONTROL_BUF_LEN;
298 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
299 cmsg->cmsg_level = IPPROTO_IP;
300 cmsg->cmsg_type = IP_PKTINFO;
301 cmsg->cmsg_len = CMSG_LEN(
sizeof(
struct in_pktinfo));
302 struct in_pktinfo* pktinfo =(
struct in_pktinfo *)CMSG_DATA(cmsg);
303 memset(pktinfo, 0,
sizeof(
struct in_pktinfo));
309 if (pkt->indexSet()) {
310 pktinfo->ipi_ifindex = pkt->getIndex();
315 if (!pkt->getLocalAddr().isV4Zero()) {
316 pktinfo->ipi_spec_dst.s_addr = htonl(pkt->getLocalAddr().toUint32());
319 m.msg_controllen = CMSG_SPACE(
sizeof(
struct in_pktinfo));
322 pkt->updateTimestamp();
326 int result = sendmsg(sockfd, &m, 0);
329 " with an error: " << strerror(errno));
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.
std::string getName() const
Returns interface name.
unsigned int getIndex() const
Returns interface index.
bool flag_broadcast_
Flag specifies if selected interface is broadcast capable.
Represents DHCPv4 packet.
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 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 int send(const Iface &iface, uint16_t sockfd, const Pkt4Ptr &pkt)
Send packet over specified socket.
virtual Pkt4Ptr receive(Iface &iface, const SocketInfo &socket_info)
Receive packet over specified 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.
#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.
Defines the logger used by the top-level component of kea-lfc.
Holds information about socket.
int sockfd_
Socket descriptor (a.k.a. primary socket).
uint16_t port_
Socket port.