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

« back to all changes in this revision

Viewing changes to if-linux.c

  • Committer: Package Import Robot
  • Author(s): Roy Marples
  • Date: 2013-08-04 08:00:44 UTC
  • mfrom: (1.1.5)
  • Revision ID: package-import@ubuntu.com-20130804080044-36wi725sqa9658eq
Tags: 6.0.5-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
 
1
/*
2
2
 * dhcpcd - DHCP client daemon
3
 
 * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
 
3
 * Copyright (c) 2006-2013 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
57
57
 
58
58
#include "config.h"
59
59
#include "common.h"
60
 
#include "configure.h"
61
60
#include "dhcp.h"
 
61
#include "ipv4.h"
 
62
#include "ipv6.h"
62
63
#include "net.h"
63
64
 
64
65
static int sock_fd;
105
106
        if (fp == NULL)
106
107
                return errno == ENOENT ? 0 : -1;
107
108
        if (fgets(buf, sizeof(buf), fp) != NULL && buf[0] == '0')
108
 
                iface->state->options->options |= DHCPCD_BROADCAST;
 
109
                iface->options->options |= DHCPCD_BROADCAST;
109
110
        fclose(fp);
110
111
        return 0;
111
112
}
125
126
}
126
127
 
127
128
int
128
 
init_sockets(void)
 
129
open_sockets(void)
129
130
{
130
131
        if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
131
132
                return -1;
141
142
        struct sockaddr_nl snl;
142
143
 
143
144
        memset(&snl, 0, sizeof(snl));
144
 
        snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
 
145
        snl.nl_groups = RTMGRP_LINK;
 
146
 
 
147
#ifdef INET
 
148
        snl.nl_groups |= RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
 
149
#endif
 
150
#ifdef INET6
 
151
        snl.nl_groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
 
152
#endif
 
153
 
145
154
        return _open_link_socket(&snl);
146
155
}
147
156
 
152
161
        char *buf = NULL, *nbuf;
153
162
        ssize_t buflen = 0, bytes;
154
163
        struct nlmsghdr *nlm;
 
164
        struct sockaddr_nl nladdr;
 
165
        socklen_t nladdr_len = sizeof(nladdr);
155
166
        int r = -1;
156
167
 
157
168
        for (;;) {
180
191
                                goto eexit;
181
192
                        buf = nbuf;
182
193
                }
183
 
                bytes = recv(fd, buf, buflen, flags);
 
194
                bytes = recvfrom(fd, buf, buflen, flags,
 
195
                    (struct sockaddr *)&nladdr, &nladdr_len);
184
196
                if (bytes == -1) {
185
197
                        if (errno == EAGAIN) {
186
198
                                r = 0;
190
202
                                continue;
191
203
                        goto eexit;
192
204
                }
193
 
                for (nlm = (struct nlmsghdr *)buf;
 
205
 
 
206
                /* Check sender */
 
207
                if (nladdr_len != sizeof(nladdr)) {
 
208
                        errno = EINVAL;
 
209
                        goto eexit;
 
210
                }
 
211
                /* Ignore message if it is not from kernel */
 
212
                if (nladdr.nl_pid != 0)
 
213
                        continue;
 
214
 
 
215
                for (nlm = (struct nlmsghdr *)(void *)buf;
194
216
                     NLMSG_OK(nlm, (size_t)bytes);
195
217
                     nlm = NLMSG_NEXT(nlm, bytes))
196
218
                {
248
270
            rtm->rtm_family != AF_INET ||
249
271
            nlm->nlmsg_pid == (uint32_t)getpid())
250
272
                return 1;
251
 
        rta = (struct rtattr *) ((char *)rtm + NLMSG_ALIGN(sizeof(*rtm)));
 
273
        rta = (struct rtattr *)(void *)((char *)rtm +NLMSG_ALIGN(sizeof(*rtm)));
252
274
        len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
253
 
        rt.iface = NULL;
 
275
        memset(&rt, 0, sizeof(rt));
254
276
        rt.dest.s_addr = INADDR_ANY;
255
277
        rt.net.s_addr = INADDR_ANY;
256
278
        rt.gate.s_addr = INADDR_ANY;
