~ubuntu-branches/ubuntu/wily/dhcpcd5/wily-proposed

« back to all changes in this revision

Viewing changes to bpf.c

  • Committer: Package Import Robot
  • Author(s): Daniel Echeverry
  • Date: 2015-06-03 10:43:23 UTC
  • mfrom: (7.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20150603104323-74htea00somdput9
Tags: 6.9.0-1
* QA Upload
* New upstream release. Closes: #786772, #758713, #782085, #788693
* debian/control
  + Use Replaces instead Conflicts field
  + Bump Standards-Version 3.9.6
    + Update to DEP5 copyright format 1.0
* debian/rules
  + Add DEB_HOST_GNU_TYPE and DEB_BUILD_GNU_TYPE
* debian/patches
  + Add fix_ftbfs_kfreebsd.diff patch
    + Fix ftbfs on kfreebsd Closes: #770464
  + Add fix_manpage.diff patch
    * Fix lintian warning
  + Remove CVE-2014-6060.patch patch
    + Merge with upstream
  + Remove kfreebsd.diff patch
    * Upstream removed platform-bsd.c file in new version
* debian/prerm
  + Replace bashim with set -e
* debian/postint
  + Replace bashim with set -e
* debian/postrm
  + Replace bashim with set -e

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * dhcpcd - DHCP client daemon
3
 
 * Copyright (c) 2006-2013 Roy Marples <roy@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 "ipv4.h"
49
 
#include "bpf-filter.h"
50
 
 
51
 
int
52
 
ipv4_opensocket(struct interface *ifp, int protocol)
53
 
{
54
 
        struct dhcp_state *state;
55
 
        int fd = -1;
56
 
        int *fdp = NULL;
57
 
        struct ifreq ifr;
58
 
        int buf_len = 0;
59
 
        struct bpf_version pv;
60
 
        struct bpf_program pf;
61
 
#ifdef BIOCIMMEDIATE
62
 
        int flags;
63
 
#endif
64
 
#ifdef _PATH_BPF
65
 
        fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK);
66
 
#else
67
 
        char *device;
68
 
        int n = 0;
69
 
 
70
 
        device = malloc(sizeof(char) * PATH_MAX);
71
 
        if (device == NULL)
72
 
                return -1;
73
 
        do {
74
 
                snprintf(device, PATH_MAX, "/dev/bpf%d", n++);
75
 
                fd = open(device, O_RDWR | O_NONBLOCK);
76
 
        } while (fd == -1 && errno == EBUSY);
77
 
        free(device);
78
 
#endif
79
 
 
80
 
        if (fd == -1)
81
 
                return -1;
82
 
 
83
 
        state = D_STATE(ifp);
84
 
 
85
 
        if (ioctl(fd, BIOCVERSION, &pv) == -1)
86
 
                goto eexit;
87
 
        if (pv.bv_major != BPF_MAJOR_VERSION ||
88
 
            pv.bv_minor < BPF_MINOR_VERSION) {
89
 
                syslog(LOG_ERR, "BPF version mismatch - recompile");
90
 
                goto eexit;
91
 
        }
92
 
 
93
 
        memset(&ifr, 0, sizeof(ifr));
94
 
        strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
95
 
        if (ioctl(fd, BIOCSETIF, &ifr) == -1)
96
 
                goto eexit;
97
 
 
98
 
        /* Get the required BPF buffer length from the kernel. */
99
 
        if (ioctl(fd, BIOCGBLEN, &buf_len) == -1)
100
 
                goto eexit;
101
 
        if (state->buffer_size != (size_t)buf_len) {
102
 
                free(state->buffer);
103
 
                state->buffer = malloc(buf_len);
104
 
                if (state->buffer == NULL)
105
 
                        goto eexit;
106
 
                state->buffer_size = buf_len;
107
 
                state->buffer_len = state->buffer_pos = 0;
108
 
        }
109
 
 
110
 
#ifdef BIOCIMMEDIATE
111
 
        flags = 1;
112
 
        if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1)
113
 
                goto eexit;
114
 
#endif
115
 
 
116
 
        /* Install the DHCP filter */
