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.");
165 uint8_t control_buf[CONTROL_BUF_LEN];
166 memset(&control_buf[0], 0, CONTROL_BUF_LEN);
167 struct sockaddr_in6 from;
168 memset(&from, 0,
sizeof(from));
171 struct timeval so_rcv_timestamp;
172 memset(&so_rcv_timestamp, 0,
sizeof(so_rcv_timestamp));
177 memset(&m, 0,
sizeof(m));
181 m.msg_namelen =
sizeof(from);
187 memset(&v, 0,
sizeof(v));
188 v.iov_base =
static_cast<void*
>(buf);
199 m.msg_control = &control_buf[0];
200 m.msg_controllen = CONTROL_BUF_LEN;
202 int result = recvmsg(socket_info.sockfd_, &m, 0);
204 struct in6_addr to_addr;
205 memset(&to_addr, 0,
sizeof(to_addr));
209 struct in6_pktinfo* pktinfo = NULL;
218 bool found_pktinfo =
false;
219 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
220 while (cmsg != NULL) {
221 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
222 (cmsg->cmsg_type == IPV6_PKTINFO)) {
224 to_addr = pktinfo->ipi6_addr;
225 ifindex = pktinfo->ipi6_ifindex;
226 found_pktinfo =
true;
231 }
else if ((cmsg->cmsg_level == SOL_SOCKET) &&
232 (cmsg->cmsg_type == SCM_TIMESTAMP)) {
233 memcpy(&so_rcv_timestamp, CMSG_DATA(cmsg),
sizeof(so_rcv_timestamp));
236 cmsg = CMSG_NXTHDR(&m, cmsg);
238 if (!found_pktinfo) {
250 reinterpret_cast<const uint8_t*
>(&to_addr));
251 if ((socket_info.addr_ ==
IOAddress(
"::")) &&
252 !(local_addr.isV6Multicast() || local_addr.isV6LinkLocal())) {
259 pkt =
Pkt6Ptr(
new Pkt6(buf, result));
260 }
catch (
const std::exception& ex) {
261 isc_throw(SocketReadError,
"failed to create new packet");
264 pkt->updateTimestamp();
273 reinterpret_cast<const uint8_t*
>(&to_addr)));
275 reinterpret_cast<const uint8_t*
>(&from.sin6_addr)));
276 pkt->setRemotePort(ntohs(from.sin6_port));
277 pkt->setIndex(ifindex);
281 pkt->setIface(received->getName());
283 isc_throw(SocketReadError,
"received packet over unknown interface"
284 <<
"(ifindex=" << pkt->getIndex() <<
")");
292PktFilterInet6::send(
const Iface&, uint16_t sockfd,
const Pkt6Ptr& pkt) {
293 uint8_t control_buf[CONTROL_BUF_LEN];
294 memset(&control_buf[0], 0, CONTROL_BUF_LEN);
298 memset(&to, 0,
sizeof(to));
299 to.sin6_family = AF_INET6;
300 to.sin6_port = htons(pkt->getRemotePort());
301 memcpy(&to.sin6_addr,
302 &pkt->getRemoteAddr().toBytes()[0],
304 to.sin6_scope_id = pkt->getIndex();
308 memset(&m, 0,
sizeof(m));
310 m.msg_namelen =
sizeof(to);
324 memset(&v, 0,
sizeof(v));
325 v.iov_base =
const_cast<void *
>(pkt->getBuffer().getDataAsVoidPtr());
326 v.iov_len = pkt->getBuffer().getLength();
336 m.msg_control = &control_buf[0];
337 m.msg_controllen = CONTROL_BUF_LEN;
338 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&m);
346 cmsg->cmsg_level = IPPROTO_IPV6;
347 cmsg->cmsg_type = IPV6_PKTINFO;
348 cmsg->cmsg_len = CMSG_LEN(
sizeof(
struct in6_pktinfo));
349 struct in6_pktinfo *pktinfo =
351 memset(pktinfo, 0,
sizeof(
struct in6_pktinfo));
352 pktinfo->ipi6_ifindex = pkt->getIndex();
360 m.msg_controllen = CMSG_SPACE(
sizeof(
struct in6_pktinfo));
362 pkt->updateTimestamp();
364 pkt->addPktEvent(PktEvent::RESPONSE_SENT);
366 int result = sendmsg(sockfd, &m, 0);
369 " 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.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
static const uint32_t RCVBUFSIZE
Packet reception buffer size.
Represents a single network interface.
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 bool joinMulticast(int sock, const std::string &ifname, const std::string &mcast)
Joins IPv6 multicast group on 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.
virtual SocketInfo openSocket(const Iface &iface, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool join_multicast)
Opens a 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 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.