257
 
        rt.next = NULL;
258
279
        metric = 0;
259
280
        while (RTA_OK(rta, len)) {
260
281
                switch (rta->rta_type) {
279
300
        }
280
301
        if (rt.iface != NULL) {
281
302
                if (metric == rt.iface->metric) {
 
303
#ifdef INET
282
304
                        inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
283
 
                        route_deleted(&rt);
 
305
                        ipv4_routedeleted(&rt);
 
306
#endif
284
307
                }
285
308
        }
286
309
        return 1;
292
315
        int len;
293
316
        struct rtattr *rta;
294
317
        struct ifaddrmsg *ifa;
 
318
        char ifn[IF_NAMESIZE + 1];
 
319
        struct interface *iface;
 
320
#ifdef INET
295
321
        struct in_addr addr, net, dest;
296
 
        char ifn[IF_NAMESIZE + 1];
297
 
        struct interface *iface;
 
322
#endif
 
323
#ifdef INET6
 
324
        struct in6_addr addr6;
 
325
#endif
298
326
 
299
327
        if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
300
328
                return 0;
304
332
                errno = EBADMSG;
305
333
                return -1;
306
334
        }
307
 
        if (nlm->nlmsg_pid == (uint32_t)getpid())
308
 
                return 1;
 
335
//      if (nlm->nlmsg_pid == (uint32_t)getpid())
 
336
//              return 1;
309
337
        ifa = NLMSG_DATA(nlm);
310
338
        if (if_indextoname(ifa->ifa_index, ifn) == NULL)
311
339
                return -1;
314
342
                return 1;
315
343
        rta = (struct rtattr *) IFA_RTA(ifa);
316
344
        len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
317
 
        addr.s_addr = dest.s_addr = INADDR_ANY;
318
 
        dest.s_addr = INADDR_ANY;
319
 
        inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
320
 
        while (RTA_OK(rta, len)) {
321
 
                switch (rta->rta_type) {
322
 
                case IFA_ADDRESS:
323
 
                        if (iface->flags & IFF_POINTOPOINT) {
324
 
                                memcpy(&dest.s_addr, RTA_DATA(rta),
325
 
                                    sizeof(addr.s_addr));
326
 
                        }
327
 
                        break;
328
 
                case IFA_LOCAL:
329
 
                        memcpy(&addr.s_addr, RTA_DATA(rta),
330
 
                            sizeof(addr.s_addr));
331
 
                        break;
332
 
                }
333
 
                rta = RTA_NEXT(rta, len);
 
345
        switch (ifa->ifa_family) {
 
346
#ifdef INET
 
347
        case AF_INET:
 
348
                addr.s_addr = dest.s_addr = INADDR_ANY;
 
349
                dest.s_addr = INADDR_ANY;
 
350
                inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
 
351
                while (RTA_OK(rta, len)) {
 
352
                        switch (rta->rta_type) {
 
353
                        case IFA_ADDRESS:
 
354
                                if (iface->flags & IFF_POINTOPOINT) {
 
355
                                        memcpy(&dest.s_addr, RTA_DATA(rta),
 
356
                                               sizeof(addr.s_addr));
 
357
                                }
 
358
                                break;
 
359
                        case IFA_LOCAL:
 
360
                                memcpy(&addr.s_addr, RTA_DATA(rta),
 
361
                                       sizeof(addr.s_addr));
 
362
                                break;
 
363
                        }
 
364
                        rta = RTA_NEXT(rta, len);
 
365
                }
 
366
                ipv4_handleifa(nlm->nlmsg_type, ifn, &addr, &net, &dest);
 
367
                break;
 
368
#endif
 
369
#ifdef INET6
 
370
        case AF_INET6:
 
371
                memset(&addr6, 0, sizeof(addr6));
 
372
                while (RTA_OK(rta, len)) {
 
373
                        switch (rta->rta_type) {
 
374
                        case IFA_ADDRESS:
 
375
                                memcpy(&addr6.s6_addr, RTA_DATA(rta),
 
376
                                       sizeof(addr6.s6_addr));
 
377
                                break;
 
378
                        }
 
379
                        rta = RTA_NEXT(rta, len);
 
380
                }
 
381
                ipv6_handleifa(nlm->nlmsg_type, NULL, ifn,
 
382
                    &addr6, ifa->ifa_flags);
 
383
                break;
 
384
#endif
334
385
        }
335
 
        handle_ifa(nlm->nlmsg_type, ifn, &addr, &net, &dest);
336
386
        return 1;
337
387
}
338
388
 
 
389
static short l2addr_len(unsigned short if_type)
 
