Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2011 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 
     31 #include <net/if.h>
     32 #include <netinet/in_systm.h>
     33 #include <netinet/in.h>
     34 #include <arpa/inet.h>
     35 
     36 #ifdef __linux__
     37 # include <asm/types.h> /* needed for 2.4 kernels for the below header */
     38 # include <linux/filter.h>
     39 # include <linux/if_packet.h>
     40 # define bpf_insn		sock_filter
     41 # define BPF_SKIPTYPE
     42 # define BPF_ETHCOOK		-ETH_HLEN
     43 # define BPF_WHOLEPACKET	0x0fffffff /* work around buggy LPF filters */
     44 #endif
     45 
     46 #include <errno.h>
     47 #include <fcntl.h>
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <time.h>
     52 #include <unistd.h>
     53 
     54 #include "config.h"
     55 #include "common.h"
     56 #include "dhcp.h"
     57 #include "net.h"
     58 #include "bpf-filter.h"
     59 
     60 /* Broadcast address for IPoIB */
     61 static const uint8_t ipv4_bcast_addr[] = {
     62 	0x00, 0xff, 0xff, 0xff,
     63 	0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
     64 	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
     65 };
     66 
     67 int
     68 open_socket(struct interface *iface, int protocol)
     69 {
     70 	int s;
     71 	union sockunion {
     72 		struct sockaddr sa;
     73 		struct sockaddr_in sin;
     74 		struct sockaddr_ll sll;
     75 		struct sockaddr_storage ss;
     76 	} su;
     77 	struct sock_fprog pf;
     78 	int *fd;
     79 #ifdef PACKET_AUXDATA
     80 	int n;
     81 #endif
     82 
     83 	if ((s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol))) == -1)
     84 		return -1;
     85 
     86 	memset(&su, 0, sizeof(su));
     87 	su.sll.sll_family = PF_PACKET;
     88 	su.sll.sll_protocol = htons(protocol);
     89 	if (!(su.sll.sll_ifindex = if_nametoindex(iface->name))) {
     90 		errno = ENOENT;
     91 		goto eexit;
     92 	}
     93 	/* Install the DHCP filter */
     94 	memset(&pf, 0, sizeof(pf));
     95 	if (protocol == ETHERTYPE_ARP) {
     96 		pf.filter = UNCONST(arp_bpf_filter);
     97 		pf.len = arp_bpf_filter_len;
     98 	} else {
     99 		pf.filter = UNCONST(dhcp_bpf_filter);
    100 		pf.len = dhcp_bpf_filter_len;
    101 	}
    102 	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) != 0)
    103 		goto eexit;
    104 #ifdef PACKET_AUXDATA
    105 	n = 1;
    106 	if (setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &n, sizeof(n)) != 0) {
    107 		if (errno != ENOPROTOOPT)
    108 			goto eexit;
    109 	}
    110 #endif
    111 	if (set_cloexec(s) == -1)
    112 		goto eexit;
    113 	if (set_nonblock(s) == -1)
    114 		goto eexit;
    115 	if (bind(s, &su.sa, sizeof(su)) == -1)
    116 		goto eexit;
    117 	if (protocol == ETHERTYPE_ARP)
    118 		fd = &iface->arp_fd;
    119 	else
    120 		fd = &iface->raw_fd;
    121 	if (*fd != -1)
    122 		close(*fd);
    123 	*fd = s;
    124 	return s;
    125 
    126 eexit:
    127 	close(s);
    128 	return -1;
    129 }
    130 
    131 ssize_t
    132 send_raw_packet(const struct interface *iface, int protocol,
    133     const void *data, ssize_t len)
    134 {
    135 	union sockunion {
    136 		struct sockaddr sa;
    137 		struct sockaddr_ll sll;
    138 		struct sockaddr_storage ss;
    139 	} su;
    140 	int fd;
    141 
    142 	memset(&su, 0, sizeof(su));
    143 	su.sll.sll_family = AF_PACKET;
    144 	su.sll.sll_protocol = htons(protocol);
    145 	if (!(su.sll.sll_ifindex = if_nametoindex(iface->name))) {
    146 		errno = ENOENT;
    147 		return -1;
    148 	}
    149 	su.sll.sll_hatype = htons(iface->family);
    150 	su.sll.sll_halen = iface->hwlen;
    151 	if (iface->family == ARPHRD_INFINIBAND)
    152 		memcpy(&su.sll.sll_addr,
    153 		    &ipv4_bcast_addr, sizeof(ipv4_bcast_addr));
    154 	else
    155 		memset(&su.sll.sll_addr, 0xff, iface->hwlen);
    156 	if (protocol == ETHERTYPE_ARP)
    157 		fd = iface->arp_fd;
    158 	else
    159 		fd = iface->raw_fd;
    160 
    161 	return sendto(fd, data, len, 0, &su.sa, sizeof(su));
    162 }
    163 
    164 ssize_t
    165 get_raw_packet(struct interface *iface, int protocol,
    166     void *data, ssize_t len, int *partialcsum)
    167 {
    168 	struct iovec iov = {
    169 		.iov_base = data,
    170 		.iov_len = len,
    171 	};
    172 	struct msghdr msg = {
    173 		.msg_iov = &iov,
    174 		.msg_iovlen = 1,
    175 	};
    176 #ifdef PACKET_AUXDATA
    177 	unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
    178 	struct cmsghdr *cmsg;
    179 	struct tpacket_auxdata *aux;
    180 #endif
    181 
    182 	ssize_t bytes;
    183 	int fd = -1;
    184 
    185 #ifdef PACKET_AUXDATA
    186 	msg.msg_control = cmsgbuf;
    187 	msg.msg_controllen = sizeof(cmsgbuf);
    188 #endif
    189 
    190 	if (protocol == ETHERTYPE_ARP)
    191 		fd = iface->arp_fd;
    192 	else
    193 		fd = iface->raw_fd;
    194 	bytes = recvmsg(fd, &msg, 0);
    195 	if (bytes == -1)
    196 		return errno == EAGAIN ? 0 : -1;
    197 	if (partialcsum != NULL) {
    198 		*partialcsum = 0;
    199 #ifdef PACKET_AUXDATA
    200 		for (cmsg = CMSG_FIRSTHDR(&msg);
    201 		     cmsg;
    202 		     cmsg = CMSG_NXTHDR(&msg, cmsg))
    203 		{
    204 			if (cmsg->cmsg_level == SOL_PACKET &&
    205 			    cmsg->cmsg_type == PACKET_AUXDATA) {
    206 				aux = (void *)CMSG_DATA(cmsg);
    207 				*partialcsum = aux->tp_status &
    208 				    TP_STATUS_CSUMNOTREADY;
    209 			}
    210 		}
    211 #endif
    212 	}
    213 	return bytes;
    214 }
    215