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 
22 /// @brief Maximum number of attempts to open BPF device.
23 const unsigned int MAX_BPF_OPEN_ATTEMPTS = 100;
24 
25 /// @brief Length of the header containing the address family for the packet
26 /// received on local loopback interface.
27 const unsigned int BPF_LOCAL_LOOPBACK_HEADER_LEN = 4;
28 
29 /// The following structure defines a Berkeley Packet Filter program to perform
30 /// packet filtering. The program operates on Ethernet packets.  To help with
31 /// interpretation of the program, for the types of Ethernet packets we are
32 /// interested in, the header layout is:
33 ///
34 ///   6 bytes  Destination Ethernet Address
35 ///   6 bytes  Source Ethernet Address
36 ///   2 bytes  Ethernet packet type
37 ///
38 ///  20 bytes  Fixed part of IP header
39 ///  variable  Variable part of IP header
40 ///
41 ///   2 bytes  UDP Source port
42 ///   2 bytes  UDP destination port
43 ///   4 bytes  Rest of UDP header
44 ///
45 /// Each instruction is preceded with the comment giving the instruction
46 /// number within a BPF program, in the following format: #123.
47 ///
48 /// @todo We may want to extend the filter to receive packets sent
49 /// to the particular IP address assigned to the interface or
50 /// broadcast address.
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 
129 /// The following structure defines a BPF program to perform packet filtering
130 /// on local loopback interface. The packets received on this interface do not
131 /// contain the regular link-layer header, but rather a 4-byte long pseudo
132 /// header containing the address family. The reminder of the packet contains
133 /// IP header, UDP header and a DHCP message.
134 ///
135 /// Each instruction is preceded with the comment giving the instruction
136 /// number within a BPF program, in the following format: #123.
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 
224 SocketInfo
openSocket(Iface & iface,const isc::asiolink::IOAddress & addr,const uint16_t port,const bool,const bool)225 PktFilterBPF::openSocket(Iface& iface,
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);
256             isc_throw(SocketConfigError,
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
receive(Iface & iface,const SocketInfo & socket_info)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 
426     /// @todo BPF may occasionally append more than one packet in a
427     /// single read. Our current libdhcp++ API is oriented towards receiving
428     /// one packet at the time so we just pick first usable packet here
429     /// and drop other packets. In the future the additional packets should
430     /// be queued and processed. For now, we just iterate over the packets
431     /// in the buffer and pick the first usable one.
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
send(const Iface & iface,uint16_t sockfd,const Pkt4Ptr & pkt)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
writeAFPseudoHeader(const uint32_t address_family,util::OutputBuffer & out_buf)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
607