#include "includes.h"
#include "lib/addrchange.h"
+#include "../lib/util/tevent_ntstatus.h"
#if HAVE_LINUX_RTNETLINK_H
+#include "asm/types.h"
#include "linux/netlink.h"
#include "linux/rtnetlink.h"
-#include "lib/async_req/async_sock.h"
+#include "lib/tsocket/tsocket.h"
struct addrchange_context {
- int sock;
- uint8_t *buf;
+ struct tdgram_context *sock;
};
-static int addrchange_context_destructor(struct addrchange_context *c);
-
NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
struct addrchange_context **pctx)
{
struct addrchange_context *ctx;
struct sockaddr_nl addr;
NTSTATUS status;
+ int sock = -1;
int res;
+ bool ok;
ctx = talloc(mem_ctx, struct addrchange_context);
if (ctx == NULL) {
return NT_STATUS_NO_MEMORY;
}
- ctx->sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (ctx->sock == -1) {
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock == -1) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ ok = smb_set_close_on_exec(sock);
+ if (!ok) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ res = set_blocking(sock, false);
+ if (res == -1) {
status = map_nt_error_from_unix(errno);
goto fail;
}
- talloc_set_destructor(ctx, addrchange_context_destructor);
/*
* We're interested in address changes
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_IFADDR;
- res = bind(ctx->sock, (struct sockaddr *)(void *)&addr, sizeof(addr));
+ res = bind(sock, (struct sockaddr *)(void *)&addr, sizeof(addr));
+ if (res == -1) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ res = tdgram_bsd_existing_socket(ctx, sock, &ctx->sock);
if (res == -1) {
status = map_nt_error_from_unix(errno);
goto fail;
*pctx = ctx;
return NT_STATUS_OK;
fail:
+ if (sock != -1) {
+ close(sock);
+ }
TALLOC_FREE(ctx);
return status;
}
-static int addrchange_context_destructor(struct addrchange_context *c)
-{
- if (c->sock != -1) {
- close(c->sock);
- c->sock = 0;
- }
- return 0;
-}
-
struct addrchange_state {
- uint8_t buf[8192];
- struct sockaddr_storage fromaddr;
- socklen_t fromaddr_len;
+ struct tevent_context *ev;
+ struct addrchange_context *ctx;
+ uint8_t *buf;
+ struct tsocket_address *fromaddr;
enum addrchange_type type;
struct sockaddr_storage addr;
if (req == NULL) {
return NULL;
}
+ state->ev = ev;
+ state->ctx = ctx;
- state->fromaddr_len = sizeof(state->fromaddr);
-
- subreq = recvfrom_send(state, ev, ctx->sock,
- state->buf, sizeof(state->buf), 0,
- &state->fromaddr, &state->fromaddr_len);
+ subreq = tdgram_recvfrom_send(state, state->ev, state->ctx->sock);
if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ return tevent_req_post(req, state->ev);
}
tevent_req_set_callback(subreq, addrchange_done, req);
return req;
subreq, struct tevent_req);
struct addrchange_state *state = tevent_req_data(
req, struct addrchange_state);
+ union {
+ struct sockaddr sa;
+ struct sockaddr_nl nl;
+ struct sockaddr_storage ss;
+ } fromaddr;
struct nlmsghdr *h;
struct ifaddrmsg *ifa;
struct rtattr *rta;
int err;
bool found;
- received = recvfrom_recv(subreq, &err);
+ received = tdgram_recvfrom_recv(subreq, &err, state,
+ &state->buf,
+ &state->fromaddr);
TALLOC_FREE(subreq);
if (received == -1) {
- DEBUG(10, ("recvfrom returned %s\n", strerror(errno)));
+ DEBUG(10, ("tdgram_recvfrom_recv returned %s\n", strerror(err)));
tevent_req_nterror(req, map_nt_error_from_unix(err));
return;
}
+ len = tsocket_address_bsd_sockaddr(state->fromaddr,
+ &fromaddr.sa,
+ sizeof(fromaddr));
+
+ if ((len != sizeof(fromaddr.nl) ||
+ fromaddr.sa.sa_family != AF_NETLINK))
+ {
+ DEBUG(10, ("Got message from wrong addr\n"));
+ goto retry;
+ }
+
+ if (fromaddr.nl.nl_pid != 0) {
+ DEBUG(10, ("Got msg from pid %d, not from the kernel\n",
+ (int)fromaddr.nl.nl_pid));
+ goto retry;
+ }
+
if (received < sizeof(struct nlmsghdr)) {
DEBUG(10, ("received %d, expected at least %d\n",
(int)received, (int)sizeof(struct nlmsghdr)));
- tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
- return;
+ goto retry;
}
h = (struct nlmsghdr *)state->buf;
if (h->nlmsg_len < sizeof(struct nlmsghdr)) {
DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
(int)h->nlmsg_len, (int)sizeof(struct nlmsghdr)));
- tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
- return;
+ goto retry;
}
if (h->nlmsg_len > received) {
DEBUG(10, ("nlmsg_len=%d, expected at most %d\n",
(int)h->nlmsg_len, (int)received));
- tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
- return;
+ goto retry;
}
switch (h->nlmsg_type) {
case RTM_NEWADDR:
state->type = ADDRCHANGE_DEL;
break;
default:
- DEBUG(10, ("Got unexpected type %d\n", h->nlmsg_type));
- tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
- return;
+ DEBUG(10, ("Got unexpected type %d - ignoring\n", h->nlmsg_type));
+ goto retry;
}
if (h->nlmsg_len < sizeof(struct nlmsghdr)+sizeof(struct ifaddrmsg)) {
}
tevent_req_done(req);
+ return;
+
+retry:
+ TALLOC_FREE(state->buf);
+ TALLOC_FREE(state->fromaddr);
+
+ subreq = tdgram_recvfrom_send(state, state->ev, state->ctx->sock);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, addrchange_done, req);
}
NTSTATUS addrchange_recv(struct tevent_req *req, enum addrchange_type *type,
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
return status;
}
*type = state->type;
*addr = state->addr;
+ tevent_req_received(req);
return NT_STATUS_OK;
}