390
{
 
391
 
 
392
        switch (if_type) {
 
393
        case ARPHRD_ETHER: /* FALLTHROUGH */
 
394
        case ARPHRD_IEEE802: /*FALLTHROUGH */
 
395
        case ARPHRD_IEEE80211:
 
396
                return 6;
 
397
        case ARPHRD_IEEE1394:
 
398
                return 8;
 
399
        case ARPHRD_INFINIBAND:
 
400
                return 20;
 
401
        default:
 
402
                return -1;
 
403
        }
 
404
}
 
405
 
339
406
static int
340
407
link_netlink(struct nlmsghdr *nlm)
341
408
{
342
409
        int len;
343
 
        struct rtattr *rta;
 
410
        struct rtattr *rta, *hwaddr;
344
411
        struct ifinfomsg *ifi;
345
412
        char ifn[IF_NAMESIZE + 1];
346
413
 
361
428
        ifi = NLMSG_DATA(nlm);
362
429
        if (ifi->ifi_flags & IFF_LOOPBACK)
363
430
                return 1;
364
 
        rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
 
431
        rta = (struct rtattr *)(void *)((char *)ifi +NLMSG_ALIGN(sizeof(*ifi)));
365
432
        len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
366
433
        *ifn = '\0';
 
434
        hwaddr = NULL;
367
435
        while (RTA_OK(rta, len)) {
368
436
                switch (rta->rta_type) {
369
437
                case IFLA_WIRELESS:
375
443
                case IFLA_IFNAME:
376
444
                        strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
377
445
                        break;
 
446
                case IFLA_ADDRESS:
 
447
                        hwaddr = rta;
 
448
                        break;
378
449
                }
379
450
                rta = RTA_NEXT(rta, len);
380
451
        }
393
464
                return 1;
394
465
        }
395
466
 
396
 
        handle_carrier(ifi->ifi_flags & IFF_RUNNING ? 1 : -1,
 
467
        /* Re-read hardware address and friends */
 
468
        if (!(ifi->ifi_flags & IFF_UP) && hwaddr) {
 
469
                len = l2addr_len(ifi->ifi_type);
 
470
                if (hwaddr->rta_len == RTA_LENGTH(len))
 
471
                        handle_hwaddr(ifn, RTA_DATA(hwaddr), len);
 
472
        }
 
473
 
 
474
        handle_carrier(ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
397
475
            ifi->ifi_flags, ifn);
398
476
        return 1;
399
477
}
478
556
struct nlma
479
557
{
480
558
        struct nlmsghdr hdr;
481
 
        struct ifaddrmsg ifa; 
 
559
        struct ifaddrmsg ifa;
482
560
        char buffer[64];
483
561
};
484
562
 
489
567
        char buffer[256];
490
568
};
491
569
 
 
570
#ifdef INET
492
571
int
493
572
if_address(const struct interface *iface,
494
573
    const struct in_addr *address, const struct in_addr *netmask,
497
576
        struct nlma *nlm;
498
577
        int retval = 0;
499
578
 
500
 
        nlm = xzalloc(sizeof(*nlm));
 
579
        nlm = calloc(1, sizeof(*nlm));
 
580
        if (nlm == NULL)
 
581
                return -1;
501
582
        nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
502
583
        nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
503
584
        if (action >= 0) {
505
586
                nlm->hdr.nlmsg_type = RTM_NEWADDR;
506
587
        } else
507
588
                nlm->hdr.nlmsg_type = RTM_DELADDR;
508
 
        if (!(nlm->ifa.ifa_index = if_nametoindex(iface->name))) {
509
 
                free(nlm);
510
 
                errno = ENODEV;
511
 
                return -1;
512
 
        }
 
589
        nlm->ifa.ifa_index = iface->index;
513
590
        nlm->ifa.ifa_family = AF_INET;
514
591
        nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask);
