source: rtems-libbsd/dhcpcd/ipv4.c @ 2017a6d

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 2017a6d was f2ed769, checked in by Sebastian Huber <sebastian.huber@…>, on 01/30/14 at 12:29:46

DHCPCD(8): Import

Import DHCPCD(8) from:

http://roy.marples.name/projects/dhcpcd/

The upstream sources can be obtained via:

fossil clone http://roy.marples.name/projects/dhcpcd

The imported version is 2014-01-29 19:46:44 [6b209507bb].

  • Property mode set to 100644
File size: 18.3 KB
Line 
1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/queue.h>
29#include <sys/socket.h>
30#include <sys/types.h>
31
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <net/route.h>
35
36#ifdef __linux__
37#  include <asm/types.h> /* for systems with broken headers */
38#  include <linux/rtnetlink.h>
39#endif
40
41#include <ctype.h>
42#include <errno.h>
43#include <stdlib.h>
44#include <string.h>
45#include <syslog.h>
46#include <unistd.h>
47
48#include "config.h"
49#include "common.h"
50#include "dhcpcd.h"
51#include "dhcp.h"
52#include "if-options.h"
53#include "if-pref.h"
54#include "ipv4.h"
55#include "net.h"
56#include "script.h"
57
58#define IPV4_LOOPBACK_ROUTE
59#ifdef __linux__
60/* Linux has had loopback routes in the local table since 2.2 */
61#undef IPV4_LOOPBACK_ROUTE
62#endif
63
64static struct rt_head *routes;
65
66int
67inet_ntocidr(struct in_addr address)
68{
69        int cidr = 0;
70        uint32_t mask = htonl(address.s_addr);
71
72        while (mask) {
73                cidr++;
74                mask <<= 1;
75        }
76        return cidr;
77}
78
79int
80inet_cidrtoaddr(int cidr, struct in_addr *addr)
81{
82        int ocets;
83
84        if (cidr < 1 || cidr > 32) {
85                errno = EINVAL;
86                return -1;
87        }
88        ocets = (cidr + 7) / 8;
89
90        addr->s_addr = 0;
91        if (ocets > 0) {
92                memset(&addr->s_addr, 255, (size_t)ocets - 1);
93                memset((unsigned char *)&addr->s_addr + (ocets - 1),
94                    (256 - (1 << (32 - cidr) % 8)), 1);
95        }
96
97        return 0;
98}
99
100uint32_t
101ipv4_getnetmask(uint32_t addr)
102{
103        uint32_t dst;
104
105        if (addr == 0)
106                return 0;
107
108        dst = htonl(addr);
109        if (IN_CLASSA(dst))
110                return ntohl(IN_CLASSA_NET);
111        if (IN_CLASSB(dst))
112                return ntohl(IN_CLASSB_NET);
113        if (IN_CLASSC(dst))
114                return ntohl(IN_CLASSC_NET);
115
116        return 0;
117}
118
119struct ipv4_addr *
120ipv4_findaddr(struct interface *ifp,
121    const struct in_addr *addr, const struct in_addr *net)
122{
123        struct ipv4_state *state;
124        struct ipv4_addr *ap;
125
126        state = IPV4_STATE(ifp);
127        if (state) {
128                TAILQ_FOREACH(ap, &state->addrs, next) {
129                        if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
130                            (net == NULL || ap->net.s_addr == net->s_addr))
131                                return ap;
132                }
133        }
134        return NULL;
135}
136
137int
138ipv4_addrexists(const struct in_addr *addr)
139{
140        struct interface *ifp;
141        struct dhcp_state *state;
142
143        TAILQ_FOREACH(ifp, ifaces, next) {
144                state = D_STATE(ifp);
145                if (state) {
146                        if (addr == NULL) {
147                                if (state->addr.s_addr != INADDR_ANY)
148                                        return 1;
149                        } else if (addr->s_addr == state->addr.s_addr)
150                                return 1;
151                }
152                if (addr != NULL && ipv4_findaddr(ifp, addr, NULL))
153                        return 1;
154        }
155        return 0;
156}
157
158void
159ipv4_freeroutes(struct rt_head *rts)
160{
161        struct rt *r;
162
163        if (rts) {
164                while ((r = TAILQ_FIRST(rts))) {
165                        TAILQ_REMOVE(rts, r, next);
166                        free(r);
167                }
168                free(rts);
169        }
170}
171
172#ifdef DEBUG_MEMORY
173static void
174ipv4_cleanup()
175{
176
177        ipv4_freeroutes(routes);
178}
179#endif
180
181int
182ipv4_init(void)
183{
184
185        if (routes == NULL) {
186                routes = malloc(sizeof(*routes));
187                if (routes == NULL)
188                        return -1;
189                TAILQ_INIT(routes);
190#ifdef DEBUG_MEMORY
191                atexit(ipv4_cleanup);
192#endif
193        }
194        return 0;
195}
196
197static struct rt *
198find_route(struct rt_head *rts, const struct rt *r, const struct rt *srt)
199{
200        struct rt *rt;
201
202        if (rts == NULL)
203                return NULL;
204        TAILQ_FOREACH(rt, rts, next) {
205                if (rt->dest.s_addr == r->dest.s_addr &&
206#if HAVE_ROUTE_METRIC
207                    (srt || (!rt->iface ||
208                        rt->iface->metric == r->iface->metric)) &&
209#endif
210                    (!srt || srt != rt) &&
211                    rt->net.s_addr == r->net.s_addr)
212                        return rt;
213        }
214        return NULL;
215}
216
217static void
218desc_route(const char *cmd, const struct rt *rt)
219{
220        char addr[sizeof("000.000.000.000") + 1];
221        const char *ifname = rt->iface->name;
222
223        strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
224        if (rt->gate.s_addr == INADDR_ANY)
225                syslog(LOG_INFO, "%s: %s route to %s/%d", ifname, cmd,
226                    addr, inet_ntocidr(rt->net));
227        else if (rt->gate.s_addr == rt->dest.s_addr &&
228            rt->net.s_addr == INADDR_BROADCAST)
229                syslog(LOG_INFO, "%s: %s host route to %s", ifname, cmd,
230                    addr);
231        else if (rt->gate.s_addr == htonl(INADDR_LOOPBACK) &&
232            rt->net.s_addr == INADDR_BROADCAST)
233                syslog(LOG_INFO, "%s: %s host route to %s via %s", ifname, cmd,
234                    addr, inet_ntoa(rt->gate));
235        else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY)
236                syslog(LOG_INFO, "%s: %s default route via %s", ifname, cmd,
237                    inet_ntoa(rt->gate));
238        else
239                syslog(LOG_INFO, "%s: %s route to %s/%d via %s", ifname, cmd,
240                    addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
241}
242
243/* If something other than dhcpcd removes a route,
244 * we need to remove it from our internal table. */
245int
246ipv4_routedeleted(const struct rt *rt)
247{
248        struct rt *f;
249
250        f = find_route(routes, rt, NULL);
251        if (f == NULL)
252                return 0;
253        desc_route("removing", f);
254        TAILQ_REMOVE(routes, f, next);
255        free(f);
256        return 1;
257}
258
259#define n_route(a)       nc_route(1, a, a)
260#define c_route(a, b)    nc_route(0, a, b)
261static int
262nc_route(int add, struct rt *ort, struct rt *nrt)
263{
264
265        /* Don't set default routes if not asked to */
266        if (nrt->dest.s_addr == 0 &&
267            nrt->net.s_addr == 0 &&
268            !(nrt->iface->options->options & DHCPCD_GATEWAY))
269                return -1;
270
271        desc_route(add ? "adding" : "changing", nrt);
272        /* We delete and add the route so that we can change metric and
273         * prefer the interface.
274         * This also has the nice side effect of flushing ARP entries so
275         * we don't have to do that manually. */
276        ipv4_deleteroute(ort);
277        if (!ipv4_addroute(nrt))
278                return 0;
279        syslog(LOG_ERR, "%s: ipv4_addroute: %m", nrt->iface->name);
280        return -1;
281}
282
283static int
284d_route(struct rt *rt)
285{
286        int retval;
287
288        desc_route("deleting", rt);
289        retval = ipv4_deleteroute(rt);
290        if (retval != 0 && errno != ENOENT && errno != ESRCH)
291                syslog(LOG_ERR,"%s: ipv4_deleteroute: %m", rt->iface->name);
292        return retval;
293}
294
295static struct rt *
296get_subnet_route(struct dhcp_message *dhcp)
297{
298        in_addr_t addr;
299        struct in_addr net;
300        struct rt *rt;
301
302        addr = dhcp->yiaddr;
303        if (addr == 0)
304                addr = dhcp->ciaddr;
305        /* Ensure we have all the needed values */
306        if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
307                net.s_addr = ipv4_getnetmask(addr);
308        if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
309                return NULL;
310        rt = malloc(sizeof(*rt));
311        rt->dest.s_addr = addr & net.s_addr;
312        rt->net.s_addr = net.s_addr;
313        rt->gate.s_addr = 0;
314        return rt;
315}
316
317static struct rt_head *
318add_subnet_route(struct rt_head *rt, const struct interface *ifp)
319{
320        struct rt *r;
321        const struct dhcp_state *s;
322
323        if (rt == NULL) /* earlier malloc failed */
324                return NULL;
325
326        s = D_CSTATE(ifp);
327        if (s->net.s_addr == INADDR_BROADCAST ||
328            s->net.s_addr == INADDR_ANY)
329                return rt;
330
331        r = malloc(sizeof(*r));
332        if (r == NULL) {
333                syslog(LOG_ERR, "%s: %m", __func__);
334                ipv4_freeroutes(rt);
335                return NULL;
336        }
337        r->dest.s_addr = s->addr.s_addr & s->net.s_addr;
338        r->net.s_addr = s->net.s_addr;
339        r->gate.s_addr = 0;
340        TAILQ_INSERT_HEAD(rt, r, next);
341        return rt;
342}
343
344#ifdef IPV4_LOOPBACK_ROUTE
345static struct rt_head *
346add_loopback_route(struct rt_head *rt, const struct interface *ifp)
347{
348        struct rt *r;
349        const struct dhcp_state *s;
350
351        if (rt == NULL) /* earlier malloc failed */
352                return NULL;
353
354        s = D_CSTATE(ifp);
355        if (s->addr.s_addr == INADDR_ANY)
356                return rt;
357
358        r = malloc(sizeof(*r));
359        if (r == NULL) {
360                syslog(LOG_ERR, "%s: %m", __func__);
361                ipv4_freeroutes(rt);
362                return NULL;
363        }
364        r->dest.s_addr = s->addr.s_addr;
365        r->net.s_addr = INADDR_BROADCAST;
366        r->gate.s_addr = htonl(INADDR_LOOPBACK);
367        TAILQ_INSERT_HEAD(rt, r, next);
368        return rt;
369}
370#endif
371
372static struct rt_head *
373get_routes(struct interface *ifp)
374{
375        struct rt_head *nrt;
376        struct rt *rt, *r = NULL;
377
378        if (ifp->options->routes && TAILQ_FIRST(ifp->options->routes)) {
379                nrt = malloc(sizeof(*nrt));
380                TAILQ_INIT(nrt);
381                TAILQ_FOREACH(rt, ifp->options->routes, next) {
382                        if (rt->gate.s_addr == 0)
383                                break;
384                        r = malloc(sizeof(*r));
385                        if (r == NULL) {
386                                syslog(LOG_ERR, "%s: %m", __func__);
387                                ipv4_freeroutes(nrt);
388                                return NULL;
389                        }
390                        memcpy(r, rt, sizeof(*r));
391                        TAILQ_INSERT_TAIL(nrt, r, next);
392                }
393                return nrt;
394        }
395
396        return get_option_routes(ifp, D_STATE(ifp)->new);
397}
398
399/* Some DHCP servers add set host routes by setting the gateway
400 * to the assinged IP address. This differs from our notion of a host route
401 * where the gateway is the destination address, so we fix it. */
402static struct rt_head *
403massage_host_routes(struct rt_head *rt, const struct interface *ifp)
404{
405        struct rt *r;
406
407        if (rt) {
408                TAILQ_FOREACH(r, rt, next) {
409                        if (r->gate.s_addr == D_CSTATE(ifp)->addr.s_addr &&
410                            r->net.s_addr == INADDR_BROADCAST)
411                                r->gate.s_addr = r->dest.s_addr;
412                }
413        }
414        return rt;
415}
416
417static struct rt_head *
418add_destination_route(struct rt_head *rt, const struct interface *iface)
419{
420        struct rt *r;
421
422        if (rt == NULL || /* failed a malloc earlier probably */
423            !(iface->flags & IFF_POINTOPOINT) ||
424            !has_option_mask(iface->options->dstmask, DHO_ROUTER))
425                return rt;
426
427        r = malloc(sizeof(*r));
428        if (r == NULL) {
429                syslog(LOG_ERR, "%s: %m", __func__);
430                ipv4_freeroutes(rt);
431                return NULL;
432        }
433        r->dest.s_addr = INADDR_ANY;
434        r->net.s_addr = INADDR_ANY;
435        r->gate.s_addr = D_CSTATE(iface)->dst.s_addr;
436        TAILQ_INSERT_HEAD(rt, r, next);
437        return rt;
438}
439
440/* We should check to ensure the routers are on the same subnet
441 * OR supply a host route. If not, warn and add a host route. */
442static struct rt_head *
443add_router_host_route(struct rt_head *rt, const struct interface *ifp)
444{
445        struct rt *rtp, *rtn;
446        const char *cp, *cp2, *cp3, *cplim;
447
448        if (rt == NULL) /* earlier malloc failed */
449                return NULL;
450
451        TAILQ_FOREACH(rtp, rt, next) {
452                if (rtp->dest.s_addr != INADDR_ANY)
453                        continue;
454                /* Scan for a route to match */
455                TAILQ_FOREACH(rtn, rt, next) {
456                        if (rtn == rtp)
457                                break;
458                        /* match host */
459                        if (rtn->dest.s_addr == rtp->gate.s_addr)
460                                break;
461                        /* match subnet */
462                        cp = (const char *)&rtp->gate.s_addr;
463                        cp2 = (const char *)&rtn->dest.s_addr;
464                        cp3 = (const char *)&rtn->net.s_addr;
465                        cplim = cp3 + sizeof(rtn->net.s_addr);
466                        while (cp3 < cplim) {
467                                if ((*cp++ ^ *cp2++) & *cp3++)
468                                        break;
469                        }
470                        if (cp3 == cplim)
471                                break;
472                }
473                if (rtn != rtp)
474                        continue;
475                if (ifp->flags & IFF_NOARP) {
476                        syslog(LOG_WARNING,
477                            "%s: forcing router %s through interface",
478                            ifp->name, inet_ntoa(rtp->gate));
479                        rtp->gate.s_addr = 0;
480                        continue;
481                }
482                syslog(LOG_WARNING, "%s: router %s requires a host route",
483                    ifp->name, inet_ntoa(rtp->gate));
484                rtn = malloc(sizeof(*rtn));
485                if (rtn == NULL) {
486                        syslog(LOG_ERR, "%s: %m", __func__);
487                        ipv4_freeroutes(rt);
488                        return NULL;
489                }
490                rtn->dest.s_addr = rtp->gate.s_addr;
491                rtn->net.s_addr = INADDR_BROADCAST;
492                rtn->gate.s_addr = rtp->gate.s_addr;
493                TAILQ_INSERT_BEFORE(rtp, rtn, next);
494        }
495        return rt;
496}
497
498void
499ipv4_buildroutes(void)
500{
501        struct rt_head *nrs, *dnr;
502        struct rt *or, *rt, *rtn;
503        struct interface *ifp;
504        const struct dhcp_state *state;
505
506        nrs = malloc(sizeof(*nrs));
507        if (nrs == NULL) {
508                syslog(LOG_ERR, "%s: %m", __func__);
509                return;
510        }
511        TAILQ_INIT(nrs);
512        TAILQ_FOREACH(ifp, ifaces, next) {
513                state = D_CSTATE(ifp);
514                if (state == NULL || state->new == NULL)
515                        continue;
516                dnr = get_routes(ifp);
517                dnr = massage_host_routes(dnr, ifp);
518                dnr = add_subnet_route(dnr, ifp);
519#ifdef IPV4_LOOPBACK_ROUTE
520                dnr = add_loopback_route(dnr, ifp);
521#endif
522                if (ifp->options->options & DHCPCD_GATEWAY) {
523                        dnr = add_router_host_route(dnr, ifp);
524                        dnr = add_destination_route(dnr, ifp);
525                }
526                if (dnr == NULL) /* failed to malloc all new routes */
527                        continue;
528                TAILQ_FOREACH_SAFE(rt, dnr, next, rtn) {
529                        rt->iface = ifp;
530                        rt->metric = ifp->metric;
531                        /* Is this route already in our table? */
532                        if ((find_route(nrs, rt, NULL)) != NULL)
533                                continue;
534                        rt->src.s_addr = state->addr.s_addr;
535                        /* Do we already manage it? */
536                        if ((or = find_route(routes, rt, NULL))) {
537                                if (or->iface != ifp ||
538                                    or->src.s_addr != state->addr.s_addr ||
539                                    rt->gate.s_addr != or->gate.s_addr ||
540                                    rt->metric != or->metric)
541                                {
542                                        if (c_route(or, rt) != 0)
543                                                continue;
544                                }
545                                TAILQ_REMOVE(routes, or, next);
546                                free(or);
547                        } else {
548                                if (n_route(rt) != 0)
549                                        continue;
550                        }
551                        TAILQ_REMOVE(dnr, rt, next);
552                        TAILQ_INSERT_TAIL(nrs, rt, next);
553                }
554                ipv4_freeroutes(dnr);
555        }
556
557        /* Remove old routes we used to manage */
558        TAILQ_FOREACH(rt, routes, next) {
559                if (find_route(nrs, rt, NULL) == NULL)
560                        d_route(rt);
561        }
562        ipv4_freeroutes(routes);
563
564        routes = nrs;
565}
566
567static int
568delete_address1(struct interface *ifp,
569    const struct in_addr *addr, const struct in_addr *net)
570{
571        int r;
572        struct ipv4_state *state;
573        struct ipv4_addr *ap;
574
575        syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
576            ifp->name, inet_ntoa(*addr), inet_ntocidr(*net));
577        r = ipv4_deleteaddress(ifp, addr, net);
578        if (r == -1 && errno != EADDRNOTAVAIL && errno != ENXIO &&
579            errno != ENODEV)
580                syslog(LOG_ERR, "%s: %s: %m", ifp->name, __func__);
581
582        state = IPV4_STATE(ifp);
583        TAILQ_FOREACH(ap, &state->addrs, next) {
584                if (ap->addr.s_addr == addr->s_addr &&
585                    ap->net.s_addr == net->s_addr)
586                {
587                        TAILQ_REMOVE(&state->addrs, ap, next);
588                        free(ap);
589                        break;
590                }
591        }
592        return r;
593}
594
595static int
596delete_address(struct interface *ifp)
597{
598        int r;
599        struct if_options *ifo;
600        struct dhcp_state *state;
601
602        state = D_STATE(ifp);
603        ifo = ifp->options;
604        if (ifo->options & DHCPCD_INFORM ||
605            (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
606                return 0;
607        r = delete_address1(ifp, &state->addr, &state->net);
608        state->addr.s_addr = 0;
609        state->net.s_addr = 0;
610        return r;
611}
612
613static struct ipv4_state *
614ipv4_getstate(struct interface *ifp)
615{
616        struct ipv4_state *state;
617
618        state = IPV4_STATE(ifp);
619        if (state == NULL) {
620                ifp->if_data[IF_DATA_IPV4] = malloc(sizeof(*state));
621                state = IPV4_STATE(ifp);
622                if (state == NULL) {
623                        syslog(LOG_ERR, "%s: %m", __func__);
624                        return NULL;
625                }
626                TAILQ_INIT(&state->addrs);
627        }
628        return state;
629}
630
631void
632ipv4_applyaddr(void *arg)
633{
634        struct interface *ifp = arg;
635        struct dhcp_state *state = D_STATE(ifp);
636        struct dhcp_message *dhcp;
637        struct dhcp_lease *lease;
638        struct if_options *ifo = ifp->options;
639        struct ipv4_addr *ap;
640        struct ipv4_state *istate;
641        struct rt *rt;
642        int r;
643
644        /* As we are now adjusting an interface, we need to ensure
645         * we have them in the right order for routing and configuration. */
646        sort_interfaces();
647
648        if (state == NULL)
649                return;
650        dhcp = state->new;
651        lease = &state->lease;
652
653        if (dhcp == NULL) {
654                if ((ifo->options & (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
655                    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
656                {
657                        ipv4_buildroutes();
658                        if (state->addr.s_addr != 0)
659                                delete_address(ifp);
660                        script_runreason(ifp, state->reason);
661                }
662                return;
663        }
664
665        /* If the netmask is different, delete the addresss */
666        ap = ipv4_findaddr(ifp, &lease->addr, NULL);
667        if (ap && ap->net.s_addr != lease->net.s_addr)
668                delete_address1(ifp, &ap->addr, &ap->net);
669
670        if (ipv4_findaddr(ifp, &lease->addr, &lease->net))
671                syslog(LOG_DEBUG, "%s: IP address %s/%d already exists",
672                    ifp->name, inet_ntoa(lease->addr),
673                    inet_ntocidr(lease->net));
674        else {
675                syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
676                    ifp->name, inet_ntoa(lease->addr),
677                    inet_ntocidr(lease->net));
678                if (ifo->options & DHCPCD_NOALIAS)
679                        r = ipv4_setaddress(ifp,
680                            &lease->addr, &lease->net, &lease->brd);
681                else
682                        r = ipv4_addaddress(ifp,
683                            &lease->addr, &lease->net, &lease->brd);
684                if (r == -1 && errno != EEXIST) {
685                        syslog(LOG_ERR, "%s: ipv4_addaddress: %m", __func__);
686                        return;
687                }
688                istate = ipv4_getstate(ifp);
689                ap = malloc(sizeof(*ap));
690                ap->addr = lease->addr;
691                ap->net = lease->net;
692                ap->dst.s_addr = INADDR_ANY;
693                TAILQ_INSERT_TAIL(&istate->addrs, ap, next);
694        }
695
696        /* Now delete the old address if different */
697        if (state->addr.s_addr != lease->addr.s_addr &&
698            state->addr.s_addr != 0)
699                delete_address(ifp);
700
701        state->addr.s_addr = lease->addr.s_addr;
702        state->net.s_addr = lease->net.s_addr;
703
704        /* We need to delete the subnet route to have our metric or
705         * prefer the interface. */
706        rt = get_subnet_route(dhcp);
707        if (rt != NULL) {
708                rt->iface = ifp;
709                rt->metric = 0;
710                if (!find_route(routes, rt, NULL))
711                        ipv4_deleteroute(rt);
712                free(rt);
713        }
714
715        ipv4_buildroutes();
716        if (!state->lease.frominfo &&
717            !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
718                if (write_lease(ifp, dhcp) == -1)
719                        syslog(LOG_ERR, "%s: write_lease: %m", __func__);
720        script_runreason(ifp, state->reason);
721}
722
723void
724ipv4_handleifa(int type, struct if_head *ifs, const char *ifname,
725    const struct in_addr *addr, const struct in_addr *net,
726    const struct in_addr *dst)
727{
728        struct interface *ifp;
729        struct ipv4_state *state;
730        struct ipv4_addr *ap;
731
732        if (ifs == NULL)
733                ifs = ifaces;
734        if (ifs == NULL)
735                return;
736        if (addr->s_addr == INADDR_ANY)
737                return;
738
739        TAILQ_FOREACH(ifp, ifs, next) {
740                if (strcmp(ifp->name, ifname) == 0)
741                        break;
742        }
743        if (ifp == NULL)
744                return;
745
746        state = ipv4_getstate(ifp);
747        if (state == NULL)
748                return;
749        ap = ipv4_findaddr(ifp, addr, net);
750        if (type == RTM_NEWADDR && ap == NULL) {
751                ap = malloc(sizeof(*ap));
752                if (ap == NULL) {
753                        syslog(LOG_ERR, "%s: %m", __func__);
754                        return;
755                }
756                ap->addr.s_addr = addr->s_addr;
757                ap->net.s_addr = net->s_addr;
758                if (dst)
759                        ap->dst.s_addr = dst->s_addr;
760                else
761                        ap->dst.s_addr = INADDR_ANY;
762                TAILQ_INSERT_TAIL(&state->addrs, ap, next);
763        } else if (type == RTM_DELADDR) {
764                if (ap == NULL)
765                        return;
766                TAILQ_REMOVE(&state->addrs, ap, next);
767                free(ap);
768        }
769
770        dhcp_handleifa(type, ifp, addr, net, dst);
771}
772
773void
774ipv4_free(struct interface *ifp)
775{
776        struct ipv4_state *state;
777        struct ipv4_addr *addr;
778
779        state = IPV4_STATE(ifp);
780        if (state) {
781                while ((addr = TAILQ_FIRST(&state->addrs))) {
782                        TAILQ_REMOVE(&state->addrs, addr, next);
783                        free(addr);
784                }
785                free(state);
786        }
787}
Note: See TracBrowser for help on using the repository browser.