2 * Samba Unix/Linux SMB client library
3 * Copyright (C) Volker Lendecke 2011
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "lib/addrchange.h"
21 #include "../lib/util/tevent_ntstatus.h"
23 #if HAVE_LINUX_RTNETLINK_H
25 #include "asm/types.h"
26 #include "linux/netlink.h"
27 #include "linux/rtnetlink.h"
28 #include "lib/async_req/async_sock.h"
30 struct addrchange_context
{
34 static int addrchange_context_destructor(struct addrchange_context
*c
);
36 NTSTATUS
addrchange_context_create(TALLOC_CTX
*mem_ctx
,
37 struct addrchange_context
**pctx
)
39 struct addrchange_context
*ctx
;
40 struct sockaddr_nl addr
;
44 ctx
= talloc(mem_ctx
, struct addrchange_context
);
46 return NT_STATUS_NO_MEMORY
;
49 ctx
->sock
= socket(AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
50 if (ctx
->sock
== -1) {
51 status
= map_nt_error_from_unix(errno
);
54 talloc_set_destructor(ctx
, addrchange_context_destructor
);
57 * We're interested in address changes
60 addr
.nl_family
= AF_NETLINK
;
61 addr
.nl_groups
= RTMGRP_IPV6_IFADDR
| RTMGRP_IPV4_IFADDR
;
63 res
= bind(ctx
->sock
, (struct sockaddr
*)(void *)&addr
, sizeof(addr
));
65 status
= map_nt_error_from_unix(errno
);
76 static int addrchange_context_destructor(struct addrchange_context
*c
)
85 struct addrchange_state
{
86 struct tevent_context
*ev
;
87 struct addrchange_context
*ctx
;
89 struct sockaddr_storage fromaddr
;
90 socklen_t fromaddr_len
;
92 enum addrchange_type type
;
93 struct sockaddr_storage addr
;
96 static void addrchange_done(struct tevent_req
*subreq
);
98 struct tevent_req
*addrchange_send(TALLOC_CTX
*mem_ctx
,
99 struct tevent_context
*ev
,
100 struct addrchange_context
*ctx
)
102 struct tevent_req
*req
, *subreq
;
103 struct addrchange_state
*state
;
105 req
= tevent_req_create(mem_ctx
, &state
, struct addrchange_state
);
112 state
->fromaddr_len
= sizeof(state
->fromaddr
);
113 subreq
= recvfrom_send(state
, state
->ev
, state
->ctx
->sock
,
114 state
->buf
, sizeof(state
->buf
), 0,
115 &state
->fromaddr
, &state
->fromaddr_len
);
116 if (tevent_req_nomem(subreq
, req
)) {
117 return tevent_req_post(req
, state
->ev
);
119 tevent_req_set_callback(subreq
, addrchange_done
, req
);
123 static void addrchange_done(struct tevent_req
*subreq
)
125 struct tevent_req
*req
= tevent_req_callback_data(
126 subreq
, struct tevent_req
);
127 struct addrchange_state
*state
= tevent_req_data(
128 req
, struct addrchange_state
);
129 struct sockaddr_nl
*addr
;
131 struct ifaddrmsg
*ifa
;
138 received
= recvfrom_recv(subreq
, &err
);
140 if (received
== -1) {
141 DEBUG(10, ("recvfrom returned %s\n", strerror(errno
)));
142 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
145 if ((state
->fromaddr_len
!= sizeof(struct sockaddr_nl
))
146 || (state
->fromaddr
.ss_family
!= AF_NETLINK
)) {
147 DEBUG(10, ("Got message from wrong addr\n"));
151 addr
= (struct sockaddr_nl
*)(void *)&state
->addr
;
152 if (addr
->nl_pid
!= 0) {
153 DEBUG(10, ("Got msg from pid %d, not from the kernel\n",
158 if (received
< sizeof(struct nlmsghdr
)) {
159 DEBUG(10, ("received %d, expected at least %d\n",
160 (int)received
, (int)sizeof(struct nlmsghdr
)));
164 h
= (struct nlmsghdr
*)state
->buf
;
165 if (h
->nlmsg_len
< sizeof(struct nlmsghdr
)) {
166 DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
167 (int)h
->nlmsg_len
, (int)sizeof(struct nlmsghdr
)));
170 if (h
->nlmsg_len
> received
) {
171 DEBUG(10, ("nlmsg_len=%d, expected at most %d\n",
172 (int)h
->nlmsg_len
, (int)received
));
175 switch (h
->nlmsg_type
) {
177 state
->type
= ADDRCHANGE_ADD
;
180 state
->type
= ADDRCHANGE_DEL
;
183 DEBUG(10, ("Got unexpected type %d - ignoring\n", h
->nlmsg_type
));
187 if (h
->nlmsg_len
< sizeof(struct nlmsghdr
)+sizeof(struct ifaddrmsg
)) {
188 DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
190 (int)(sizeof(struct nlmsghdr
)
191 +sizeof(struct ifaddrmsg
))));
192 tevent_req_nterror(req
, NT_STATUS_UNEXPECTED_IO_ERROR
);
196 ifa
= (struct ifaddrmsg
*)NLMSG_DATA(h
);
198 state
->addr
.ss_family
= ifa
->ifa_family
;
201 len
= h
->nlmsg_len
- sizeof(struct nlmsghdr
) + sizeof(struct ifaddrmsg
);
205 for (rta
= IFA_RTA(ifa
); RTA_OK(rta
, len
); rta
= RTA_NEXT(rta
, len
)) {
207 if ((rta
->rta_type
!= IFA_LOCAL
)
208 && (rta
->rta_type
!= IFA_ADDRESS
)) {
212 switch (ifa
->ifa_family
) {
214 struct sockaddr_in
*v4_addr
;
215 v4_addr
= (struct sockaddr_in
*)(void *)&state
->addr
;
217 if (RTA_PAYLOAD(rta
) != sizeof(uint32_t)) {
220 v4_addr
->sin_addr
.s_addr
= *(uint32_t *)RTA_DATA(rta
);
225 struct sockaddr_in6
*v6_addr
;
226 v6_addr
= (struct sockaddr_in6
*)(void *)&state
->addr
;
228 if (RTA_PAYLOAD(rta
) !=
229 sizeof(v6_addr
->sin6_addr
.s6_addr
)) {
232 memcpy(v6_addr
->sin6_addr
.s6_addr
, RTA_DATA(rta
),
233 sizeof(v6_addr
->sin6_addr
.s6_addr
));
241 tevent_req_nterror(req
, NT_STATUS_INVALID_ADDRESS
);
245 tevent_req_done(req
);
249 state
->fromaddr_len
= sizeof(state
->fromaddr
);
250 subreq
= recvfrom_send(state
, state
->ev
, state
->ctx
->sock
,
251 state
->buf
, sizeof(state
->buf
), 0,
252 &state
->fromaddr
, &state
->fromaddr_len
);
253 if (tevent_req_nomem(subreq
, req
)) {
256 tevent_req_set_callback(subreq
, addrchange_done
, req
);
259 NTSTATUS
addrchange_recv(struct tevent_req
*req
, enum addrchange_type
*type
,
260 struct sockaddr_storage
*addr
)
262 struct addrchange_state
*state
= tevent_req_data(
263 req
, struct addrchange_state
);
266 if (tevent_req_is_nterror(req
, &status
)) {
277 NTSTATUS
addrchange_context_create(TALLOC_CTX
*mem_ctx
,
278 struct addrchange_context
**pctx
)
280 return NT_STATUS_NOT_SUPPORTED
;
283 struct tevent_req
*addrchange_send(TALLOC_CTX
*mem_ctx
,
284 struct tevent_context
*ev
,
285 struct addrchange_context
*ctx
)
290 NTSTATUS
addrchange_recv(struct tevent_req
*req
, enum addrchange_type
*type
,
291 struct sockaddr_storage
*addr
)
293 return NT_STATUS_NOT_IMPLEMENTED
;