1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2008 Roy Marples <roy (at) marples.name> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/ioctl.h> 29 #include <sys/socket.h> 30 #include <sys/uio.h> 31 32 #include <net/bpf.h> 33 #include <net/if.h> 34 #include <arpa/inet.h> 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <paths.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <syslog.h> 43 #include <unistd.h> 44 45 #include "config.h" 46 #include "common.h" 47 #include "dhcp.h" 48 #include "net.h" 49 #include "bpf-filter.h" 50 51 int 52 open_socket(struct interface *iface, int protocol) 53 { 54 int fd = -1; 55 int *fdp = NULL; 56 struct ifreq ifr; 57 int buf_len = 0; 58 struct bpf_version pv; 59 struct bpf_program pf; 60 #ifdef BIOCIMMEDIATE 61 int flags; 62 #endif 63 #ifdef _PATH_BPF 64 fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK); 65 #else 66 char *device; 67 int n = 0; 68 69 device = xmalloc(sizeof(char) * PATH_MAX); 70 do { 71 snprintf(device, PATH_MAX, "/dev/bpf%d", n++); 72 fd = open(device, O_RDWR | O_NONBLOCK); 73 } while (fd == -1 && errno == EBUSY); 74 free(device); 75 #endif 76 77 if (fd == -1) 78 return -1; 79 80 if (ioctl(fd, BIOCVERSION, &pv) == -1) 81 goto eexit; 82 if (pv.bv_major != BPF_MAJOR_VERSION || 83 pv.bv_minor < BPF_MINOR_VERSION) { 84 syslog(LOG_ERR, "BPF version mismatch - recompile"); 85 goto eexit; 86 } 87 88 memset(&ifr, 0, sizeof(ifr)); 89 strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); 90 if (ioctl(fd, BIOCSETIF, &ifr) == -1) 91 goto eexit; 92 93 /* Get the required BPF buffer length from the kernel. */ 94 if (ioctl(fd, BIOCGBLEN, &buf_len) == -1) 95 goto eexit; 96 if (iface->buffer_size != (size_t)buf_len) { 97 free(iface->buffer); 98 iface->buffer_size = buf_len; 99 iface->buffer = xmalloc(buf_len); 100 iface->buffer_len = iface->buffer_pos = 0; 101 } 102 103 #ifdef BIOCIMMEDIATE 104 flags = 1; 105 if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1) 106 goto eexit; 107 #endif 108 109 /* Install the DHCP filter */ 110 if (protocol == ETHERTYPE_ARP) { 111 pf.bf_insns = UNCONST(arp_bpf_filter); 112 pf.bf_len = arp_bpf_filter_len; 113 fdp = &iface->arp_fd; 114 } else { 115 pf.bf_insns = UNCONST(dhcp_bpf_filter); 116 pf.bf_len = dhcp_bpf_filter_len; 117 fdp = &iface->raw_fd; 118 } 119 if (ioctl(fd, BIOCSETF, &pf) == -1) 120 goto eexit; 121 if (set_cloexec(fd) == -1) 122 goto eexit; 123 if (fdp) { 124 if (*fdp != -1) 125 close(*fdp); 126 *fdp = fd; 127 } 128 return fd; 129 130 eexit: 131 free(iface->buffer); 132 iface->buffer = NULL; 133 close(fd); 134 return -1; 135 } 136 137 ssize_t 138 send_raw_packet(const struct interface *iface, int protocol, 139 const void *data, ssize_t len) 140 { 141 struct iovec iov[2]; 142 struct ether_header hw; 143 int fd; 144 145 memset(&hw, 0, ETHER_HDR_LEN); 146 memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); 147 hw.ether_type = htons(protocol); 148 iov[0].iov_base = &hw; 149 iov[0].iov_len = ETHER_HDR_LEN; 150 iov[1].iov_base = UNCONST(data); 151 iov[1].iov_len = len; 152 if (protocol == ETHERTYPE_ARP) 153 fd = iface->arp_fd; 154 else 155 fd = iface->raw_fd; 156 return writev(fd, iov, 2); 157 } 158 159 /* BPF requires that we read the entire buffer. 160 * So we pass the buffer in the API so we can loop on >1 packet. */ 161 ssize_t 162 get_raw_packet(struct interface *iface, int protocol, 163 void *data, ssize_t len) 164 { 165 int fd = -1; 166 struct bpf_hdr packet; 167 ssize_t bytes; 168 const unsigned char *payload; 169 170 if (protocol == ETHERTYPE_ARP) 171 fd = iface->arp_fd; 172 else 173 fd = iface->raw_fd; 174 175 for (;;) { 176 if (iface->buffer_len == 0) { 177 bytes = read(fd, iface->buffer, iface->buffer_size); 178 if (bytes == -1) 179 return errno == EAGAIN ? 0 : -1; 180 else if ((size_t)bytes < sizeof(packet)) 181 return -1; 182 iface->buffer_len = bytes; 183 iface->buffer_pos = 0; 184 } 185 bytes = -1; 186 memcpy(&packet, iface->buffer + iface->buffer_pos, 187 sizeof(packet)); 188 if (packet.bh_caplen != packet.bh_datalen) 189 goto next; /* Incomplete packet, drop. */ 190 if (iface->buffer_pos + packet.bh_caplen + packet.bh_hdrlen > 191 iface->buffer_len) 192 goto next; /* Packet beyond buffer, drop. */ 193 payload = iface->buffer + packet.bh_hdrlen + ETHER_HDR_LEN; 194 bytes = packet.bh_caplen - ETHER_HDR_LEN; 195 if (bytes > len) 196 bytes = len; 197 memcpy(data, payload, bytes); 198 next: 199 iface->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen + 200 packet.bh_caplen); 201 if (iface->buffer_pos >= iface->buffer_len) 202 iface->buffer_len = iface->buffer_pos = 0; 203 if (bytes != -1) 204 return bytes; 205 } 206 } 207