Kea 2.5.5
pkt_filter_bpf.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2017 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;
21
23const unsigned int MAX_BPF_OPEN_ATTEMPTS = 100;
24
27const unsigned int BPF_LOCAL_LOOPBACK_HEADER_LEN = 4;
28
51struct bpf_insn ethernet_ip_udp_filter [] = {
52 // Make sure this is an IP packet: check the half-word (two bytes)
53 // at offset 12 in the packet (the Ethernet packet type). If it
54 // is, advance to the next instruction. If not, advance 11
55 // instructions (which takes execution to the last instruction in
56 // the sequence: "drop it").
57 // #0
58 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_PACKET_TYPE_OFFSET),
59 // #1
60 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 11),
61
62 // Make sure it's a UDP packet. The IP protocol is at offset
63 // 9 in the IP header so, adding the Ethernet packet header size
64 // of 14 bytes gives an absolute byte offset in the packet of 23.
65 // #2
66 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
67 ETHERNET_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
68 // #3
69 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
70
71 // Make sure this isn't a fragment by checking that the fragment
72 // offset field in the IP header is zero. This field is the
73 // least-significant 13 bits in the bytes at offsets 6 and 7 in
74 // the IP header, so the half-word at offset 20 (6 + size of
75 // Ethernet header) is loaded and an appropriate mask applied.
76 // #4
77 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_HEADER_LEN + IP_FLAGS_OFFSET),
78 // #5
79 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
80
81 // Check the packet's destination address. The program will only
82 // allow the packets sent to the broadcast address or unicast
83 // to the specific address on the interface. By default, this
84 // address is set to 0 and must be set to the specific value
85 // when the raw socket is created and the program is attached
86 // to it. The caller must assign the address to the
87 // prog.bf_insns[8].k in the network byte order.
88 // #6
89 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
90 ETHERNET_HEADER_LEN + IP_DEST_ADDR_OFFSET),
91 // If this is a broadcast address, skip the next check.
92 // #7
93 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
94 // If this is not broadcast address, compare it with the unicast
95 // address specified for the interface.
96 // #8
97 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
98
99 // Get the IP header length. This is achieved by the following
100 // (special) instruction that, given the offset of the start
101 // of the IP header (offset 14) loads the IP header length.
102 // #9
103 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, ETHERNET_HEADER_LEN),
104
105 // Make sure it's to the right port. The following instruction
106 // adds the previously extracted IP header length to the given
107 // offset to locate the correct byte. The given offset of 16
108 // comprises the length of the Ethernet header (14) plus the offset
109 // of the UDP destination port (2) within the UDP header.
110 // #10
111 BPF_STMT(BPF_LD + BPF_H + BPF_IND, ETHERNET_HEADER_LEN + UDP_DEST_PORT),
112 // The following instruction tests against the default DHCP server port,
113 // but the action port is actually set in PktFilterBPF::openSocket().
114 // N.B. The code in that method assumes that this instruction is at
115 // offset 11 in the program. If this is changed, openSocket() must be
116 // updated.
117 // #11
118 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
119
120 // If we passed all the tests, ask for the whole packet.
121 // #12
122 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
123
124 // Otherwise, drop it.
125 // #13
126 BPF_STMT(BPF_RET + BPF_K, 0),
127};
128
137struct bpf_insn loopback_ip_udp_filter [] = {
138 // Make sure this is an IP packet. The pseudo header comprises a 4-byte
139 // long value identifying the address family, which should be set to
140 // AF_INET. The default value used here (0xFFFFFFFF) must be overridden
141 // with htonl(AF_INET) from within the openSocket function.
142 // #0
143 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 0),
144 // #1
145 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xFFFFFFFF, 0, 11),
146
147 // Make sure it's a UDP packet. The IP protocol is at offset
148 // 9 in the IP header so, adding the pseudo header size 4 bytes
149 // gives an absolute byte offset in the packet of 13.
150 // #2
151 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
152 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
153 // #3
154 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
155
156 // Make sure this isn't a fragment by checking that the fragment
157 // offset field in the IP header is zero. This field is the
158 // least-significant 13 bits in the bytes at offsets 6 and 7 in
159 // the IP header, so the half-word at offset 10 (6 + size of
160 // pseudo header) is loaded and an appropriate mask applied.
161 // #4
162 BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
163 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_FLAGS_OFFSET),
164 // #5
165 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
166
167 // Check the packet's destination address. The program will only
168 // allow the packets sent to the broadcast address or unicast
169 // to the specific address on the interface. By default, this
170 // address is set to 0 and must be set to the specific value
171 // when the raw socket is created and the program is attached
172 // to it. The caller must assign the address to the
173 // prog.bf_insns[8].k in the network byte order.
174 // #6
175 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
176 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_DEST_ADDR_OFFSET),
177 // If this is a broadcast address, skip the next check.
178 // #7
179 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
180 // If this is not broadcast address, compare it with the unicast
181 // address specified for the interface.
182 // #8
183 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
184
185 // Get the IP header length. This is achieved by the following
186 // (special) instruction that, given the offset of the start
187 // of the IP header (offset 4) loads the IP header length.
188 // #9
189 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, BPF_LOCAL_LOOPBACK_HEADER_LEN),
190
191 // Make sure it's to the right port. The following instruction
192 // adds the previously extracted IP header length to the given
193 // offset to locate the correct byte. The given offset of 6
194 // comprises the length of the pseudo header (4) plus the offset
195 // of the UDP destination port (2) within the UDP header.
196 // #10
197 BPF_STMT(BPF_LD + BPF_H + BPF_IND,
198 BPF_LOCAL_LOOPBACK_HEADER_LEN + UDP_DEST_PORT),
199 // The following instruction tests against the default DHCP server port,
200 // but the action port is actually set in PktFilterBPF::openSocket().
201 // N.B. The code in that method assumes that this instruction is at
202 // offset 11 in the program. If this is changed, openSocket() must be
203 // updated.
204 // #11
205 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
206
207 // If we passed all the tests, ask for the whole packet.
208 // #12
209 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
210
211 // Otherwise, drop it.
212 // #13
213 BPF_STMT(BPF_RET + BPF_K, 0),
214};
215
216
217}
218
219using namespace isc::util;
220
221namespace isc {
222namespace dhcp {
223
226 const isc::asiolink::IOAddress& addr,
227 const uint16_t port, const bool,
228 const bool) {
229
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 return (SocketInfo(addr, port, sock, fallback));
380}
381
383PktFilterBPF::receive(Iface& iface, const SocketInfo& socket_info) {
384 // When using BPF, the read buffer must be allocated for the interface.
385 // If it is not allocated, it is a programmatic error.
386 if (iface.getReadBufferSize() == 0) {
387 isc_throw(SocketConfigError, "socket read buffer empty"
388 " for the interface: " << iface.getName());
389 }
390
391 // First let's get some data from the fallback socket. The data will be
392 // discarded but we don't want the socket buffer to bloat. We get the
393 // packets from the socket in loop but most of the time the loop will
394 // end after receiving one packet. The call to recv returns immediately
395 // when there is no data left on the socket because the socket is
396 // non-blocking.
397 // @todo In the normal conditions, both the primary socket and the fallback
398 // socket are in sync as they are set to receive packets on the same
399 // address and port. The reception of packets on the fallback socket
400 // shouldn't cause significant lags in packet reception. If we find in the
401 // future that it does, the sort of threshold could be set for the maximum
402 // bytes received on the fallback socket in a single round. Further
403 // optimizations would include an asynchronous read from the fallback socket
404 // when the DHCP server is idle.
405 int datalen;
406 do {
407 datalen = recv(socket_info.fallbackfd_, iface.getReadBuffer(),
408 iface.getReadBufferSize(), 0);
409 } while (datalen > 0);
410
411 datalen = read(socket_info.sockfd_, iface.getReadBuffer(),
412 iface.getReadBufferSize());
413 // If negative value is returned by read(), it indicates that an
414 // error occurred. If returned value is 0, no data was read from the
415 // socket. In both cases something has gone wrong, because we expect
416 // that a chunk of data is there. We signal the lack of data by
417 // returning an empty packet.
418 if (datalen <= 0) {
419 return Pkt4Ptr();
420 }
421 datalen = BPF_WORDALIGN(datalen);
422
423 // Holds BPF header.
424 struct bpf_hdr bpfh;
425
432 int offset = 0;
433 while (offset < datalen) {
434 // Check if the BPF header fits in the reminder of the buffer.
435 // If it doesn't something is really wrong.
436 if (datalen - offset < sizeof(bpf_hdr)) {
437 isc_throw(SocketReadError, "packet received over the BPF device on"
438 " interface " << iface.getName() << " has a truncated "
439 " BPF header");
440 }
441
442 // Copy the BPF header.
443 memcpy(static_cast<void*>(&bpfh),
444 static_cast<void*>(iface.getReadBuffer()),
445 sizeof(bpfh));
446
447 // Check if the captured data fit into the reminder of the buffer.
448 // Again, something is really wrong here if it doesn't fit.
449 if (offset + bpfh.bh_hdrlen + bpfh.bh_caplen > datalen) {
450 isc_throw(SocketReadError, "packet received from the BPF device"
451 << " attached to interface " << iface.getName()
452 << " is truncated");
453 }
454
455 // Check if the whole packet has been captured.
456 if (bpfh.bh_caplen != bpfh.bh_datalen) {
457 // Not whole packet captured, proceed to next received packet.
458 offset = BPF_WORDALIGN(offset + bpfh.bh_hdrlen + bpfh.bh_caplen);
459 continue;
460 }
461
462 // All checks passed, let's use the packet at the offset found.
463 // Typically it will be at offset 0.
464 break;
465 };
466
467 // No parsable packet found, so return.
468 if (offset >= datalen) {
469 return (Pkt4Ptr());
470 }
471
472 // Skip the BPF header and create the buffer holding a frame.
473 InputBuffer buf(iface.getReadBuffer() + offset + bpfh.bh_hdrlen,
474 datalen - bpfh.bh_hdrlen - offset);
475
476
477 // @todo: This is awkward way to solve the chicken and egg problem
478 // whereby we don't know the offset where DHCP data start in the
479 // received buffer when we create the packet object. In general case,
480 // the IP header has variable length. The information about its length
481 // is stored in one of its fields. Therefore, we have to decode the
482 // packet to get the offset of the DHCP data. The dummy object is
483 // created so as we can pass it to the functions which decode IP stack
484 // and find actual offset of the DHCP data.
485 // Once we find the offset we can create another Pkt4 object from
486 // the reminder of the input buffer and set the IP addresses and
487 // ports from the dummy packet. We should consider doing it
488 // in some more elegant way.
489 Pkt4Ptr dummy_pkt = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 0));
490
491 // On local loopback interface the ethernet header is not present.
492 // Instead, there is a 4-byte long pseudo header containing the
493 // address family in the host byte order. Note that this header
494 // is present in the received messages on OSX, but should not be
495 // included in the sent messages on OSX.
496 if (iface.flag_loopback_) {
497 if (buf.getLength() < BPF_LOCAL_LOOPBACK_HEADER_LEN) {
498 isc_throw(SocketReadError, "packet received on local loopback"
499 " interface " << iface.getName() << " doesn't contain"
500 " the pseudo header with the address family type");
501 }
502 // Advance to the position of the IP header. We don't check the
503 // contents of the pseudo header because the BPF filter should have
504 // filtered out the packets with address family other than AF_INET.
505 buf.setPosition(BPF_LOCAL_LOOPBACK_HEADER_LEN);
506
507 // Since we don't decode the real link-layer header we need to
508 // supply the hardware address ourselves.
509 dummy_pkt->setLocalHWAddr(HWAddrPtr(new HWAddr()));
510 dummy_pkt->setRemoteHWAddr(HWAddrPtr(new HWAddr()));
511
512 } else {
513 // If we are on the interface other than local loopback, assume
514 // the ethernet header. For now we don't support any other data
515 // link layer.
516 decodeEthernetHeader(buf, dummy_pkt);
517 }
518
519 // Decode IP/UDP headers.
520 decodeIpUdpHeader(buf, dummy_pkt);
521
522 // Read the DHCP data.
523 std::vector<uint8_t> dhcp_buf;
524 buf.readVector(dhcp_buf, buf.getLength() - buf.getPosition());
525
526 // Decode DHCP data into the Pkt4 object.
527 Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(&dhcp_buf[0], dhcp_buf.size()));
528
529 // Set the appropriate packet members using data collected from
530 // the decoded headers.
531 pkt->setIndex(iface.getIndex());
532 pkt->setIface(iface.getName());
533 pkt->setLocalAddr(dummy_pkt->getLocalAddr());
534 pkt->setRemoteAddr(dummy_pkt->getRemoteAddr());
535 pkt->setLocalPort(dummy_pkt->getLocalPort());
536 pkt->setRemotePort(dummy_pkt->getRemotePort());
537 pkt->setLocalHWAddr(dummy_pkt->getLocalHWAddr());
538 pkt->setRemoteHWAddr(dummy_pkt->getRemoteHWAddr());
539
540 return (pkt);
541}
542
543int
544PktFilterBPF::send(const Iface& iface, uint16_t sockfd, const Pkt4Ptr& pkt) {
545
546 OutputBuffer buf(14);
547
548 // Some interfaces may have no HW address - e.g. loopback interface.
549 // For these interfaces the HW address length is 0. If this is the case,
550 // then we will rely on the functions which construct the IP/UDP headers
551 // to provide a default HW address. Otherwise, create the HW address
552 // object using the HW address of the interface.
553 if (iface.getMacLen() > 0) {
554 HWAddrPtr hwaddr(new HWAddr(iface.getMac(), iface.getMacLen(),
555 iface.getHWType()));
556 pkt->setLocalHWAddr(hwaddr);
557 }
558
559 // Loopback interface requires special treatment. It doesn't
560 // use the ethernet header but rather a 4-byte long pseudo header
561 // holding an address family type (see bpf.c in OS sources).
562 // On OSX, it even lacks pseudo header.
563#if !defined (OS_OSX)
564 if (iface.flag_loopback_) {
565 writeAFPseudoHeader(AF_INET, buf);
566 }
567#endif
568
569 // If this is not a loopback interface create Ethernet frame header.
570 if (!iface.flag_loopback_) {
571 // Ethernet frame header.
572 // Note that we don't validate whether HW addresses in 'pkt'
573 // are valid because they are validated by the function called.
574 writeEthernetHeader(pkt, buf);
575 }
576
577 // IP and UDP header
578 writeIpUdpHeader(pkt, buf);
579
580 // DHCPv4 message
581 buf.writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
582
583 int result = write(sockfd, buf.getData(), buf.getLength());
584 if (result < 0) {
585 isc_throw(SocketWriteError, "failed to send DHCPv4 packet: "
586 << strerror(errno));
587 }
588
589 return (0);
590}
591
592void
593PktFilterBPF::writeAFPseudoHeader(const uint32_t address_family,
594 util::OutputBuffer& out_buf) {
595 // Copy address family to the temporary buffer and preserve the
596 // bytes order.
597 uint8_t af_buf[4];
598 memcpy(static_cast<void*>(af_buf),
599 static_cast<const void*>(&address_family),
600 sizeof(af_buf));
601 // Write the data into the buffer.
602 out_buf.writeData(af_buf, sizeof(af_buf));
603}
604
605} // end of isc::dhcp namespace
606} // 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
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:204
void setPosition(size_t position)
Set the read position of the buffer to the given value.
Definition: buffer.h:115
size_t getPosition() const
Return the current read position.
Definition: buffer.h:102
size_t getLength() const
Return the length of the data stored in the buffer.
Definition: buffer.h:100
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:401
#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.
Definition: edns.h:19
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