515
592
        /* This creates the aliased interface */
531
608
if_route(const struct rt *rt, int action)
532
609
{
533
610
        struct nlmr *nlm;
534
 
        unsigned int ifindex;
535
611
        int retval = 0;
 
612
        struct dhcp_state *state;
536
613
 
537
 
        if (!(ifindex = if_nametoindex(rt->iface->name))) {
538
 
                errno = ENODEV;
 
614
        nlm = calloc(1, sizeof(*nlm));
 
615
        if (nlm == NULL)
539
616
                return -1;
540
 
        }
541
 
 
542
 
        nlm = xzalloc(sizeof(*nlm));
543
617
        nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
544
618
        nlm->hdr.nlmsg_type = RTM_NEWROUTE;
545
619
        if (action == 0)
552
626
        nlm->rt.rtm_family = AF_INET;
553
627
        nlm->rt.rtm_table = RT_TABLE_MAIN;
554
628
 
 
629
        state = D_STATE(rt->iface);
555
630
        if (action == -1 || action == -2)
556
631
                nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
557
632
        else {
558
633
                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
559
634
                /* We only change route metrics for kernel routes */
560
635
                if (rt->dest.s_addr ==
561
 
                    (rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
562
 
                    rt->net.s_addr == rt->iface->net.s_addr)
 
636
                    (state->addr.s_addr & state->net.s_addr) &&
 
637
                    rt->net.s_addr == state->net.s_addr)
563
638
                        nlm->rt.rtm_protocol = RTPROT_KERNEL;
564
639
                else
565
640
                        nlm->rt.rtm_protocol = RTPROT_BOOT;
577
652
            &rt->dest.s_addr, sizeof(rt->dest.s_addr));
578
653
        if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
579
654
                add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
580
 
                    &rt->iface->addr.s_addr, sizeof(rt->iface->addr.s_addr));
 
655
                    &state->addr.s_addr, sizeof(state->addr.s_addr));
581
656
        }
582
657
        /* If destination == gateway then don't add the gateway */
583
658
        if (rt->dest.s_addr != rt->gate.s_addr ||
585
660
                add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
586
661
                    &rt->gate.s_addr, sizeof(rt->gate.s_addr));
587
662
 
588
 
        add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
589
 
        add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
590
 
 
591
 
        if (send_netlink(&nlm->hdr) == -1)
592
 
                retval = -1;
593
 
        free(nlm);
594
 
        return retval;
595
 
}
 
663
        if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
 
664
                add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index);
 
665
        add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
 
666
 
 
667
        if (send_netlink(&nlm->hdr) == -1)
 
668
                retval = -1;
 
669
        free(nlm);
 
670
        return retval;
 
671
}
 
672
#endif
 
673
 
 
674
#ifdef INET6
 
675
int
 
676
if_address6(const struct ipv6_addr *ap, int action)
 
677
{
 
678
        struct nlma *nlm;
 
679
        struct ifa_cacheinfo cinfo;
 
680
        int retval = 0;
 
681
 
 
682
        nlm = calloc(1, sizeof(*nlm));
 
683
        if (nlm == NULL)
 
684
                return -1;
 
685
        nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
 
686
        nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
 
687
        if (action >= 0) {
 
688
                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
 
689
                nlm->hdr.nlmsg_type = RTM_NEWADDR;
 
690
        } else
 
691
                nlm->hdr.nlmsg_type = RTM_DELADDR;
 
692
        nlm->ifa.ifa_index = ap->iface->index;
 
693
        nlm->ifa.ifa_family = AF_INET6;
 
694
        nlm->ifa.ifa_prefixlen = ap->prefix_len;
 
695
        /* This creates the aliased interface */
 
696
        add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
 
697
            ap->iface->name, strlen(ap->iface->name) + 1);
 
698
        add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
 
699
            &ap->addr.s6_addr, sizeof(ap->addr.s6_addr));
 
700
 
 
701
        if (action >= 0) {
 
702
                memset(&cinfo, 0, sizeof(cinfo));
 
703
                cinfo.ifa_prefered = ap->prefix_pltime;
 
704
                cinfo.ifa_valid = ap->prefix_vltime;
 
705
                add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_CACHEINFO,
 
706
                    &cinfo, sizeof(cinfo));
 
