Kea  2.1.7-git
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>
13 #include <exceptions/exceptions.h>
14 #include <algorithm>
15 #include <net/bpf.h>
16 #include <netinet/if_ether.h>
17 
18 namespace {
19 
20 using namespace isc::dhcp;
21 
23 const unsigned int MAX_BPF_OPEN_ATTEMPTS = 100;
24 
27 const unsigned int BPF_LOCAL_LOOPBACK_HEADER_LEN = 4;
28 
51 struct 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 
137 struct 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 
219 using namespace isc::util;
220 
221 namespace isc {
222 namespace 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 
382 Pkt4Ptr
383 PktFilterBPF::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 
543 int
544 PktFilterBPF::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 
592 void
593 PktFilterBPF::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
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.
void writeEthernetHeader(const Pkt4Ptr &pkt, OutputBuffer &out_buf)
Writes ethernet frame header into a buffer.
IfaceMgr exception thrown thrown when socket opening or configuration failed.
Definition: iface_mgr.h:63
virtual Pkt4Ptr receive(Iface &iface, const SocketInfo &socket_info)
Receive packet over specified socket.
int fallbackfd_
Fallback socket descriptor.
Definition: socket_info.h:50
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
virtual int send(const Iface &iface, uint16_t sockfd, const Pkt4Ptr &pkt)
Send packet over specified socket.
bool flag_loopback_
Specifies if selected interface is loopback.
Definition: iface_mgr.h:425
int getIndex() const
Returns interface index.
Definition: iface_mgr.h:216
size_t getMacLen() const
Returns MAC length.
Definition: iface_mgr.h:196
Represents a single network interface.
Definition: iface_mgr.h:118
const uint8_t * getMac() const
Returns pointer to MAC address.
Definition: iface_mgr.h:202
int sockfd_
IPv4 or IPv6.
Definition: socket_info.h:26
void decodeEthernetHeader(InputBuffer &buf, Pkt4Ptr &pkt)
Decode the Ethernet header.
size_t getReadBufferSize() const
Returns the current size of the socket read buffer.
Definition: iface_mgr.h:384
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: edns.h:19
uint16_t getHWType() const
Returns hardware type of the interface.
Definition: iface_mgr.h:231
void writeIpUdpHeader(const Pkt4Ptr &pkt, util::OutputBuffer &out_buf)
Writes both IP and UDP header into output buffer.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:544
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:401
std::string getName() const
Returns interface name.
Definition: iface_mgr.h:221
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
Definition: iface_mgr.h:71
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
Defines the logger used by the top-level component of kea-lfc.
Represents DHCPv4 packet.
Definition: pkt4.h:37
void resizeReadBuffer(const size_t new_size)
Reallocates the socket read buffer.
Definition: iface_mgr.h:391
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
uint8_t * getReadBuffer()
Returns the pointer to the buffer used for data reading.
Definition: iface_mgr.h:376
IfaceMgr exception thrown thrown when error occurred during sending data through socket.
Definition: iface_mgr.h:79
Holds information about socket.
Definition: socket_info.h:19
void decodeIpUdpHeader(InputBuffer &buf, Pkt4Ptr &pkt)
Decode IP and UDP header.