LCOV - code coverage report
Current view: top level - source3/lib - addrchange.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 28 149 18.8 %
Date: 2024-02-28 12:06:22 Functions: 2 4 50.0 %

          Line data    Source code
       1             : /*
       2             :  * Samba Unix/Linux SMB client library
       3             :  * Copyright (C) Volker Lendecke 2011
       4             :  *
       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.
       9             :  *
      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.
      14             :  *
      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/>.
      17             :  */
      18             : 
      19             : #include "includes.h"
      20             : #include "lib/addrchange.h"
      21             : #include "../lib/util/tevent_ntstatus.h"
      22             : 
      23             : #ifdef HAVE_LINUX_RTNETLINK_H
      24             : 
      25             : #include "asm/types.h"
      26             : #include "linux/netlink.h"
      27             : #include "linux/rtnetlink.h"
      28             : #include "lib/tsocket/tsocket.h"
      29             : 
      30             : struct addrchange_context {
      31             :         struct tdgram_context *sock;
      32             : };
      33             : 
      34          45 : NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
      35             :                                    struct addrchange_context **pctx)
      36             : {
      37           0 :         struct addrchange_context *ctx;
      38           0 :         struct sockaddr_nl addr;
      39           0 :         NTSTATUS status;
      40          45 :         int sock = -1;
      41           0 :         int res;
      42           0 :         bool ok;
      43             : 
      44          45 :         ctx = talloc(mem_ctx, struct addrchange_context);
      45          45 :         if (ctx == NULL) {
      46           0 :                 return NT_STATUS_NO_MEMORY;
      47             :         }
      48             : 
      49          45 :         sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
      50          45 :         if (sock == -1) {
      51           0 :                 status = map_nt_error_from_unix(errno);
      52           0 :                 goto fail;
      53             :         }
      54             : 
      55          45 :         ok = smb_set_close_on_exec(sock);
      56          45 :         if (!ok) {
      57           0 :                 status = map_nt_error_from_unix(errno);
      58           0 :                 goto fail;
      59             :         }
      60             : 
      61          45 :         res = set_blocking(sock, false);
      62          45 :         if (res == -1) {
      63           0 :                 status = map_nt_error_from_unix(errno);
      64           0 :                 goto fail;
      65             :         }
      66             : 
      67             :         /*
      68             :          * We're interested in address changes
      69             :          */
      70          45 :         ZERO_STRUCT(addr);
      71          45 :         addr.nl_family = AF_NETLINK;
      72          45 :         addr.nl_groups = RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_IFADDR;
      73             : 
      74          45 :         res = bind(sock, (struct sockaddr *)(void *)&addr, sizeof(addr));
      75          45 :         if (res == -1) {
      76           0 :                 status = map_nt_error_from_unix(errno);
      77           0 :                 goto fail;
      78             :         }
      79             : 
      80          45 :         res = tdgram_bsd_existing_socket(ctx, sock, &ctx->sock);
      81          45 :         if (res == -1) {
      82           0 :                 status = map_nt_error_from_unix(errno);
      83           0 :                 goto fail;
      84             :         }
      85             : 
      86          45 :         *pctx = ctx;
      87          45 :         return NT_STATUS_OK;
      88           0 : fail:
      89           0 :         if (sock != -1) {
      90           0 :                 close(sock);
      91             :         }
      92           0 :         TALLOC_FREE(ctx);
      93           0 :         return status;
      94             : }
      95             : 
      96             : struct addrchange_state {
      97             :         struct tevent_context *ev;
      98             :         struct addrchange_context *ctx;
      99             :         uint8_t *buf;
     100             :         struct tsocket_address *fromaddr;
     101             : 
     102             :         enum addrchange_type type;
     103             :         struct sockaddr_storage addr;
     104             : };
     105             : 
     106             : static void addrchange_done(struct tevent_req *subreq);
     107             : 
     108          45 : struct tevent_req *addrchange_send(TALLOC_CTX *mem_ctx,
     109             :                                    struct tevent_context *ev,
     110             :                                    struct addrchange_context *ctx)
     111             : {
     112           0 :         struct tevent_req *req, *subreq;
     113           0 :         struct addrchange_state *state;
     114             : 
     115          45 :         req = tevent_req_create(mem_ctx, &state, struct addrchange_state);
     116          45 :         if (req == NULL) {
     117           0 :                 return NULL;
     118             :         }
     119          45 :         state->ev = ev;
     120          45 :         state->ctx = ctx;
     121             : 
     122          45 :         subreq = tdgram_recvfrom_send(state, state->ev, state->ctx->sock);
     123          45 :         if (tevent_req_nomem(subreq, req)) {
     124           0 :                 return tevent_req_post(req, state->ev);
     125             :         }
     126          45 :         tevent_req_set_callback(subreq, addrchange_done, req);
     127          45 :         return req;
     128             : }
     129             : 
     130           0 : static void addrchange_done(struct tevent_req *subreq)
     131             : {
     132           0 :         struct tevent_req *req = tevent_req_callback_data(
     133             :                 subreq, struct tevent_req);
     134           0 :         struct addrchange_state *state = tevent_req_data(
     135             :                 req, struct addrchange_state);
     136           0 :         union {
     137             :                 struct sockaddr sa;
     138             :                 struct sockaddr_nl nl;
     139             :                 struct sockaddr_storage ss;
     140             :         } fromaddr;
     141           0 :         struct nlmsghdr *h;
     142           0 :         struct ifaddrmsg *ifa;
     143           0 :         struct rtattr *rta;
     144           0 :         ssize_t received;
     145           0 :         int len;
     146           0 :         int err;
     147           0 :         bool found;
     148             : 
     149           0 :         received = tdgram_recvfrom_recv(subreq, &err, state,
     150             :                                         &state->buf,
     151             :                                         &state->fromaddr);
     152           0 :         TALLOC_FREE(subreq);
     153           0 :         if (received == -1) {
     154           0 :                 DEBUG(10, ("tdgram_recvfrom_recv returned %s\n", strerror(err)));
     155           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(err));
     156           0 :                 return;
     157             :         }
     158           0 :         len = tsocket_address_bsd_sockaddr(state->fromaddr,
     159             :                                            &fromaddr.sa,
     160             :                                            sizeof(fromaddr));
     161             : 
     162           0 :         if ((len != sizeof(fromaddr.nl) ||
     163           0 :             fromaddr.sa.sa_family != AF_NETLINK))
     164             :         {
     165           0 :                 DEBUG(10, ("Got message from wrong addr\n"));
     166           0 :                 goto retry;
     167             :         }
     168             : 
     169           0 :         if (fromaddr.nl.nl_pid != 0) {
     170           0 :                 DEBUG(10, ("Got msg from pid %d, not from the kernel\n",
     171             :                            (int)fromaddr.nl.nl_pid));
     172           0 :                 goto retry;
     173             :         }
     174             : 
     175           0 :         if (received < sizeof(struct nlmsghdr)) {
     176           0 :                 DEBUG(10, ("received %d, expected at least %d\n",
     177             :                            (int)received, (int)sizeof(struct nlmsghdr)));
     178           0 :                 goto retry;
     179             :         }
     180             : 
     181           0 :         h = (struct nlmsghdr *)state->buf;
     182           0 :         if (h->nlmsg_len < sizeof(struct nlmsghdr)) {
     183           0 :                 DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
     184             :                            (int)h->nlmsg_len, (int)sizeof(struct nlmsghdr)));
     185           0 :                 goto retry;
     186             :         }
     187           0 :         if (h->nlmsg_len > received) {
     188           0 :                 DEBUG(10, ("nlmsg_len=%d, expected at most %d\n",
     189             :                            (int)h->nlmsg_len, (int)received));
     190           0 :                 goto retry;
     191             :         }
     192           0 :         switch (h->nlmsg_type) {
     193           0 :         case RTM_NEWADDR:
     194           0 :                 state->type = ADDRCHANGE_ADD;
     195           0 :                 break;
     196           0 :         case RTM_DELADDR:
     197           0 :                 state->type = ADDRCHANGE_DEL;
     198           0 :                 break;
     199           0 :         default:
     200           0 :                 DEBUG(10, ("Got unexpected type %d - ignoring\n", h->nlmsg_type));
     201           0 :                 goto retry;
     202             :         }
     203             : 
     204           0 :         if (h->nlmsg_len < sizeof(struct nlmsghdr)+sizeof(struct ifaddrmsg)) {
     205           0 :                 DEBUG(10, ("nlmsg_len=%d, expected at least %d\n",
     206             :                            (int)h->nlmsg_len,
     207             :                            (int)(sizeof(struct nlmsghdr)
     208             :                                  +sizeof(struct ifaddrmsg))));
     209           0 :                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
     210           0 :                 return;
     211             :         }
     212             : 
     213           0 :         ifa = (struct ifaddrmsg *)NLMSG_DATA(h);
     214             : 
     215           0 :         state->addr.ss_family = ifa->ifa_family;
     216             : 
     217           0 :         len = h->nlmsg_len - sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg);
     218             : 
     219           0 :         found = false;
     220             : 
     221           0 :         for (rta = IFA_RTA(ifa); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
     222             : 
     223           0 :                 if ((rta->rta_type != IFA_LOCAL)
     224           0 :                     && (rta->rta_type != IFA_ADDRESS)) {
     225           0 :                         continue;
     226             :                 }
     227             : 
     228           0 :                 switch (ifa->ifa_family) {
     229           0 :                 case AF_INET: {
     230           0 :                         struct sockaddr_in *v4_addr;
     231           0 :                         v4_addr = (struct sockaddr_in *)(void *)&state->addr;
     232             : 
     233           0 :                         if (RTA_PAYLOAD(rta) != sizeof(uint32_t)) {
     234           0 :                                 continue;
     235             :                         }
     236           0 :                         v4_addr->sin_addr.s_addr = *(uint32_t *)RTA_DATA(rta);
     237           0 :                         found = true;
     238           0 :                         break;
     239             :                 }
     240           0 :                 case AF_INET6: {
     241           0 :                         struct sockaddr_in6 *v6_addr;
     242           0 :                         v6_addr = (struct sockaddr_in6 *)(void *)&state->addr;
     243             : 
     244           0 :                         if (RTA_PAYLOAD(rta) !=
     245             :                             sizeof(v6_addr->sin6_addr.s6_addr)) {
     246           0 :                                 continue;
     247             :                         }
     248           0 :                         memcpy(v6_addr->sin6_addr.s6_addr, RTA_DATA(rta),
     249             :                                sizeof(v6_addr->sin6_addr.s6_addr));
     250           0 :                         found = true;
     251           0 :                         break;
     252             :                 }
     253             :                 }
     254             :         }
     255             : 
     256           0 :         if (!found) {
     257           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
     258           0 :                 return;
     259             :         }
     260             : 
     261           0 :         tevent_req_done(req);
     262           0 :         return;
     263             : 
     264           0 : retry:
     265           0 :         TALLOC_FREE(state->buf);
     266           0 :         TALLOC_FREE(state->fromaddr);
     267             : 
     268           0 :         subreq = tdgram_recvfrom_send(state, state->ev, state->ctx->sock);
     269           0 :         if (tevent_req_nomem(subreq, req)) {
     270           0 :                 return;
     271             :         }
     272           0 :         tevent_req_set_callback(subreq, addrchange_done, req);
     273             : }
     274             : 
     275           0 : NTSTATUS addrchange_recv(struct tevent_req *req, enum addrchange_type *type,
     276             :                          struct sockaddr_storage *addr)
     277             : {
     278           0 :         struct addrchange_state *state = tevent_req_data(
     279             :                 req, struct addrchange_state);
     280           0 :         NTSTATUS status;
     281             : 
     282           0 :         if (tevent_req_is_nterror(req, &status)) {
     283           0 :                 tevent_req_received(req);
     284           0 :                 return status;
     285             :         }
     286             : 
     287           0 :         *type = state->type;
     288           0 :         *addr = state->addr;
     289           0 :         tevent_req_received(req);
     290           0 :         return NT_STATUS_OK;
     291             : }
     292             : 
     293             : #else
     294             : 
     295             : NTSTATUS addrchange_context_create(TALLOC_CTX *mem_ctx,
     296             :                                    struct addrchange_context **pctx)
     297             : {
     298             :         return NT_STATUS_NOT_SUPPORTED;
     299             : }
     300             : 
     301             : struct tevent_req *addrchange_send(TALLOC_CTX *mem_ctx,
     302             :                                    struct tevent_context *ev,
     303             :                                    struct addrchange_context *ctx)
     304             : {
     305             :         return NULL;
     306             : }
     307             : 
     308             : NTSTATUS addrchange_recv(struct tevent_req *req, enum addrchange_type *type,
     309             :                          struct sockaddr_storage *addr)
     310             : {
     311             :         return NT_STATUS_NOT_IMPLEMENTED;
     312             : }
     313             : 
     314             : #endif

Generated by: LCOV version 1.14