707
        }
 
708
 
 
709
        if (send_netlink(&nlm->hdr) == -1)
 
710
                retval = -1;
 
711
        free(nlm);
 
712
        return retval;
 
713
}
 
714
 
 
715
static int
 
716
rta_add_attr_32(struct rtattr *rta, unsigned int maxlen,
 
717
    int type, uint32_t data)
 
718
{
 
719
        unsigned int len = RTA_LENGTH(sizeof(data));
 
720
        struct rtattr *subrta;
 
721
 
 
722
        if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
 
723
                errno = ENOBUFS;
 
724
                return -1;
 
725
        }
 
726
 
 
727
        subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
 
728
        subrta->rta_type = type;
 
729
        subrta->rta_len = len;
 
730
        memcpy(RTA_DATA(subrta), &data, sizeof(data));
 
731
        rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
 
732
        return 0;
 
733
}
 
734
 
 
735
int
 
736
if_route6(const struct rt6 *rt, int action)
 
737
{
 
738
        struct nlmr *nlm;
 
739
        char metricsbuf[32];
 
740
        struct rtattr *metrics = (void *)metricsbuf;
 
741
        int retval = 0;
 
742
 
 
743
        nlm = calloc(1, sizeof(*nlm));
 
744
        if (nlm == NULL)
 
745
                return -1;
 
746
        nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
 
747
        nlm->hdr.nlmsg_type = RTM_NEWROUTE;
 
748
        nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
 
749
        if (action == 0)
 
750
                nlm->hdr.nlmsg_flags |= NLM_F_REPLACE;
 
751
        else if (action == 1)
 
752
                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
 
753
        else
 
754
                nlm->hdr.nlmsg_type = RTM_DELROUTE;
 
755
        nlm->rt.rtm_family = AF_INET6;
 
756
        nlm->rt.rtm_table = RT_TABLE_MAIN;
 
757
 
 
758
        if (action == -1 || action == -2)
 
759
                nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
 
760
        else {
 
761
                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
 
762
                /* None interface subnet routes are static. */
 
763
                if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
 
764
                        nlm->rt.rtm_protocol = RTPROT_KERNEL;
 
765
                        nlm->rt.rtm_scope = RT_SCOPE_LINK;
 
766
                } else
 
767
                        nlm->rt.rtm_protocol = RTPROT_BOOT;
 
768
                nlm->rt.rtm_type = RTN_UNICAST;
 
769
        }
 
770
 
 
771
        nlm->rt.rtm_dst_len = ipv6_prefixlen(&rt->net);
 
772
        add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
 
773
            &rt->dest.s6_addr, sizeof(rt->dest.s6_addr));
 
774
 
 
775
        /* If destination == gateway then don't add the gateway */
 
776
        if (!IN6_IS_ADDR_UNSPECIFIED(&rt->gate) &&
 
777
            !IN6_ARE_ADDR_EQUAL(&rt->dest, &rt->gate))
 
778
                add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
 
779
                    &rt->gate.s6_addr, sizeof(rt->gate.s6_addr));
 
780
 
 
781
        add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index);
 
782
        add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
 
783
 
 
784
        if (rt->mtu) {
 
785
                metrics->rta_type = RTA_METRICS;
 
786
                metrics->rta_len = RTA_LENGTH(0);
 
787
                rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu);
 
788
                add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_METRICS,
 
789
                    RTA_DATA(metrics), RTA_PAYLOAD(metrics));
 
790
        }
 
791
 
 
792
        if (send_netlink(&nlm->hdr) == -1)
 
793
                retval = -1;
 
794
        free(nlm);
 
795
        return retval;
 
796
        errno = ENOTSUP;
 
797
        return -1;
 
798
}
 
799
 
 
800
int
 
801
in6_addr_flags(__unused const char *ifname,
 
802
    __unused const struct in6_addr *addr)
 
803
{
 
804
 
 
805
        /* How do I get IPv6 address flags on Linux? */
 
806
        return 0;
 
807
}
 
808
#endif