16#include <netinet/in.h>
23const size_t PktFilterInet6::CONTROL_BUF_LEN = 512;
38 const bool join_multicast) {
39 struct sockaddr_in6 addr6;
40 memset(&addr6, 0,
sizeof(addr6));
41 addr6.sin6_family = AF_INET6;
42 addr6.sin6_port = htons(port);
50 addr6.sin6_scope_id = if_nametoindex(iface.
getName().c_str());
55 memcpy(&addr6.sin6_addr, &addr.
toBytes()[0],
sizeof(addr6.sin6_addr));
58 addr6.sin6_len =
sizeof(addr6);
64 int sock = socket(AF_INET6, SOCK_DGRAM, 0);
70 if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
73 <<
" on IPv6 socket.");
78 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
79 (
char *)&flag,
sizeof(flag)) < 0) {
93 if ((setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
94 (
char *)&flag,
sizeof(flag)) < 0) &&
95 (errno != ENOPROTOOPT)) {
104 if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &enable,
sizeof(enable))) {
105 const char* errmsg = strerror(errno);
107 <<
", error: " << errmsg);
113 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
114 (
char *)&flag,
sizeof(flag)) < 0) {
121 if (bind(sock, (
struct sockaddr *)&addr6,
sizeof(addr6)) < 0) {
124 char* errmsg = strerror(errno);
127 << addr.
toText() <<
"/port=" << port
131#ifdef IPV6_RECVPKTINFO
133 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
134 &flag,
sizeof(flag)) != 0) {
140 if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
141 &flag,
sizeof(flag)) != 0) {
149 if (join_multicast &&
155 <<
" multicast group.");
159 if (join_multicast &&
173 uint8_t control_buf[CONTROL_BUF_LEN];
174 memset(&control_buf[0], 0, CONTROL_BUF_LEN);
175 struct sockaddr_in6 from;
176 memset(&from, 0,
sizeof(from));
179 struct timeval so_rcv_timestamp;
180 memset(&so_rcv_timestamp, 0,
sizeof(so_rcv_timestamp));
185 memset(&m, 0,
sizeof(m));
189 m.msg_namelen =
sizeof(from);
195 memset(&v, 0,
sizeof(v));
196 v.iov_base =
static_cast<void*
>(buf);
207 m.msg_control = &control_buf[0];
208 m.msg_controllen = CONTROL_BUF_LEN;
210 int result = recvmsg(socket_info.
sockfd_, &m, 0);
212 struct in6_addr to_addr;
213 memset(&to_addr, 0,
sizeof(to_addr));
217 struct in6_pktinfo* pktinfo = NULL;
226 bool found_pktinfo =
false;
227 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
228 while (cmsg != NULL) {
229 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
230 (cmsg->cmsg_type == IPV6_PKTINFO)) {
232 to_addr = pktinfo->ipi6_addr;
233 ifindex = pktinfo->ipi6_ifindex;
234 found_pktinfo =
true;
239 }
else if ((cmsg->cmsg_level == SOL_SOCKET) &&
240 (cmsg->cmsg_type == SCM_TIMESTAMP)) {
241 memcpy(&so_rcv_timestamp, CMSG_DATA(cmsg),
sizeof(so_rcv_timestamp));
244 cmsg = CMSG_NXTHDR(&m, cmsg);
246 if (!found_pktinfo) {
258 reinterpret_cast<const uint8_t*
>(&to_addr));
259 if ((socket_info.addr_ ==
IOAddress(
"::")) &&
267 pkt =
Pkt6Ptr(
new Pkt6(buf, result));
268 }
catch (
const std::exception& ex) {
272 pkt->updateTimestamp();
281 reinterpret_cast<const uint8_t*
>(&to_addr)));
283 reinterpret_cast<const uint8_t*
>(&from.sin6_addr)));
284 pkt->setRemotePort(ntohs(from.sin6_port));
285 pkt->setIndex(ifindex);
289 pkt->setIface(received->getName());
292 <<
"(ifindex=" << pkt->getIndex() <<
")");
301 uint8_t control_buf[CONTROL_BUF_LEN];
302 memset(&control_buf[0], 0, CONTROL_BUF_LEN);
306 memset(&to, 0,
sizeof(to));
307 to.sin6_family = AF_INET6;
308 to.sin6_port = htons(pkt->getRemotePort());
309 memcpy(&to.sin6_addr,
310 &pkt->getRemoteAddr().toBytes()[0],
312 to.sin6_scope_id = pkt->getIndex();
316 memset(&m, 0,
sizeof(m));
318 m.msg_namelen =
sizeof(to);
332 memset(&v, 0,
sizeof(v));
333 v.iov_base =
const_cast<void *
>(pkt->getBuffer().getDataAsVoidPtr());
334 v.iov_len = pkt->getBuffer().getLength();
344 m.msg_control = &control_buf[0];
345 m.msg_controllen = CONTROL_BUF_LEN;
346 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&m);
354 cmsg->cmsg_level = IPPROTO_IPV6;
355 cmsg->cmsg_type = IPV6_PKTINFO;
356 cmsg->cmsg_len = CMSG_LEN(
sizeof(
struct in6_pktinfo));
357 struct in6_pktinfo *pktinfo =
359 memset(pktinfo, 0,
sizeof(
struct in6_pktinfo));
360 pktinfo->ipi6_ifindex = pkt->getIndex();
368 m.msg_controllen = CMSG_SPACE(
sizeof(
struct in6_pktinfo));
370 pkt->updateTimestamp();
374 int result = sendmsg(sockfd, &m, 0);
377 " with an error: " << strerror(errno));
The IOAddress class represents an IP addresses (version agnostic).
std::string toText() const
Convert the address to a string.
std::vector< uint8_t > toBytes() const
Return address as set of bytes.
bool isV6Multicast() const
checks whether and address is IPv6 and is multicast
bool isV6LinkLocal() const
checks whether and address is IPv6 and is link-local
static IOAddress fromBytes(short family, const uint8_t *data)
Creates an address from over wire data.
IfacePtr getIface(const unsigned int ifindex)
Returns interface specified interface index.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
static const uint32_t RCVBUFSIZE
Packet reception buffer size.
Represents a single network interface.
std::string getName() const
Returns interface name.
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.
static bool joinMulticast(int sock, const std::string &ifname, const std::string &mcast)
Joins IPv6 multicast group on a socket.
virtual int send(const Iface &iface, uint16_t sockfd, const Pkt6Ptr &pkt)
Sends DHCPv6 message through a specified interface and socket.
virtual SocketInfo openSocket(Iface &iface, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool join_multicast)
Opens a socket.
virtual bool isSocketReceivedTimeSupported() const
Check if the socket received time is supported.
virtual Pkt6Ptr receive(const SocketInfo &socket_info)
Receives DHCPv6 message on the interface.
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 ALL_DHCP_RELAY_AGENTS_AND_SERVERS
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
constexpr unsigned int UNSET_IFINDEX
A value used to signal that the interface index was not set.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
struct in6_pktinfo * convertPktInfo6(char *pktinfo)
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).