2 * Copyright (C) 2012 Steven Barth <steven@midlink.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License v2 as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
21 #include <arpa/inet.h>
22 #include <sys/socket.h>
23 #include <linux/rtnetlink.h>
29 static unsigned seq
= 0;
32 // Init rtnetlink socket
33 int init_rtnetlink(void)
35 sock
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, NETLINK_ROUTE
);
36 struct sockaddr_nl rtnl_kernel
= { .nl_family
= AF_NETLINK
};
37 if (connect(sock
, (struct sockaddr
*)&rtnl_kernel
, sizeof(rtnl_kernel
)))
44 // CRUD addresses to interface
45 int set_rtnetlink_addr(int ifindex
, const struct in6_addr
*addr
,
46 time_t pref
, time_t valid
)
48 int flags
= NLM_F_REQUEST
| NLM_F_ACK
;
49 int cmd
= RTM_DELADDR
;
52 flags
|= NLM_F_CREATE
| NLM_F_REPLACE
;
59 struct rtattr rta_addr
;
61 struct rtattr rta_local
;
62 struct in6_addr local
;
63 struct rtattr rta_info
;
64 struct ifa_cacheinfo info
;
66 {sizeof(req
), cmd
, flags
, ++seq
, 0},
67 {AF_INET6
, 128, 0, RT_SCOPE_UNIVERSE
, ifindex
},
68 {sizeof(req
.rta_addr
) + sizeof(req
.addr
), IFA_ADDRESS
},
70 {sizeof(req
.rta_local
) + sizeof(req
.local
), IFA_LOCAL
},
72 {sizeof(req
.rta_info
) + sizeof(req
.info
), IFA_CACHEINFO
},
75 send(sock
, &req
, sizeof(req
), 0);
81 recv(sock
, &reply
, sizeof(reply
), 0);
83 char buf
[INET6_ADDRSTRLEN
];
84 inet_ntop(AF_INET6
, addr
, buf
, sizeof(buf
));
85 syslog(LOG_WARNING
, "%s address %s/128 for iface %i: %s",
86 (valid
) ? "assigning" : "removing", buf
,
87 ifindex
, strerror(-reply
.err
.error
));
89 if (reply
.err
.error
< 0 || valid
== 0)
90 return reply
.err
.error
;
92 // Check for duplicate addresses
93 struct timespec ts
= {1, 0};
96 req
.nhm
.nlmsg_type
= RTM_GETADDR
;
97 req
.nhm
.nlmsg_seq
= ++seq
;
98 req
.nhm
.nlmsg_flags
= NLM_F_REQUEST
;
99 send(sock
, &req
, sizeof(req
), 0);
103 struct ifaddrmsg ifa
;
106 recv(sock
, &dad_reply
, sizeof(dad_reply
), 0);
108 if (dad_reply
.nhm
.nlmsg_type
!= RTM_NEWADDR
||
109 (dad_reply
.ifa
.ifa_flags
& IFA_F_DADFAILED
)) {
110 syslog(LOG_WARNING
, "Removing duplicate address %s", buf
);
111 set_rtnetlink_addr(ifindex
, addr
, 0, 0);
112 return -EADDRNOTAVAIL
;