Kea 2.6.2
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
when the call the UDPServer carries on at the same position As a result
Definition asiodns.dox:16
then both cases could be regarded as being with the completion being signalled by the posting of the completion event However UDP is the most common case and that would involve extra overhead So the open() returns a status indicating whether the operation completed asynchronously. If it did
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:262
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:346
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition buffer.h:559
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition buffer.h:398
size_t getLength() const
Return the length of data written in the buffer.
Definition buffer.h:412
#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:235
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