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 #ifdef HAVE_LINUX_RTNETLINK_H
25 #include "asm/types.h"
27 #include "linux/netlink.h"
28 #include "linux/rtnetlink.h"
29 #include "lib/tsocket/tsocket.h"
31 struct addrchange_context {
32 struct tdgram_context *sock;
35 NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
36 struct addrchange_context **pctx)
38 struct addrchange_context *ctx;
39 struct sockaddr_nl addr;
45 ctx = talloc(mem_ctx, struct addrchange_context);
47 return NT_STATUS_NO_MEMORY;
50 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
52 status = map_nt_error_from_unix(errno);
56 ok = smb_set_close_on_exec(sock);
58 status = map_nt_error_from_unix(errno);
62 res = set_blocking(sock, false);
64 status = map_nt_error_from_unix(errno);
69 * We're interested in address changes
72 addr.nl_family = AF_NETLINK;
73 addr.nl_groups = RTNLGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_IFADDR;
75 res = bind(sock, (struct sockaddr *)(void *)&addr, sizeof(addr));
77 status = map_nt_error_from_unix(errno);
81 res = tdgram_bsd_existing_socket(ctx, sock, &ctx->sock);
83 status = map_nt_error_from_unix(errno);
97 struct addrchange_state {
98 struct tevent_context *ev;
99 struct addrchange_context *ctx;
101 struct tsocket_address *fromaddr;
103 enum addrchange_type type;
104 struct sockaddr_storage addr;
107 static void addrchange_done(struct tevent_req *subreq);
109 struct tevent_req *addrchange_send(TALLOC_CTX *mem_ctx,
110 struct tevent_context *ev,
111 struct addrchange_context *ctx)
113 struct tevent_req *req, *subreq;
114 struct addrchange_state *state;
116 req = tevent_req_create(mem_ctx, &state, struct addrchange_state);
123 subreq = tdgram_recvfrom_send(state, state->ev, state->ctx->sock);
124 if (tevent_req_nomem(subreq, req)) {
125 return tevent_req_post(req, state->ev);
127 tevent_req_set_callback(subreq, addrchange_done, req);
131 static void addrchange_done(struct tevent_req *subreq)
133 struct tevent_req *req = tevent_req_callback_data(
134 subreq, struct tevent_req);
135 struct addrchange_state *state = tevent_req_data(
136 req, struct addrchange_state);
139 struct sockaddr_nl nl;
140 struct sockaddr_storage ss;
143 struct ifaddrmsg *ifa;
144 struct ifinfomsg *ifi;
151 received = tdgram_recvfrom_recv(subreq, &err, state,
155 if (received == -1) {
156 DEBUG(10, ("tdgram_recvfrom_recv returned %s\n", strerror(err)));
157 tevent_req_nterror(req, map_nt_error_from_unix(err));
160 len = tsocket_address_bsd_sockaddr(state->fromaddr,
164 if ((len != sizeof(fromaddr.nl) ||
165 fromaddr.sa.sa_family != AF_NETLINK))
167 DEBUG(10, ("Got message from wrong addr\n"));
171 if (fromaddr.nl.nl_pid != 0) {
172 DEBUG(10, ("Got msg from pid %d, not from the kernel\n",
173 (int)fromaddr.nl.nl_pid));
177 if (received < sizeof(struct nlmsghdr)) {
178 DEBUG(10, ("received %d, expected at least %d\n",
179 (int)received, (int)sizeof(struct nlmsghdr)));
183 h = (struct nlmsghdr *)state->buf;
184 if (h->nlmsg_len < sizeof(struct nlmsghdr)) {
185 DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
186 (int)h->nlmsg_len, (int)sizeof(struct nlmsghdr)));
189 if (h->nlmsg_len > received) {
190 DEBUG(10, ("nlmsg_len=%d, expected at most %d\n",
191 (int)h->nlmsg_len, (int)received));
194 switch (h->nlmsg_type) {
196 state->type = ADDRCHANGE_ADD;
199 state->type = ADDRCHANGE_DEL;
202 state->type = ADDRCHANGE_LINK;
206 DEBUG(10, ("Got unexpected type %d - ignoring\n", h->nlmsg_type));
210 if (h->nlmsg_len < sizeof(struct nlmsghdr)+sizeof(struct ifaddrmsg)) {
211 DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
213 (int)(sizeof(struct nlmsghdr)
214 +sizeof(struct ifaddrmsg))));
215 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
219 ifa = (struct ifaddrmsg *)NLMSG_DATA(h);
221 state->addr.ss_family = ifa->ifa_family;
223 len = h->nlmsg_len - sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg);
227 for (rta = IFA_RTA(ifa); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
229 if ((rta->rta_type != IFA_LOCAL)
230 && (rta->rta_type != IFA_ADDRESS)) {
234 switch (ifa->ifa_family) {
236 struct sockaddr_in *v4_addr;
237 v4_addr = (struct sockaddr_in *)(void *)&state->addr;
239 if (RTA_PAYLOAD(rta) != sizeof(uint32_t)) {
242 v4_addr->sin_addr.s_addr = *(uint32_t *)RTA_DATA(rta);
247 struct sockaddr_in6 *v6_addr;
248 v6_addr = (struct sockaddr_in6 *)(void *)&state->addr;
250 if (RTA_PAYLOAD(rta) !=
251 sizeof(v6_addr->sin6_addr.s6_addr)) {
254 memcpy(v6_addr->sin6_addr.s6_addr, RTA_DATA(rta),
255 sizeof(v6_addr->sin6_addr.s6_addr));
263 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
267 tevent_req_done(req);
272 if (h->nlmsg_len < sizeof(struct nlmsghdr)+sizeof(struct ifinfomsg)) {
273 DEBUG(0, ("nlmsg_len=%d, expected at least %d\n",
275 (int)(sizeof(struct nlmsghdr)
276 +sizeof(struct ifinfomsg))));
277 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
281 ifi = (struct ifinfomsg *)NLMSG_DATA(h);
283 DBG_ERR("ifi_type[%u] ifi_index[%d] ifi_flags[%u]\n",
284 ifi->ifi_type, ifi->ifi_index, ifi->ifi_flags);
286 DBG_ERR("IFF_UP: %u\n", ifi->ifi_flags & IFF_UP);
287 DBG_ERR("IFF_BROADCAST: %u\n", ifi->ifi_flags & IFF_BROADCAST);
288 DBG_ERR("IFF_DEBUG: %u\n", ifi->ifi_flags & IFF_DEBUG);
289 DBG_ERR("IFF_LOOPBACK: %u\n", ifi->ifi_flags & IFF_LOOPBACK);
290 DBG_ERR("IFF_POINTOPOINT: %u\n", ifi->ifi_flags & IFF_POINTOPOINT);
291 DBG_ERR("IFF_NOTRAILERS: %u\n", ifi->ifi_flags & IFF_NOTRAILERS);
292 DBG_ERR("IFF_RUNNING: %u\n", ifi->ifi_flags & IFF_RUNNING);
293 DBG_ERR("IFF_NOARP: %u\n", ifi->ifi_flags & IFF_NOARP);
294 DBG_ERR("IFF_PROMISC: %u\n", ifi->ifi_flags & IFF_PROMISC);
295 DBG_ERR("IFF_ALLMULTI: %u\n", ifi->ifi_flags & IFF_ALLMULTI);
296 DBG_ERR("IFF_MASTER: %u\n", ifi->ifi_flags & IFF_MASTER);
297 DBG_ERR("IFF_SLAVE: %u\n", ifi->ifi_flags & IFF_SLAVE);
298 DBG_ERR("IFF_MULTICAST: %u\n", ifi->ifi_flags & IFF_MULTICAST);
299 DBG_ERR("IFF_PORTSEL: %u\n", ifi->ifi_flags & IFF_PORTSEL);
300 DBG_ERR("IFF_AUTOMEDIA: %u\n", ifi->ifi_flags & IFF_AUTOMEDIA);
301 DBG_ERR("IFF_DYNAMIC: %u\n", ifi->ifi_flags & IFF_DYNAMIC);
302 DBG_ERR("IFF_LOWER_UP: %u\n", ifi->ifi_flags & IFF_LOWER_UP);
303 DBG_ERR("IFF_DORMANT: %u\n", ifi->ifi_flags & IFF_DORMANT);
304 DBG_ERR("IFF_ECHO: %u\n", ifi->ifi_flags & IFF_ECHO);
306 len = h->nlmsg_len - sizeof(struct nlmsghdr) + sizeof(struct ifinfomsg);
310 for (rta = IFA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
312 DBG_ERR("rta_type[%u] RTA_PAYLOAD(%lu)\n", rta->rta_type, RTA_PAYLOAD(rta));
314 switch (rta->rta_type) {
316 if (RTA_PAYLOAD(rta) != sizeof(int)) {
323 if (RTA_PAYLOAD(rta) != sizeof(unsigned int)) {
338 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
342 tevent_req_done(req);
345 TALLOC_FREE(state->buf);
346 TALLOC_FREE(state->fromaddr);
348 subreq = tdgram_recvfrom_send(state, state->ev, state->ctx->sock);
349 if (tevent_req_nomem(subreq, req)) {
352 tevent_req_set_callback(subreq, addrchange_done, req);
355 NTSTATUS addrchange_recv(struct tevent_req *req, enum addrchange_type *type,
356 struct sockaddr_storage *addr)
358 struct addrchange_state *state = tevent_req_data(
359 req, struct addrchange_state);
362 if (tevent_req_is_nterror(req, &status)) {
363 tevent_req_received(req);
369 tevent_req_received(req);
375 NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
376 struct addrchange_context **pctx)
378 return NT_STATUS_NOT_SUPPORTED;
381 struct tevent_req *addrchange_send(TALLOC_CTX *mem_ctx,
382 struct tevent_context *ev,
383 struct addrchange_context *ctx)
388 NTSTATUS addrchange_recv(struct tevent_req *req, enum addrchange_type *type,
389 struct sockaddr_storage *addr)
391 return NT_STATUS_NOT_IMPLEMENTED;