117
 
        if (protocol == ETHERTYPE_ARP) {
118
 
                pf.bf_insns = UNCONST(arp_bpf_filter);
119
 
                pf.bf_len = arp_bpf_filter_len;
120
 
                fdp = &state->arp_fd;
121
 
        } else {
122
 
                pf.bf_insns = UNCONST(dhcp_bpf_filter);
123
 
                pf.bf_len = dhcp_bpf_filter_len;
124
 
                fdp = &state->raw_fd;
125
 
        }
126
 
        if (ioctl(fd, BIOCSETF, &pf) == -1)
127
 
                goto eexit;
128
 
        if (set_cloexec(fd) == -1)
129
 
                goto eexit;
130
 
        if (fdp) {
131
 
                if (*fdp != -1)
132
 
                        close(*fdp);
133
 
                *fdp = fd;
134
 
        }
135
 
        return fd;
136
 
 
137
 
eexit:
138
 
        free(state->buffer);
139
 
        state->buffer = NULL;
140
 
        close(fd);
141
 
        return -1;
142
 
}
143
 
 
144
 
ssize_t
145
 
ipv4_sendrawpacket(const struct interface *ifp, int protocol,
146
 
    const void *data, ssize_t len)
147
 
{
148
 
        struct iovec iov[2];
149
 
        struct ether_header hw;
150
 
        int fd;
151
 
        const struct dhcp_state *state;
152
 
 
153
 
        memset(&hw, 0, ETHER_HDR_LEN);
154
 
        memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
155
 
        hw.ether_type = htons(protocol);
156
 
        iov[0].iov_base = &hw;
157
 
        iov[0].iov_len = ETHER_HDR_LEN;
158
 
        iov[1].iov_base = UNCONST(data);
159
 
        iov[1].iov_len = len;
160
 
        state = D_CSTATE(ifp);
161
 
        if (protocol == ETHERTYPE_ARP)
162
 
                fd = state->arp_fd;
163
 
        else
164
 
                fd = state->raw_fd;
165
 
        return writev(fd, iov, 2);
166
 
}
167
 
 
168
 
/* BPF requires that we read the entire buffer.
169
 
 * So we pass the buffer in the API so we can loop on >1 packet. */
170
 
ssize_t
171
 
ipv4_getrawpacket(struct interface *ifp, int protocol,
172
 
    void *data, ssize_t len, int *partialcsum)
173
 
{
174
 
        int fd = -1;
175
 
        struct bpf_hdr packet;
176
 
        ssize_t bytes;
177
 
        const unsigned char *payload;
178
 
        struct dhcp_state *state;
179
 
 
180
 
        state = D_STATE(ifp);
181
 
        if (protocol == ETHERTYPE_ARP)
182
 
                fd = state->arp_fd;
183
 
        else
184
 
                fd = state->raw_fd;
185
 
 
186
 
        if (partialcsum != NULL)
187
 
                *partialcsum = 0; /* Not supported on BSD */
188
 
 
189
 
        for (;;) {
190
 
                if (state->buffer_len == 0) {
191
 
                        bytes = read(fd, state->buffer, state->buffer_size);
192
 
                        if (bytes == -1)
193
 
                                return errno == EAGAIN ? 0 : -1;
194
 
                        else if ((size_t)bytes < sizeof(packet))
195
 
                                return -1;
196
 
                        state->buffer_len = bytes;
197
 
                        state->buffer_pos = 0;
198
 
                }
199
 
                bytes = -1;
200
 
                memcpy(&packet, state->buffer + state->buffer_pos,
201
 
                    sizeof(packet));
202
 
                if (packet.bh_caplen != packet.bh_datalen)
203
 
                        goto next; /* Incomplete packet, drop. */
204
 
                if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
205
 
                    state->buffer_len)
206
 
                        goto next; /* Packet beyond buffer, drop. */
207
 
                payload = state->buffer + packet.bh_hdrlen + ETHER_HDR_LEN;
208
 
                bytes = packet.bh_caplen - ETHER_HDR_LEN;
209
 
                if (bytes > len)
210
 
                        bytes = len;
211
 
                memcpy(data, payload, bytes);
212
 
next:
213
 
                state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
214
 
                    packet.bh_caplen);
215
 
                if (state->buffer_pos >= state->buffer_len)
216
 
                        state->buffer_len = state->buffer_pos = 0;
217
 
                if (bytes != -1)
218
 
                        return bytes;
219
 
        }
220
 
}