source: rtems-libbsd/dhcpcd/if-linux.c @ 91b858d

55-freebsd-126-freebsd-12
Last change on this file since 91b858d 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: 20.6 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 <asm/types.h> /* Needed for 2.4 kernels */
29
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/ioctl.h>
33#include <sys/param.h>
34
35#include <linux/netlink.h>
36#include <linux/rtnetlink.h>
37
38/* Support older kernels */
39#ifndef IFLA_WIRELESS
40# define IFLA_WIRELESS (IFLA_MASTER + 1)
41#endif
42
43/* For some reason, glibc doesn't include newer flags from linux/if.h
44 * However, we cannot include linux/if.h directly as it conflicts
45 * with the glibc version. D'oh! */
46#ifndef IFF_LOWER_UP
47#define IFF_LOWER_UP    0x10000         /* driver signals L1 up         */
48#endif
49
50#include <errno.h>
51#include <ctype.h>
52#include <stddef.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58#include "config.h"
59#include "common.h"
60#include "dev.h"
61#include "dhcp.h"
62#include "ipv4.h"
63#include "ipv6.h"
64#include "net.h"
65
66static int sock_fd;
67static struct sockaddr_nl sock_nl;
68
69int
70if_init(struct interface *iface)
71{
72        char path[PATH_MAX];
73        FILE *fp;
74        int n;
75
76        /* We enable promote_secondaries so that we can do this
77         * add 192.168.1.2/24
78         * add 192.168.1.3/24
79         * del 192.168.1.2/24
80         * and the subnet mask moves onto 192.168.1.3/24
81         * This matches the behaviour of BSD which makes coding dhcpcd
82         * a little easier as there's just one behaviour. */
83        snprintf(path, sizeof(path),
84            "/proc/sys/net/ipv4/conf/%s/promote_secondaries",
85            iface->name);
86
87        fp = fopen(path, "w");
88        if (fp == NULL)
89                return errno == ENOENT ? 0 : -1;
90        n = fprintf(fp, "1");
91        fclose(fp);
92        return n == -1 ? -1 : 0;
93}
94
95int
96if_conf(struct interface *iface)
97{
98        char path[PATH_MAX], buf[1];
99        FILE *fp;
100
101        /* Some qeth setups require the use of the broadcast flag. */
102        snprintf(path, sizeof(path),
103            "/sys/class/net/%s/device/layer2",
104            iface->name);
105
106        fp = fopen(path, "r");
107        if (fp == NULL)
108                return errno == ENOENT ? 0 : -1;
109        if (fgets(buf, sizeof(buf), fp) != NULL && buf[0] == '0')
110                iface->options->options |= DHCPCD_BROADCAST;
111        fclose(fp);
112        return 0;
113}
114
115/* XXX work out Virtal Interface Masters */
116int
117if_vimaster(__unused const char *ifname)
118{
119
120        return 0;
121}
122
123static int
124_open_link_socket(struct sockaddr_nl *nl)
125{
126        int fd;
127
128        if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
129                return -1;
130        nl->nl_family = AF_NETLINK;
131        if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1)
132                return -1;
133        set_cloexec(fd);
134
135        return fd;
136}
137
138int
139open_sockets(void)
140{
141        if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
142                return -1;
143        set_cloexec(socket_afnet);
144        sock_fd = _open_link_socket(&sock_nl);
145        set_cloexec(sock_fd);
146        return sock_fd;
147}
148
149int
150open_link_socket(void)
151{
152        struct sockaddr_nl snl;
153
154        memset(&snl, 0, sizeof(snl));
155        snl.nl_groups = RTMGRP_LINK;
156
157#ifdef INET
158        snl.nl_groups |= RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
159#endif
160#ifdef INET6
161        snl.nl_groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
162#endif
163
164        return _open_link_socket(&snl);
165}
166
167static int
168get_netlink(int fd, int flags,
169    int (*callback)(struct nlmsghdr *))
170{
171        char *buf = NULL, *nbuf;
172        ssize_t buflen = 0, bytes;
173        struct nlmsghdr *nlm;
174        struct sockaddr_nl nladdr;
175        socklen_t nladdr_len = sizeof(nladdr);
176        int r = -1;
177
178        for (;;) {
179                bytes = recv(fd, NULL, 0,
180                    flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
181                if (bytes == -1) {
182                        if (errno == EAGAIN) {
183                                r = 0;
184                                goto eexit;
185                        }
186                        if (errno == EINTR)
187                                continue;
188                        goto eexit;
189                } else if (bytes == buflen) {
190                        /* Support kernels older than 2.6.22 */
191                        if (bytes == 0)
192                                bytes = 512;
193                        else
194                                bytes *= 2;
195                }
196                if (buflen < bytes) {
197                        /* Alloc 1 more so we work with older kernels */
198                        buflen = bytes + 1;
199                        nbuf = realloc(buf, buflen);
200                        if (nbuf == NULL)
201                                goto eexit;
202                        buf = nbuf;
203                }
204                bytes = recvfrom(fd, buf, buflen, flags,
205                    (struct sockaddr *)&nladdr, &nladdr_len);
206                if (bytes == -1) {
207                        if (errno == EAGAIN) {
208                                r = 0;
209                                goto eexit;
210                        }
211                        if (errno == EINTR)
212                                continue;
213                        goto eexit;
214                }
215
216                /* Check sender */
217                if (nladdr_len != sizeof(nladdr)) {
218                        errno = EINVAL;
219                        goto eexit;
220                }
221                /* Ignore message if it is not from kernel */
222                if (nladdr.nl_pid != 0)
223                        continue;
224
225                for (nlm = (struct nlmsghdr *)(void *)buf;
226                     NLMSG_OK(nlm, (size_t)bytes);
227                     nlm = NLMSG_NEXT(nlm, bytes))
228                {
229                        r = callback(nlm);
230                        if (r != 0)
231                                goto eexit;
232                }
233        }
234
235eexit:
236        free(buf);
237        return r;
238}
239
240static int
241err_netlink(struct nlmsghdr *nlm)
242{
243        struct nlmsgerr *err;
244        int l;
245
246        if (nlm->nlmsg_type != NLMSG_ERROR)
247                return 0;
248        l = nlm->nlmsg_len - sizeof(*nlm);
249        if ((size_t)l < sizeof(*err)) {
250                errno = EBADMSG;
251                return -1;
252        }
253        err = (struct nlmsgerr *)NLMSG_DATA(nlm);
254        if (err->error == 0)
255                return l;
256        errno = -err->error;
257        return -1;
258}
259
260static int
261link_route(struct nlmsghdr *nlm)
262{
263        int len, idx, metric;
264        struct rtattr *rta;
265        struct rtmsg *rtm;
266        struct rt rt;
267        char ifn[IF_NAMESIZE + 1];
268
269        if (nlm->nlmsg_type != RTM_DELROUTE)
270                return 0;
271
272        len = nlm->nlmsg_len - sizeof(*nlm);
273        if ((size_t)len < sizeof(*rtm)) {
274                errno = EBADMSG;
275                return -1;
276        }
277        rtm = NLMSG_DATA(nlm);
278        if (rtm->rtm_type != RTN_UNICAST ||
279            rtm->rtm_table != RT_TABLE_MAIN ||
280            rtm->rtm_family != AF_INET ||
281            nlm->nlmsg_pid == (uint32_t)getpid())
282                return 1;
283        rta = (struct rtattr *)(void *)((char *)rtm +NLMSG_ALIGN(sizeof(*rtm)));
284        len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
285        memset(&rt, 0, sizeof(rt));
286        rt.dest.s_addr = INADDR_ANY;
287        rt.net.s_addr = INADDR_ANY;
288        rt.gate.s_addr = INADDR_ANY;
289        metric = 0;
290        while (RTA_OK(rta, len)) {
291                switch (rta->rta_type) {
292                case RTA_DST:
293                        memcpy(&rt.dest.s_addr, RTA_DATA(rta),
294                            sizeof(rt.dest.s_addr));
295                        break;
296                case RTA_GATEWAY:
297                        memcpy(&rt.gate.s_addr, RTA_DATA(rta),
298                            sizeof(rt.gate.s_addr));
299                        break;
300                case RTA_OIF:
301                        idx = *(int *)RTA_DATA(rta);
302                        if (if_indextoname(idx, ifn))
303                                rt.iface = find_interface(ifn);
304                        break;
305                case RTA_PRIORITY:
306                        metric = *(int *)RTA_DATA(rta);
307                        break;
308                }
309                rta = RTA_NEXT(rta, len);
310        }
311        if (rt.iface != NULL) {
312                if (metric == rt.iface->metric) {
313#ifdef INET
314                        inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
315                        ipv4_routedeleted(&rt);
316#endif
317                }
318        }
319        return 1;
320}
321
322static int
323link_addr(struct nlmsghdr *nlm)
324{
325        int len;
326        struct rtattr *rta;
327        struct ifaddrmsg *ifa;
328        char ifn[IF_NAMESIZE + 1];
329        struct interface *iface;
330#ifdef INET
331        struct in_addr addr, net, dest;
332#endif
333#ifdef INET6
334        struct in6_addr addr6;
335#endif
336
337        if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
338                return 0;
339
340        len = nlm->nlmsg_len - sizeof(*nlm);
341        if ((size_t)len < sizeof(*ifa)) {
342                errno = EBADMSG;
343                return -1;
344        }
345//      if (nlm->nlmsg_pid == (uint32_t)getpid())
346//              return 1;
347        ifa = NLMSG_DATA(nlm);
348        if (if_indextoname(ifa->ifa_index, ifn) == NULL)
349                return -1;
350        iface = find_interface(ifn);
351        if (iface == NULL)
352                return 1;
353        rta = (struct rtattr *) IFA_RTA(ifa);
354        len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
355        switch (ifa->ifa_family) {
356#ifdef INET
357        case AF_INET:
358                addr.s_addr = dest.s_addr = INADDR_ANY;
359                dest.s_addr = INADDR_ANY;
360                inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
361                while (RTA_OK(rta, len)) {
362                        switch (rta->rta_type) {
363                        case IFA_ADDRESS:
364                                if (iface->flags & IFF_POINTOPOINT) {
365                                        memcpy(&dest.s_addr, RTA_DATA(rta),
366                                               sizeof(addr.s_addr));
367                                }
368                                break;
369                        case IFA_LOCAL:
370                                memcpy(&addr.s_addr, RTA_DATA(rta),
371                                       sizeof(addr.s_addr));
372                                break;
373                        }
374                        rta = RTA_NEXT(rta, len);
375                }
376                ipv4_handleifa(nlm->nlmsg_type, NULL, ifn, &addr, &net, &dest);
377                break;
378#endif
379#ifdef INET6
380        case AF_INET6:
381                memset(&addr6, 0, sizeof(addr6));
382                while (RTA_OK(rta, len)) {
383                        switch (rta->rta_type) {
384                        case IFA_ADDRESS:
385                                memcpy(&addr6.s6_addr, RTA_DATA(rta),
386                                       sizeof(addr6.s6_addr));
387                                break;
388                        }
389                        rta = RTA_NEXT(rta, len);
390                }
391                ipv6_handleifa(nlm->nlmsg_type, NULL, ifn,
392                    &addr6, ifa->ifa_flags);
393                break;
394#endif
395        }
396        return 1;
397}
398
399static short l2addr_len(unsigned short if_type)
400{
401
402        switch (if_type) {
403        case ARPHRD_ETHER: /* FALLTHROUGH */
404        case ARPHRD_IEEE802: /*FALLTHROUGH */
405        case ARPHRD_IEEE80211:
406                return 6;
407        case ARPHRD_IEEE1394:
408                return 8;
409        case ARPHRD_INFINIBAND:
410                return 20;
411        default:
412                return -1;
413        }
414}
415
416static int
417handle_rename(unsigned int ifindex, const char *ifname)
418{
419        struct interface *ifp;
420
421        TAILQ_FOREACH(ifp, ifaces, next) {
422                if (ifp->index == ifindex && strcmp(ifp->name, ifname)) {
423                        handle_interface(-1, ifp->name);
424                        /* Let dev announce the interface for renaming */
425                        if (!dev_listening())
426                                handle_interface(1, ifname);
427                        return 1;
428                }
429        }
430        return 0;
431}
432
433static int
434link_netlink(struct nlmsghdr *nlm)
435{
436        int len;
437        struct rtattr *rta, *hwaddr;
438        struct ifinfomsg *ifi;
439        char ifn[IF_NAMESIZE + 1];
440        struct interface *ifp;
441
442        len = link_route(nlm);
443        if (len != 0)
444                return len;
445        len = link_addr(nlm);
446        if (len != 0)
447                return len;
448
449        if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
450                return 0;
451        len = nlm->nlmsg_len - sizeof(*nlm);
452        if ((size_t)len < sizeof(*ifi)) {
453                errno = EBADMSG;
454                return -1;
455        }
456        ifi = NLMSG_DATA(nlm);
457        if (ifi->ifi_flags & IFF_LOOPBACK)
458                return 1;
459        rta = (struct rtattr *)(void *)((char *)ifi +NLMSG_ALIGN(sizeof(*ifi)));
460        len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
461        *ifn = '\0';
462        hwaddr = NULL;
463
464        while (RTA_OK(rta, len)) {
465                switch (rta->rta_type) {
466                case IFLA_WIRELESS:
467                        /* Ignore wireless messages */
468                        if (nlm->nlmsg_type == RTM_NEWLINK &&
469                            ifi->ifi_change == 0)
470                                return 1;
471                        break;
472                case IFLA_IFNAME:
473                        strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
474                        break;
475                case IFLA_ADDRESS:
476                        hwaddr = rta;
477                        break;
478                }
479                rta = RTA_NEXT(rta, len);
480        }
481
482        if (nlm->nlmsg_type == RTM_DELLINK) {
483                handle_interface(-1, ifn);
484                return 1;
485        }
486
487        /* Virtual interfaces may not get a valid hardware address
488         * at this point.
489         * To trigger a valid hardware address pickup we need to pretend
490         * that that don't exist until they have one. */
491        if (ifi->ifi_flags & IFF_MASTER && !hwaddr) {
492                handle_interface(-1, ifn);
493                return 1;
494        }
495
496        /* Check for interface name change */
497        if (handle_rename(ifi->ifi_index, ifn))
498                    return 1;
499
500        /* Check for a new interface */
501        ifp = find_interface(ifn);
502        if (ifp == NULL) {
503                /* If are listening to a dev manager, let that announce
504                 * the interface rather than the kernel. */
505                if (dev_listening() < 1)
506                        handle_interface(1, ifn);
507                return 1;
508        }
509
510        /* Re-read hardware address and friends */
511        if (!(ifi->ifi_flags & IFF_UP) && hwaddr) {
512                len = l2addr_len(ifi->ifi_type);
513                if (hwaddr->rta_len == RTA_LENGTH(len))
514                        handle_hwaddr(ifn, RTA_DATA(hwaddr), len);
515        }
516
517        handle_carrier(ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
518            ifi->ifi_flags, ifn);
519        return 1;
520}
521
522int
523manage_link(int fd)
524{
525        return get_netlink(fd, MSG_DONTWAIT, &link_netlink);
526}
527
528static int
529send_netlink(struct nlmsghdr *hdr)
530{
531        int r;
532        struct iovec iov;
533        struct msghdr msg;
534        static unsigned int seq;
535
536        memset(&iov, 0, sizeof(iov));
537        iov.iov_base = hdr;
538        iov.iov_len = hdr->nlmsg_len;
539        memset(&msg, 0, sizeof(msg));
540        msg.msg_name = &sock_nl;
541        msg.msg_namelen = sizeof(sock_nl);
542        msg.msg_iov = &iov;
543        msg.msg_iovlen = 1;
544        /* Request a reply */
545        hdr->nlmsg_flags |= NLM_F_ACK;
546        hdr->nlmsg_seq = ++seq;
547
548        if (sendmsg(sock_fd, &msg, 0) != -1)
549                r = get_netlink(sock_fd, 0, &err_netlink);
550        else
551                r = -1;
552        return r;
553}
554
555#define NLMSG_TAIL(nmsg)                                                \
556        ((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len)))
557
558static int
559add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
560    const void *data, int alen)
561{
562        int len = RTA_LENGTH(alen);
563        struct rtattr *rta;
564
565        if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
566                errno = ENOBUFS;
567                return -1;
568        }
569
570        rta = NLMSG_TAIL(n);
571        rta->rta_type = type;
572        rta->rta_len = len;
573        memcpy(RTA_DATA(rta), data, alen);
574        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
575
576        return 0;
577}
578
579static int
580add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, uint32_t data)
581{
582        int len = RTA_LENGTH(sizeof(data));
583        struct rtattr *rta;
584
585        if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
586                errno = ENOBUFS;
587                return -1;
588        }
589
590        rta = NLMSG_TAIL(n);
591        rta->rta_type = type;
592        rta->rta_len = len;
593        memcpy(RTA_DATA(rta), &data, sizeof(data));
594        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
595
596        return 0;
597}
598
599struct nlma
600{
601        struct nlmsghdr hdr;
602        struct ifaddrmsg ifa;
603        char buffer[64];
604};
605
606struct nlmr
607{
608        struct nlmsghdr hdr;
609        struct rtmsg rt;
610        char buffer[256];
611};
612
613#ifdef INET
614int
615if_address(const struct interface *iface,
616    const struct in_addr *address, const struct in_addr *netmask,
617    const struct in_addr *broadcast, int action)
618{
619        struct nlma *nlm;
620        int retval = 0;
621
622        nlm = calloc(1, sizeof(*nlm));
623        if (nlm == NULL)
624                return -1;
625        nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
626        nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
627        if (action >= 0) {
628                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
629                nlm->hdr.nlmsg_type = RTM_NEWADDR;
630        } else
631                nlm->hdr.nlmsg_type = RTM_DELADDR;
632        nlm->ifa.ifa_index = iface->index;
633        nlm->ifa.ifa_family = AF_INET;
634        nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask);
635        /* This creates the aliased interface */
636        add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
637            iface->name, strlen(iface->name) + 1);
638        add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
639            &address->s_addr, sizeof(address->s_addr));
640        if (action >= 0 && broadcast)
641                add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST,
642                    &broadcast->s_addr, sizeof(broadcast->s_addr));
643
644        if (send_netlink(&nlm->hdr) == -1)
645                retval = -1;
646        free(nlm);
647        return retval;
648}
649
650int
651if_route(const struct rt *rt, int action)
652{
653        struct nlmr *nlm;
654        int retval = 0;
655        struct dhcp_state *state;
656
657        nlm = calloc(1, sizeof(*nlm));
658        if (nlm == NULL)
659                return -1;
660        nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
661        nlm->hdr.nlmsg_type = RTM_NEWROUTE;
662        if (action == 0)
663                nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
664        else if (action == 1)
665                nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
666        else
667                nlm->hdr.nlmsg_type = RTM_DELROUTE;
668        nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
669        nlm->rt.rtm_family = AF_INET;
670        nlm->rt.rtm_table = RT_TABLE_MAIN;
671
672        state = D_STATE(rt->iface);
673        if (action == -1 || action == -2)
674                nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
675        else {
676                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
677                /* We only change route metrics for kernel routes */
678                if (rt->dest.s_addr ==
679                    (state->addr.s_addr & state->net.s_addr) &&
680                    rt->net.s_addr == state->net.s_addr)
681                        nlm->rt.rtm_protocol = RTPROT_KERNEL;
682                else
683                        nlm->rt.rtm_protocol = RTPROT_BOOT;
684                if (rt->gate.s_addr == INADDR_ANY ||
685                    (rt->gate.s_addr == rt->dest.s_addr &&
686                        rt->net.s_addr == INADDR_BROADCAST))
687                        nlm->rt.rtm_scope = RT_SCOPE_LINK;
688                else
689                        nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
690                nlm->rt.rtm_type = RTN_UNICAST;
691        }
692
693        nlm->rt.rtm_dst_len = inet_ntocidr(rt->net);
694        add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
695            &rt->dest.s_addr, sizeof(rt->dest.s_addr));
696        if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
697                add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
698                    &state->addr.s_addr, sizeof(state->addr.s_addr));
699        }
700        /* If destination == gateway then don't add the gateway */
701        if (rt->dest.s_addr != rt->gate.s_addr ||
702            rt->net.s_addr != INADDR_BROADCAST)
703                add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
704                    &rt->gate.s_addr, sizeof(rt->gate.s_addr));
705
706        if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
707                add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index);
708        add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
709
710        if (send_netlink(&nlm->hdr) == -1)
711                retval = -1;
712        free(nlm);
713        return retval;
714}
715#endif
716
717#ifdef INET6
718int
719if_address6(const struct ipv6_addr *ap, int action)
720{
721        struct nlma *nlm;
722        struct ifa_cacheinfo cinfo;
723        int retval = 0;
724
725        nlm = calloc(1, sizeof(*nlm));
726        if (nlm == NULL)
727                return -1;
728        nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
729        nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
730        if (action >= 0) {
731                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
732                nlm->hdr.nlmsg_type = RTM_NEWADDR;
733        } else
734                nlm->hdr.nlmsg_type = RTM_DELADDR;
735        nlm->ifa.ifa_index = ap->iface->index;
736        nlm->ifa.ifa_family = AF_INET6;
737        nlm->ifa.ifa_prefixlen = ap->prefix_len;
738        /* This creates the aliased interface */
739        add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
740            ap->iface->name, strlen(ap->iface->name) + 1);
741        add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
742            &ap->addr.s6_addr, sizeof(ap->addr.s6_addr));
743
744        if (action >= 0) {
745                memset(&cinfo, 0, sizeof(cinfo));
746                cinfo.ifa_prefered = ap->prefix_pltime;
747                cinfo.ifa_valid = ap->prefix_vltime;
748                add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_CACHEINFO,
749                    &cinfo, sizeof(cinfo));
750        }
751
752        if (send_netlink(&nlm->hdr) == -1)
753                retval = -1;
754        free(nlm);
755        return retval;
756}
757
758static int
759rta_add_attr_32(struct rtattr *rta, unsigned int maxlen,
760    int type, uint32_t data)
761{
762        unsigned int len = RTA_LENGTH(sizeof(data));
763        struct rtattr *subrta;
764
765        if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
766                errno = ENOBUFS;
767                return -1;
768        }
769
770        subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
771        subrta->rta_type = type;
772        subrta->rta_len = len;
773        memcpy(RTA_DATA(subrta), &data, sizeof(data));
774        rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
775        return 0;
776}
777
778int
779if_route6(const struct rt6 *rt, int action)
780{
781        struct nlmr *nlm;
782        char metricsbuf[32];
783        struct rtattr *metrics = (void *)metricsbuf;
784        int retval = 0;
785
786        nlm = calloc(1, sizeof(*nlm));
787        if (nlm == NULL)
788                return -1;
789        nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
790        nlm->hdr.nlmsg_type = RTM_NEWROUTE;
791        nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
792        if (action == 0)
793                nlm->hdr.nlmsg_flags |= NLM_F_REPLACE;
794        else if (action == 1)
795                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
796        else
797                nlm->hdr.nlmsg_type = RTM_DELROUTE;
798        nlm->rt.rtm_family = AF_INET6;
799        nlm->rt.rtm_table = RT_TABLE_MAIN;
800
801        if (action == -1 || action == -2)
802                nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
803        else {
804                nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
805                /* None interface subnet routes are static. */
806                if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
807                        nlm->rt.rtm_protocol = RTPROT_KERNEL;
808                        nlm->rt.rtm_scope = RT_SCOPE_LINK;
809                } else
810                        nlm->rt.rtm_protocol = RTPROT_BOOT;
811                nlm->rt.rtm_type = RTN_UNICAST;
812        }
813
814        nlm->rt.rtm_dst_len = ipv6_prefixlen(&rt->net);
815        add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
816            &rt->dest.s6_addr, sizeof(rt->dest.s6_addr));
817
818        /* If destination == gateway then don't add the gateway */
819        if (!IN6_IS_ADDR_UNSPECIFIED(&rt->gate) &&
820            !IN6_ARE_ADDR_EQUAL(&rt->dest, &rt->gate))
821                add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
822                    &rt->gate.s6_addr, sizeof(rt->gate.s6_addr));
823
824        add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index);
825        add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
826
827        if (rt->mtu) {
828                metrics->rta_type = RTA_METRICS;
829                metrics->rta_len = RTA_LENGTH(0);
830                rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu);
831                add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_METRICS,
832                    RTA_DATA(metrics), RTA_PAYLOAD(metrics));
833        }
834
835        if (send_netlink(&nlm->hdr) == -1)
836                retval = -1;
837        free(nlm);
838        return retval;
839        errno = ENOTSUP;
840        return -1;
841}
842
843int
844in6_addr_flags(const char *ifname, const struct in6_addr *addr)
845{
846        FILE *fp;
847        char *p, ifaddress[33], address[33], name[IF_NAMESIZE + 1];
848        unsigned int ifindex;
849        int prefix, scope, flags, i;
850
851        fp = fopen("/proc/net/if_inet6", "r");
852        if (fp == NULL)
853                return -1;
854
855        p = ifaddress;
856        for (i = 0; i < (int)sizeof(addr->s6_addr); i++) {
857                p += snprintf(p, 3, "%.2x", addr->s6_addr[i]);
858        }
859        *p = '\0';
860
861        while ((p = get_line(fp))) {
862                i = sscanf(p, "%32[a-f0-9] %x %x %x %x"
863                    " %"TOSTRING(IF_NAMESIZE)"s\n",
864                    address, &ifindex, &prefix, &scope, &flags, name);
865                if (i != 6 || strlen(address) != 32) {
866                        fclose(fp);
867                        errno = ENOTSUP;
868                        return -1;
869                }
870                if (strcmp(ifname, name) == 0 &&
871                    strcmp(ifaddress, address) == 0)
872                {
873                        fclose(fp);
874                        return flags;
875                }
876        }
877
878        fclose(fp);
879        errno = ESRCH;
880        return -1;
881}
882#endif
Note: See TracBrowser for help on using the repository browser.