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

« back to all changes in this revision

Viewing changes to ipv4ll.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
1
/*
2
2
 * dhcpcd - DHCP client daemon
3
 
 * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
 
3
 * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4
4
 * All rights reserved
5
5
 
6
6
 * Redistribution and use in source and binary forms, with or without
29
29
#include <signal.h>
30
30
#include <stdlib.h>
31
31
#include <string.h>
32
 
#include <syslog.h>
33
32
#include <unistd.h>
34
33
 
 
34
#define ELOOP_QUEUE 6
 
35
#include "config.h"
35
36
#include "arp.h"
36
37
#include "common.h"
37
38
#include "dhcp.h"
38
39
#include "eloop.h"
 
40
#include "if.h"
39
41
#include "if-options.h"
40
42
#include "ipv4ll.h"
41
 
#include "net.h"
42
43
 
43
44
static struct dhcp_message *
44
45
ipv4ll_make_lease(uint32_t addr)
68
69
        return dhcp;
69
70
}
70
71
 
71
 
static struct dhcp_message *
72
 
ipv4ll_find_lease(uint32_t old_addr)
 
72
static in_addr_t
 
73
ipv4ll_pick_addr(const struct arp_state *astate)
73
74
{
74
 
        uint32_t addr;
 
75
        in_addr_t addr;
 
76
        struct interface *ifp;
 
77
        const struct dhcp_state *state;
75
78
 
76
79
        for (;;) {
77
 
                addr = htonl(LINKLOCAL_ADDR |
78
 
                    (((uint32_t)abs((int)arc4random())
79
 
                        % 0xFD00) + 0x0100));
80
 
                if (addr != old_addr &&
81
 
                    IN_LINKLOCAL(ntohl(addr)))
 
80
                /* RFC 3927 Section 2.1 states that the first 256 and
 
81
                 * last 256 addresses are reserved for future use.
 
82
                 * See ipv4ll_start for why we don't use arc4_random. */
 
83
                addr = ntohl(LINKLOCAL_ADDR |
 
84
                    ((uint32_t)(random() % 0xFD00) + 0x0100));
 
85
 
 
86
                /* No point using a failed address */
 
87
                if (addr == astate->failed.s_addr)
 
88
                        continue;
 
89
 
 
90
                /* Ensure we don't have the address on another interface */
 
91
                TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
 
92
                        state = D_CSTATE(ifp);
 
93
                        if (state && state->addr.s_addr == addr)
 
94
                                break;
 
95
                }
 
96
 
 
97
                /* Yay, this should be a unique and workable IPv4LL address */
 
98
                if (ifp == NULL)
82
99
                        break;
83
100
        }
84
 
        return ipv4ll_make_lease(addr);
85
 
}
86
 
 
87
 
void
88
 
ipv4ll_start(void *arg)
89
 
{
90
 
        struct interface *ifp = arg;
91
 
        struct dhcp_state *state = D_STATE(ifp);
92
 
        uint32_t addr;
93
 
 
94
 
        eloop_timeout_delete(NULL, ifp);
95
 
        state->probes = 0;
96
 
        state->claims = 0;
97
 
        if (state->addr.s_addr) {
98
 
                state->conflicts = 0;
99
 
                if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
100
 
                        arp_announce(ifp);
101
 
                        return;
102
 
                }
103
 
        }
104
 
 
105
 
        if (state->offer == NULL)
106
 
                addr = 0;
107
 
        else {
108
 
                addr = state->offer->yiaddr;
109
 
                free(state->offer);
110
 
        }
111
 
        /* We maybe rebooting an IPv4LL address. */
112
 
        if (!IN_LINKLOCAL(htonl(addr))) {
113
 
                syslog(LOG_INFO, "%s: probing for an IPv4LL address",
114
 
                    ifp->name);
115
 
                addr = 0;
116
 
        }
117
 
        if (addr == 0)
118
 
                state->offer = ipv4ll_find_lease(addr);
119
 
        else
120
 
                state->offer = ipv4ll_make_lease(addr);
121
 
        if (state->offer == NULL)
122
 
                syslog(LOG_ERR, "%s: %m", __func__);
123
 
        else {
124
 
                state->lease.frominfo = 0;
125
 
                arp_probe(ifp);
126
 
        }
127
 
}
128
 
 
129
 
void
130
 
ipv4ll_handle_failure(void *arg)
131
 
