Kea 2.5.8
pkt_filter_bpf.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8#include <dhcp/dhcp4.h>
9#include <dhcp/iface_mgr.h>
10#include <dhcp/pkt4.h>
11#include <dhcp/pkt_filter_bpf.h>
12#include <dhcp/protocol_util.h>
14#include <algorithm>
15#include <net/bpf.h>
16#include <netinet/if_ether.h>
17
18namespace {
19
20using namespace isc::dhcp;
21using namespace boost::posix_time;
22
24const unsigned int MAX_BPF_OPEN_ATTEMPTS = 100;
25
28const unsigned int BPF_LOCAL_LOOPBACK_HEADER_LEN = 4;
29
52struct bpf_insn ethernet_ip_udp_filter [] = {
53 // Make sure this is an IP packet: check the half-word (two bytes)
54 // at offset 12 in the packet (the Ethernet packet type). If it
55 // is, advance to the next instruction. If not, advance 11
56 // instructions (which takes execution to the last instruction in
57 // the sequence: "drop it").
58 // #0
59 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_PACKET_TYPE_OFFSET),
60 // #1
61 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 11),
62
63 // Make sure it's a UDP packet. The IP protocol is at offset
64 // 9 in the IP header so, adding the Ethernet packet header size
65 // of 14 bytes gives an absolute byte offset in the packet of 23.
66 // #2
67 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
68 ETHERNET_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
69 // #3
70 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
71
72 // Make sure this isn't a fragment by checking that the fragment
73 // offset field in the IP header is zero. This field is the
74 // least-significant 13 bits in the bytes at offsets 6 and 7 in
75 // the IP header, so the half-word at offset 20 (6 + size of
76 // Ethernet header) is loaded and an appropriate mask applied.
77 // #4
78 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_HEADER_LEN + IP_FLAGS_OFFSET),
79 // #5
80 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
81
82 // Check the packet's destination address. The program will only
83 // allow the packets sent to the broadcast address or unicast
84 // to the specific address on the interface. By default, this
85 // address is set to 0 and must be set to the specific value
86 // when the raw socket is created and the program is attached
87 // to it. The caller must assign the address to the
88 // prog.bf_insns[8].k in the network byte order.
89 // #6
90 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
91 ETHERNET_HEADER_LEN + IP_DEST_ADDR_OFFSET),
92 // If this is a broadcast address, skip the next check.
93 // #7
94 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
95 // If this is not broadcast address, compare it with the unicast
96 // address specified for the interface.
97 // #8
98 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
99
100 // Get the IP header length. This is achieved by the following
101 // (special) instruction that, given the offset of the start
102 // of the IP header (offset 14) loads the IP header length.
103 // #9
104 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, ETHERNET_HEADER_LEN),
105
106 // Make sure it's to the right port. The following instruction
107 // adds the previously extracted IP header length to the given
108 // offset to locate the correct byte. The given offset of 16
109 // comprises the length of the Ethernet header (14) plus the offset
110 // of the UDP destination port (2) within the UDP header.
111 // #10
112 BPF_STMT(BPF_LD + BPF_H + BPF_IND, ETHERNET_HEADER_LEN + UDP_DEST_PORT),
113 // The following instruction tests against the default DHCP server port,
114 // but the action port is actually set in PktFilterBPF::openSocket().
115 // N.B. The code in that method assumes that this instruction is at
116 // offset 11 in the program. If this is changed, openSocket() must be
117 // updated.
118 // #11
119 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
120
121 // If we passed all the tests, ask for the whole packet.
122 // #12
123 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
124
125 // Otherwise, drop it.
126 // #13
127 BPF_STMT(BPF_RET + BPF_K, 0),
128};
129
138struct bpf_insn loopback_ip_udp_filter [] = {
139 // Make sure this is an IP packet. The pseudo header comprises a 4-byte
140 // long value identifying the address family, which should be set to
141 // AF_INET. The default value used here (0xFFFFFFFF) must be overridden
142 // with htonl(AF_INET) from within the openSocket function.
143 // #0
144 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 0),
145 // #1
146 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xFFFFFFFF, 0, 11),
147
148 // Make sure it's a UDP packet. The IP protocol is at offset
149 // 9 in the IP header so, adding the pseudo header size 4 bytes
150 // gives an absolute byte offset in the packet of 13.
151 // #2
152 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
153 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
154 // #3
155 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
156
157 // Make sure this isn't a fragment by checking that the fragment
158 // offset field in the IP header is zero. This field is the
159 // least-significant 13 bits in the bytes at offsets 6 and 7 in
160 // the IP header, so the half-word at offset 10 (6 + size of
161 // pseudo header) is loaded and an appropriate mask applied.
162 // #4
163 BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
164 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_FLAGS_OFFSET),
165 // #5
166 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
167
168 // Check the packet's destination address. The program will only
169 // allow the packets sent to the broadcast address or unicast
170 // to the specific address on the interface. By default, this
171 // address is set to 0 and must be set to the specific value
172 // when the raw socket is created and the program is attached
173 // to it. The caller must assign the address to the
174 // prog.bf_insns[8].k in the network byte order.
175 // #6
176 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
177 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_DEST_ADDR_OFFSET),
178 // If this is a broadcast address, skip the next check.
179 // #7
180 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
181 // If this is not broadcast address, compare it with the unicast
182 // address specified for the interface.
183 // #8
184 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
185
186 // Get the IP header length. This is achieved by the following
187 // (special) instruction that, given the offset of the start
188 // of the IP header (offset 4) loads the IP header length.
189 // #9
190 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, BPF_LOCAL_LOOPBACK_HEADER_LEN),
191
192 // Make sure it's to the right port. The following instruction
193 // adds the previously extracted IP header length to the given
194 // offset to locate the correct byte. The given offset of 6
195 // comprises the length of the pseudo header (4) plus the offset
196 // of the UDP destination port (2) within the UDP header.
197 // #10
198 BPF_STMT(BPF_LD + BPF_H + BPF_IND,
199 BPF_LOCAL_LOOPBACK_HEADER_LEN + UDP_DEST_PORT),
200 // The following instruction tests against the default DHCP server port,
201 // but the action port is actually set in PktFilterBPF::openSocket().
202 // N.B. The code in that method assumes that this instruction is at
203 // offset 11 in the program. If this is changed, openSocket() must be
204 // updated.
205 // #11
206 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
207
208 // If we passed all the tests, ask for the whole packet.
209 // #12
210 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
211
212 // Otherwise, drop it.
213 // #13
214 BPF_STMT(BPF_RET + BPF_K, 0),
215};
216
217
218}
219
220using namespace isc::util;
221
222namespace isc {
223namespace dhcp {
224
227 const isc::asiolink::IOAddress& addr,
228 const uint16_t port, const bool,
229 const bool) {
230 // Open fallback socket first. If it fails, it will give us an indication
231 // that there is another service (perhaps DHCP server) running.
232 // The function will throw an exception and effectively cease opening
233 // the BPF device below.
234 int fallback = openFallbackSocket(addr, port);
235
236 // Fallback has opened, so let's open the BPF device that we will be
237 // using for receiving and sending packets. The BPF device is opened
238 // by opening a file /dev/bpf%d where %d is a number. There may be
239 // devices already open so we will try them one by one and open the
240 // one that is not busy.
241 int sock = -1;
242 for (unsigned int bpf_dev = 0;
243 bpf_dev < MAX_BPF_OPEN_ATTEMPTS && (sock < 0);
244 ++bpf_dev) {
245 std::ostringstream s;
246 s << "/dev/bpf" << bpf_dev;
247 sock = open(s.str().c_str(), O_RDWR, 0);
248 if (sock < 0) {
249 // If device is busy, try another one.
250 if (errno == EBUSY) {
251 continue;
252 }
253 // All other errors are fatal, so close the fallback socket
254 // and throw.
255 close(fallback);
257 "Failed to open BPF device " << s.str());
258 }
259 }
260
261 // Set the close-on-exec flag.
262 if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
263 close(fallback);
264 close(sock);
265 isc_throw(SocketConfigError, "Failed to set close-on-exec flag"
266 << " on BPF device with interface " << iface.getName());
267 }
268
269 // The BPF device is now open. Now it needs to be configured.
270
271 // Associate the device with the interface name.
272 struct ifreq iface_data;
273 memset(&iface_data, 0, sizeof(iface_data));
274 std::strncpy(iface_data.ifr_name, iface.getName().c_str(),
275 std::min(static_cast<int>(IFNAMSIZ),
276 static_cast<int>(iface.getName().length())));
277 if (ioctl(sock, BIOCSETIF, &iface_data) < 0) {
278 close(fallback);
279 close(sock);
280 isc_throw(SocketConfigError, "Failed to associate BPF device "
281 " with interface " << iface.getName());
282 }
283
284 // Get the BPF version supported by the kernel. Every application
285 // must check this version against the current version in use.
286 struct bpf_version ver;
287 if (ioctl(sock, BIOCVERSION, &ver) < 0) {
288 close(fallback);
289 close(sock);
290 isc_throw(SocketConfigError, "Failed to obtain the BPF version"
291 " number from the kernel");
292 }
293 // Major BPF version must match and the minor version that the kernel
294 // runs must be at least the current version in use.
295 if ((ver.bv_major != BPF_MAJOR_VERSION) ||
296 (ver.bv_minor < BPF_MINOR_VERSION)) {
297 close(fallback);
298 close(sock);
299 isc_throw(SocketConfigError, "Invalid BPF version: "
300 << ver.bv_major << "." << ver.bv_minor
301 << " Expected at least version:"
302 << BPF_MAJOR_VERSION << "."
303 << BPF_MINOR_VERSION);
304 }
305
306 // Get the size of the read buffer for this device. We will need to
307 // allocate the buffer of this size for packet reads.
308 unsigned int buf_len = 0;
309 if (ioctl(sock, BIOCGBLEN, &buf_len) < 0) {
310 close(fallback);
311 close(sock);
312 isc_throw(SocketConfigError, "Unable to obtain the required"
313 " buffer length for reads from BPF device");
314 }
315
316 if (buf_len < sizeof(bpf_hdr)) {
317 isc_throw(SocketConfigError, "read buffer length returned by the"
318 " kernel for the BPF device associated with the interface"
319 << iface.getName() << " is lower than the BPF header"
320 " length: this condition is impossible unless the"
321 " operating system is really broken!");
322 }
323
324 // Set the filter program so as we only get packets we are interested in.
325 struct bpf_program prog;
326 memset(&prog, 0, sizeof(bpf_program));
327 if (iface.flag_loopback_) {
328 prog.bf_insns = loopback_ip_udp_filter;
329 prog.bf_len = sizeof(loopback_ip_udp_filter) / sizeof(struct bpf_insn);
330 // The address family is AF_INET. It can't be hardcoded in the BPF program
331 // because we need to make the host to network order conversion using htonl
332 // and conversion can't be done within the BPF program structure as it
333 // doesn't work on some systems.
334 prog.bf_insns[1].k = htonl(AF_INET);
335
336 } else {
337 prog.bf_insns = ethernet_ip_udp_filter;
338 prog.bf_len = sizeof(ethernet_ip_udp_filter) / sizeof(struct bpf_insn);
339 }
340
341 // Configure the BPF program to receive unicast packets sent to the
342 // specified address. The program will also allow packets sent to the
343 // 255.255.255.255 broadcast address.
344 prog.bf_insns[8].k = addr.toUint32();
345
346 // Configure the BPF program to receive packets on the specified port.
347 prog.bf_insns[11].k = port;
348
349 // Actually set the filter program for the device.
350 if (ioctl(sock, BIOCSETF, &prog) < 0) {
351 close(fallback);
352 close(sock);
353 isc_throw(SocketConfigError, "Failed to install BPF filter"
354 " program");
355 }
356
357 // Configure the BPF device to use the immediate mode. This ensures
358 // that the read function returns immediately, instead of waiting
359 // for the kernel to fill up the buffer, which would likely cause
360 // read hangs.
361 int flag = 1;
362 if (ioctl(sock, BIOCIMMEDIATE, &flag) < 0) {
363 close(fallback);
364 close(sock);
365 isc_throw(SocketConfigError, "Failed to set promiscuous mode for"
366 " BPF device");
367 }
368
369 // Everything is ok, allocate the read buffer and return the socket
370 // (BPF device descriptor) to the caller.
371 try {
372 iface.resizeReadBuffer(buf_len);
373
374 } catch (...) {
375 close(fallback);
376 close(sock);
377 throw;
378 }
379
380 return (SocketInfo(addr, port, sock, fallback));
381}
382
384PktFilterBPF::receive(Iface& iface, const SocketInfo& socket_info) {
385 // When using BPF, the read buffer must be allocated for the interface.
386 // If it is not allocated, it is a programmatic error.
387 if (iface.getReadBufferSize() == 0) {
388 isc_throw(SocketConfigError, "socket read buffer empty"
389 " for the interface: " << iface.getName());
390 }
391
392 // First let's get some data from the fallback socket. The data will be
393 // discarded but we don't want the socket buffer to bloat. We get the
394 // packets from the socket in loop but most of the time the loop will
395 // end after receiving one packet. The call to recv returns immediately
396 // when there is no data left on the socket because the socket is
397 // non-blocking.
398 // @todo In the normal conditions, both the primary socket and the fallback
399 // socket are in sync as they are set to receive packets on the same
400 // address and port. The reception of packets on the fallback socket
401 // shouldn't cause significant lags in packet reception. If we find in the
402 // future that it does, the sort of threshold could be set for the maximum
403 // bytes received on the fallback socket in a single round. Further
404 // optimizations would include an asynchronous read from the fallback socket
405 // when the DHCP server is idle.
406 int datalen;
407 do {
408 datalen = recv(socket_info.fallbackfd_, iface.getReadBuffer(),
409 iface.getReadBufferSize(), 0);
410 } while (datalen > 0);
411
412 datalen = read(socket_info.sockfd_, iface.getReadBuffer(),
413 iface.getReadBufferSize());
414 // If negative value is returned by read(), it indicates that an
415 // error occurred. If returned value is 0, no data was read from the
416 // socket. In both cases something has gone wrong, because we expect
417 // that a chunk of data is there. We signal the lack of data by
418 // returning an empty packet.
419 if (datalen <= 0) {
420 return Pkt4Ptr();
421 }
422 datalen = BPF_WORDALIGN(datalen);
423
424 // Holds BPF header.
425 struct bpf_hdr bpfh;
426
433 int offset = 0;
434 while (offset < datalen) {
435 // Check if the BPF header fits in the reminder of the buffer.
436 // If it doesn't something is really wrong.
437 if (datalen - offset < sizeof(bpf_hdr)) {
438 isc_throw(SocketReadError, "packet received over the BPF device on"
439 " interface " << iface.getName() << " has a truncated "
440 " BPF header");
441 }
442
443 // Copy the BPF header.
444 memcpy(static_cast<void*>(&bpfh),
445 static_cast<void*>(iface.getReadBuffer()),
446 sizeof(bpfh));
447
448 // Check if the captured data fit into the reminder of the buffer.
449 // Again, something is really wrong here if it doesn't fit.
450 if (offset + bpfh.bh_hdrlen + bpfh.bh_caplen > datalen) {
451 isc_throw(SocketReadError, "packet received from the BPF device"
452 << " attached to interface " << iface.getName()
453 << " is truncated");
454 }
455
456 // Check if the whole packet has been captured.
457 if (bpfh.bh_caplen != bpfh.bh_datalen) {
458 // Not whole packet captured, proceed to next received packet.
459 offset = BPF_WORDALIGN(offset + bpfh.bh_hdrlen + bpfh.bh_caplen);
460 continue;
461 }
462
463 // All checks passed, let's use the packet at the offset found.
464 // Typically it will be at offset 0.
465 break;
466 };
467
468 // No parsable packet found, so return.
469 if (offset >= datalen) {
470 return (Pkt4Ptr());
471 }
472
473 // Skip the BPF header and create the buffer holding a frame.
474 InputBuffer buf(iface.getReadBuffer() + offset + bpfh.bh_hdrlen,
475 datalen - bpfh.bh_hdrlen - offset);
476
477
478 // @todo: This is awkward way to solve the chicken and egg problem
479 // whereby we don't know the offset where DHCP data start in the
480 // received buffer when we create the packet object. In general case,
481 // the IP header has variable length. The information about its length
482 // is stored in one of its fields. Therefore, we have to decode the
483 // packet to get the offset of the DHCP data. The dummy object is
484 // created so as we can pass it to the functions which decode IP stack
485 // and find actual offset of the DHCP data.
486 // Once we find the offset we can create another Pkt4 object from
487 // the reminder of the input buffer and set the IP addresses and
488 // ports from the dummy packet. We should consider doing it
489 // in some more elegant way.
490 Pkt4Ptr dummy_pkt = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 0));
491
492 // On local loopback interface the ethernet header is not present.
493 // Instead, there is a 4-byte long pseudo header containing the
494 // address family in the host byte order. Note that this header
495 // is present in the received messages on OSX, but should not be
496 // included in the sent messages on OSX.
497 if (iface.flag_loopback_) {
498 if (buf.getLength() < BPF_LOCAL_LOOPBACK_HEADER_LEN) {
499 isc_throw(SocketReadError, "packet received on local loopback"
500 " interface " << iface.getName() << " doesn't contain"
501 " the pseudo header with the address family type");
502 }
503 // Advance to the position of the IP header. We don't check the
504 // contents of the pseudo header because the BPF filter should have
505 // filtered out the packets with address family other than AF_INET.
506 buf.setPosition(BPF_LOCAL_LOOPBACK_HEADER_LEN);
507
508 // Since we don't decode the real link-layer header we need to
509 // supply the hardware address ourselves.
510 dummy_pkt->setLocalHWAddr(HWAddrPtr(new HWAddr()));
511 dummy_pkt->setRemoteHWAddr(HWAddrPtr(new HWAddr()));
512
513 } else {
514 // If we are on the interface other than local loopback, assume
515 // the ethernet header. For now we don't support any other data
516 // link layer.
517 decodeEthernetHeader(buf, dummy_pkt);
518 }
519
520 // Decode IP/UDP headers.
521 decodeIpUdpHeader(buf, dummy_pkt);
522
523 // Read the DHCP data.
524 std::vector<uint8_t> dhcp_buf;
525 buf.readVector(dhcp_buf, buf.getLength() - buf.getPosition());
526
527 // Decode DHCP data into the Pkt4 object.
528 Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(&dhcp_buf[0], dhcp_buf.size()));
529
530 // Set the appropriate packet members using data collected from
531 // the decoded headers.
532 pkt->setIndex(iface.getIndex());
533 pkt->setIface(iface.getName());
534 pkt->setLocalAddr(dummy_pkt->getLocalAddr());
535 pkt->setRemoteAddr(dummy_pkt->getRemoteAddr());
536 pkt->setLocalPort(dummy_pkt->getLocalPort());
537 pkt->setRemotePort(dummy_pkt->getRemotePort());
538 pkt->setLocalHWAddr(dummy_pkt->getLocalHWAddr());
539 pkt->setRemoteHWAddr(dummy_pkt->getRemoteHWAddr());
540
541 // Set time the packet was stored in the buffer.
542#if (defined(BPF_TIMEVAL)) && (BPF_TIMEVAL == timeval32)
543 // Convert to ptime directly to avoid timeval vs
544 // timeval32 definitons under MacOS.
545 time_t time_t_secs = bpfh.bh_tstamp.tv_sec;
546 ptime timestamp = from_time_t(time_t_secs);
547 time_duration usecs(0, 0, 0, bpfh.bh_tstamp.tv_usec);
548 timestamp += usecs;
549 pkt->addPktEvent(PktEvent::SOCKET_RECEIVED, timestamp);
550#else
551 pkt->addPktEvent(PktEvent::SOCKET_RECEIVED, bpfh.bh_tstamp);
552#endif
553
554 // Set time packet was read from the buffer.
555 pkt->addPktEvent(PktEvent::BUFFER_READ);
556
557 return (pkt);
558}
559
560int
561PktFilterBPF::send(const Iface& iface, uint16_t sockfd, const Pkt4Ptr& pkt) {
562
563 OutputBuffer buf(14);
564
565 // Some interfaces may have no HW address - e.g. loopback interface.
566 // For these interfaces the HW address length is 0. If this is the case,
567 // then we will rely on the functions which construct the IP/UDP headers
568 // to provide a default HW address. Otherwise, create the HW address
569 // object using the HW address of the interface.
570 if (iface.getMacLen() > 0) {
571 HWAddrPtr hwaddr(new HWAddr(iface.getMac(), iface.getMacLen(),
572 iface.getHWType()));
573 pkt->setLocalHWAddr(hwaddr);
574 }
575
576 // Loopback interface requires special treatment. It doesn't
577 // use the ethernet header but rather a 4-byte long pseudo header
578 // holding an address family type (see bpf.c in OS sources).
579 // On OSX, it even lacks pseudo header.
580#if !defined (OS_OSX)
581 if (iface.flag_loopback_) {
582 writeAFPseudoHeader(AF_INET, buf);
583 }
584#endif
585
586 // If this is not a loopback interface create Ethernet frame header.
587 if (!iface.flag_loopback_) {
588 // Ethernet frame header.
589 // Note that we don't validate whether HW addresses in 'pkt'
590 // are valid because they are validated by the function called.
591 writeEthernetHeader(pkt, buf);
592 }
593
594 // IP and UDP header
595 writeIpUdpHeader(pkt, buf);
596
597 // DHCPv4 message
598 buf.writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
599
600 int result = write(sockfd, buf.getData(), buf.getLength());
601 if (result < 0) {
602 isc_throw(SocketWriteError, "failed to send DHCPv4 packet: "
603 << strerror(errno));
604 }
605
606 pkt->addPktEvent(PktEvent::RESPONSE_SENT);
607 return (0);
608}
609
610void
611PktFilterBPF::writeAFPseudoHeader(const uint32_t address_family,
612 util::OutputBuffer& out_buf) {
613 // Copy address family to the temporary buffer and preserve the
614 // bytes order.
615 uint8_t af_buf[4];
616 memcpy(static_cast<void*>(af_buf),
617 static_cast<const void*>(&address_family),
618 sizeof(af_buf));
619 // Write the data into the buffer.
620 out_buf.writeData(af_buf, sizeof(af_buf));
621}
622
623} // end of isc::dhcp namespace
624} // end of isc namespace
Represents a single network interface.
Definition: iface_mgr.h:118
size_t getReadBufferSize() const
Returns the current size of the socket read buffer.
Definition: iface_mgr.h:387
size_t getMacLen() const
Returns MAC length.
Definition: iface_mgr.h:199
uint8_t * getReadBuffer()
Returns the pointer to the buffer used for data reading.
Definition: iface_mgr.h:379
std::string getName() const
Returns interface name.
Definition: iface_mgr.h:224
uint16_t getHWType() const
Returns hardware type of the interface.
Definition: iface_mgr.h:234
unsigned int getIndex() const
Returns interface index.
Definition: iface_mgr.h:219
void resizeReadBuffer(const size_t new_size)
Reallocates the socket read buffer.
Definition: iface_mgr.h:394
bool flag_loopback_
Specifies if selected interface is loopback.
Definition: iface_mgr.h:441
const uint8_t * getMac() const
Returns pointer to MAC address.
Definition: iface_mgr.h:205
Represents DHCPv4 packet.
Definition: pkt4.h:37
static const std::string BUFFER_READ
Event that marks when a packet is read from the socket buffer by application.
Definition: pkt.h:97
static const std::string SOCKET_RECEIVED
Event that marks when a packet is placed in the socket buffer by the kernel.
Definition: pkt.h:93
static const std::string RESPONSE_SENT
Event that marks when a packet is been written to the socket by application.
Definition: pkt.h:101
virtual Pkt4Ptr receive(Iface &iface, const SocketInfo &socket_info)
Receive 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 int send(const Iface &iface, uint16_t sockfd, const Pkt4Ptr &pkt)
Send packet over specified socket.
virtual int openFallbackSocket(const isc::asiolink::IOAddress &addr, const uint16_t port)
Default implementation to open a fallback socket.
Definition: pkt_filter.cc:18
IfaceMgr exception thrown thrown when socket opening or configuration failed.
Definition: iface_mgr.h:63
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
Definition: iface_mgr.h:71
IfaceMgr exception thrown thrown when error occurred during sending data through socket.
Definition: iface_mgr.h:79
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
void readVector(std::vector< uint8_t > &data, size_t len)
Read specified number of bytes as a vector.
Definition: buffer.h:259
void setPosition(size_t position)
Set the read position of the buffer to the given value.
Definition: buffer.h:112
size_t getPosition() const
Return the current read position.
Definition: buffer.h:101
size_t getLength() const
Return the length of the data stored in the buffer.
Definition: buffer.h:96
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:343
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:556
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:395
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:409
#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.
Definition: pkt4.h:555
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.
Definition: hwaddr.h:154
@ DHCPDISCOVER
Definition: dhcp4.h:236
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.
Definition: hwaddr.h:20
Holds information about socket.
Definition: socket_info.h:19
int sockfd_
IPv4 or IPv6.
Definition: socket_info.h:26
int fallbackfd_
Fallback socket descriptor.
Definition: socket_info.h:50