{
132
 
        struct interface *ifp = arg;
133
 
        struct dhcp_state *state = D_STATE(ifp);
134
 
        time_t up;
135
 
 
136
 
        if (state->fail.s_addr == state->addr.s_addr) {
 
101
        return addr;
 
102
}
 
103
 
 
104
static void
 
105
ipv4ll_probed(struct arp_state *astate)
 
106
{
 
107
        struct dhcp_state *state = D_STATE(astate->iface);
 
108
 
 
109
        if (state->state == DHS_IPV4LL_BOUND) {
 
110
                ipv4_finaliseaddr(astate->iface);
 
111
                return;
 
112
        }
 
113
 
 
114
        if (state->state != DHS_BOUND) {
 
115
                struct dhcp_message *offer;
 
116
 
 
117
                /* A DHCP lease could have already been offered.
 
118
                 * Backup and replace once the IPv4LL address is bound */
 
119
                offer = state->offer;
 
120
                state->offer = ipv4ll_make_lease(astate->addr.s_addr);
 
121
                if (state->offer == NULL)
 
122
                        logger(astate->iface->ctx, LOG_ERR, "%s: %m", __func__);
 
123
                else
 
124
                        dhcp_bind(astate->iface, astate);
 
125
                state->offer = offer;
 
126
        }
 
127
}
 
128
 
 
129
static void
 
130
ipv4ll_announced(struct arp_state *astate)
 
131
{
 
132
        struct dhcp_state *state = D_STATE(astate->iface);
 
133
 
 
134
        state->conflicts = 0;
 
135
        /* Need to keep the arp state so we can defend our IP. */
 
136
}
 
137
 
 
138
static void
 
139
ipv4ll_probe(void *arg)
 
140
{
 
141
 
 
142
#ifdef IN_IFF_TENTATIVE
 
143
        ipv4ll_probed(arg);
 
144
#else
 
145
        arp_probe(arg);
 
146
#endif
 
147
}
 
148
 
 
149
static void
 
150
ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
 
151
{
 
152
        struct dhcp_state *state = D_STATE(astate->iface);
 
153
        in_addr_t fail;
 
154
 
 
155
        fail = 0;
 
156
        /* RFC 3927 2.2.1, Probe Conflict Detection */
 
157
        if (amsg == NULL ||
 
158
            (amsg->sip.s_addr == astate->addr.s_addr ||
 
159
            (amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr)))
 
160
                fail = astate->addr.s_addr;
 
161
 
 
162
        /* RFC 3927 2.5, Conflict Defense */
 
163
        if (IN_LINKLOCAL(htonl(state->addr.s_addr)) &&
 
164
            amsg && amsg->sip.s_addr == state->addr.s_addr)
 
165
                fail = state->addr.s_addr;
 
166
 
 
167
        if (fail == 0)
 
168
                return;
 
169
 
 
170
        astate->failed.s_addr = fail;
 
171
        arp_report_conflicted(astate, amsg);
 
172
 
 
173
        if (astate->failed.s_addr == state->addr.s_addr) {
 
174
                time_t up;
 
175
 
 
176
                /* RFC 3927 Section 2.5 */
137
177
                up = uptime();
138
178
                if (state->defend + DEFEND_INTERVAL > up) {
139
 
                        syslog(LOG_DEBUG,
140
 
                            "%s: IPv4LL %d second defence failed",
141
 
                            ifp->name, DEFEND_INTERVAL);
142
 
                        dhcp_drop(ifp, "EXPIRE");
143
 
                        state->conflicts = -1;
 
179
                        logger(astate->iface->ctx, LOG_WARNING,
 
180
                            "%s: IPv4LL %d second defence failed for %s",
 
181
                            astate->iface->name, DEFEND_INTERVAL,
 
182
                            inet_ntoa(state->addr));
 
183
                        dhcp_drop(astate->iface, "EXPIRE");
144
184
                } else {
145
 
                        syslog(LOG_DEBUG, "%s: defended IPv4LL address",
146
 
                            ifp->name);
 
185
                        logger(astate->iface->ctx, LOG_DEBUG,
 
186
                            "%s: defended IPv4LL address %s",
 
187
                            astate->iface->name, inet_ntoa(state->addr));
147
188
                        state->defend = up;
148
189
                        return;
149
190
                }
150
191
        }
151
192
 
152
 
        dhcp_close(ifp);
153
 
        free(state->offer);
154
 
        state->offer = NULL;
155
 
        eloop_timeout_delete(NULL, ifp);
156
 
        if (++state->conflicts > MAX_CONFLICTS) {
157
 
                syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
 
193
        arp_cancel(astate);
 
194
        if (++state->conflicts == MAX_CONFLICTS)
 
195
                logger(astate->iface->ctx, LOG_ERR,
 
196
                    "%s: failed to acquire an IPv4LL address",
 
197
                    astate->iface->name);
 
198
        astate->addr.s_addr = ipv4ll_pick_addr(astate);
 
199
        eloop_timeout_add_sec(astate->iface->ctx->eloop,
 
200
                state->conflicts >= MAX_CONFLICTS ?
 
201
                RATE_LIMIT_INTERVAL : PROBE_WAIT,
 
202
                ipv4ll_probe, astate);
 
203
}
 
204
 
 
205
void
 
206
ipv4ll_start(void *arg)
 
207
{
 
208
        struct interface *ifp = arg;
 
209
        struct dhcp_state *state = D_STATE(ifp);
 
210
        struct arp_state *astate;
 
211
        struct ipv4_addr *ap;
 
212
 
 
213
        if (state->arp_ipv4ll)
 
214
                return;
 
215
 
 
216
        /* RFC 3927 Section 2.1 states that the random number generator
 
217
         * SHOULD be seeded with a value derived from persistent information
 
218
         * such as the IEEE 802 MAC address so that it usually picks
 
219
         * the same address without persistent storage. */
 
220
        if (state->conflicts == 0) {
 
221
                unsigned int seed;
 
222
 
 
223
                if (sizeof(seed) > ifp->hwlen) {
 
224
                        seed = 0;
 
225
                        memcpy(&seed, ifp->hwaddr, ifp->hwlen);
 
226
                } else
 
227
                        memcpy(&seed, ifp->hwaddr + ifp->hwlen - sizeof(seed),
 
228
                            sizeof(seed));
 
229
                initstate(seed, state->randomstate, sizeof(state->randomstate));
 
230
        }
 
231
 
 
232
        if ((astate = arp_new(ifp, NULL)) == NULL)
 
233
                return;
 
234
 
 
235
        state->arp_ipv4ll = astate;
 
236
        astate->probed_cb = ipv4ll_probed;
 
237
        astate->announced_cb = ipv4ll_announced;
 
238
        astate->conflicted_cb = ipv4ll_conflicted;
 
239
 
 
240
        if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
 
241
                astate->addr = state->addr;
 
242
                arp_announce(astate);
 
243
                return;
 
244
        }
 
245
 
 
246
        if (state->offer && IN_LINKLOCAL(ntohl(state->offer->yiaddr))) {
 
247
                astate->addr.s_addr = state->offer->yiaddr;
 
248
                free(state->offer);
 
249
                state->offer = NULL;
 
250
                ap = ipv4_iffindaddr(ifp, &astate->addr, NULL);
 
251
        } else
 
252
                ap = ipv4_iffindlladdr(ifp);
 
253
        if (ap) {
 
254
                astate->addr = ap->addr;
 
255
                ipv4ll_probed(astate);
 
256
                return;
 
257
        }
 
258
 
 
259
        setstate(state->randomstate);
 
260
        /* We maybe rebooting an IPv4LL address. */
 
261
        if (!IN_LINKLOCAL(htonl(astate->addr.s_addr))) {
 
262
                logger(ifp->ctx, LOG_INFO, "%s: probing for an IPv4LL address",
158
263
                    ifp->name);
159
 
                state->interval = RATE_LIMIT_INTERVAL / 2;
160
 
                dhcp_discover(ifp);
161
 
        } else {
162
 
                eloop_timeout_add_sec(PROBE_WAIT, ipv4ll_start, ifp);
 
264
                astate->addr.s_addr = INADDR_ANY;
163
265
        }
 
266
        if (astate->addr.s_addr == INADDR_ANY)
 
267
                astate->addr.s_addr = ipv4ll_pick_addr(astate);
 
268
#ifdef IN_IFF_TENTATIVE
 
269
        ipv4ll_probed(astate);
 
270
#else
 
271
        arp_probe(astate);
 
272
#endif
 
273
}
 
274
 
 
275
void
 
276
ipv4ll_stop(struct interface *ifp)
 
277
{
 
278
        struct dhcp_state *state = D_STATE(ifp);
 
279
 
 
280
        eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp_ipv4ll);
164
281
}