root/source4/nbt_server/interfaces.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nbtd_request_handler
  2. nbtd_unexpected_handler
  3. nbtd_find_iname
  4. nbtd_add_socket
  5. nbtd_add_wins_socket
  6. nbtd_startup_interfaces
  7. nbtd_address_list
  8. nbtd_find_request_iface
  9. nbtd_find_reply_iface

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    NBT interface handling
   5 
   6    Copyright (C) Andrew Tridgell        2005
   7    
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12    
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17    
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #include "includes.h"
  23 #include "../lib/util/dlinklist.h"
  24 #include "nbt_server/nbt_server.h"
  25 #include "smbd/service_task.h"
  26 #include "lib/socket/socket.h"
  27 #include "nbt_server/wins/winsserver.h"
  28 #include "nbt_server/dgram/proto.h"
  29 #include "system/network.h"
  30 #include "lib/socket/netif.h"
  31 #include "param/param.h"
  32 
  33 
  34 /*
  35   receive an incoming request and dispatch it to the right place
  36 */
  37 static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
     /* [<][>][^][v][top][bottom][index][help] */
  38                                  struct nbt_name_packet *packet, 
  39                                  struct socket_address *src)
  40 {
  41         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
  42                                                        struct nbtd_interface);
  43         struct nbtd_server *nbtsrv = iface->nbtsrv;
  44 
  45         nbtsrv->stats.total_received++;
  46 
  47         /* see if its from one of our own interfaces - if so, then ignore it */
  48         if (nbtd_self_packet_and_bcast(nbtsock, packet, src)) {
  49                 DEBUG(10,("Ignoring bcast self packet from %s:%d\n", src->addr, src->port));
  50                 return;
  51         }
  52 
  53         switch (packet->operation & NBT_OPCODE) {
  54         case NBT_OPCODE_QUERY:
  55                 nbtsrv->stats.query_count++;
  56                 nbtd_request_query(nbtsock, packet, src);
  57                 break;
  58 
  59         case NBT_OPCODE_REGISTER:
  60         case NBT_OPCODE_REFRESH:
  61         case NBT_OPCODE_REFRESH2:
  62                 nbtsrv->stats.register_count++;
  63                 nbtd_request_defense(nbtsock, packet, src);
  64                 break;
  65 
  66         case NBT_OPCODE_RELEASE:
  67         case NBT_OPCODE_MULTI_HOME_REG:
  68                 nbtsrv->stats.release_count++;
  69                 nbtd_winsserver_request(nbtsock, packet, src);
  70                 break;
  71 
  72         default:
  73                 nbtd_bad_packet(packet, src, "Unexpected opcode");
  74                 break;
  75         }
  76 }
  77 
  78 static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
     /* [<][>][^][v][top][bottom][index][help] */
  79                                     struct nbt_name_packet *packet,
  80                                     struct socket_address *src)
  81 {
  82         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
  83                                                        struct nbtd_interface);
  84         struct nbtd_server *nbtsrv = iface->nbtsrv;
  85         struct nbtd_interface *i;
  86         struct nbt_name_request *req = NULL;
  87 
  88         nbtsrv->stats.total_received++;
  89 
  90         DEBUG(10,("unexpected from src[%s] on interface[%p] %s/%s\n",
  91                 src->addr, iface, iface->ip_address, iface->netmask));
  92 
  93         /* try the broadcast interface */
  94         if (nbtsrv->bcast_interface) {
  95                 i = nbtsrv->bcast_interface;
  96                 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
  97         }
  98 
  99         /* try the wins server client interface */
 100         if (!req && nbtsrv->wins_interface && nbtsrv->wins_interface->nbtsock) {
 101                 i = nbtsrv->wins_interface;
 102                 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
 103         }
 104 
 105         /* try all other interfaces... */
 106         if (!req) {
 107                 for (i = nbtsrv->interfaces; i; i = i->next) {
 108                         if (i == iface) {
 109                                 continue;
 110                         }
 111                         req = idr_find(i->nbtsock->idr, packet->name_trn_id);
 112                         if (req) break;
 113                 }
 114         }
 115 
 116         if (!req) {
 117                 DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
 118                 return;
 119         }
 120 
 121         DEBUG(10,("unexpected from src[%s] redirected to interface[%p] %s/%s\n",
 122                 src->addr, i, i->ip_address, i->netmask));
 123 
 124         /*
 125          * redirect the incoming response to the socket
 126          * we sent the matching request
 127          */
 128         nbt_name_socket_handle_response_packet(req, packet, src);
 129 }
 130 
 131 /*
 132   find a registered name on an interface
 133 */
 134 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface, 
     /* [<][>][^][v][top][bottom][index][help] */
 135                                         struct nbt_name *name, 
 136                                         uint16_t nb_flags)
 137 {
 138         struct nbtd_iface_name *iname;
 139         for (iname=iface->names;iname;iname=iname->next) {
 140                 if (iname->name.type == name->type &&
 141                     strcmp(name->name, iname->name.name) == 0 &&
 142                     ((iname->nb_flags & nb_flags) == nb_flags)) {
 143                         return iname;
 144                 }
 145         }
 146         return NULL;
 147 }
 148 
 149 /*
 150   start listening on the given address
 151 */
 152 static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, 
     /* [<][>][^][v][top][bottom][index][help] */
 153                                 struct loadparm_context *lp_ctx,
 154                                 const char *bind_address, 
 155                                 const char *address, 
 156                                 const char *bcast, 
 157                                 const char *netmask)
 158 {
 159         struct nbtd_interface *iface;
 160         NTSTATUS status;
 161         struct socket_address *bcast_address;
 162         struct socket_address *unicast_address;
 163 
 164         DEBUG(6,("nbtd_add_socket(%s, %s, %s, %s)\n", bind_address, address, bcast, netmask));
 165 
 166         /*
 167           we actually create two sockets. One listens on the broadcast address
 168           for the interface, and the other listens on our specific address. This
 169           allows us to run with "bind interfaces only" while still receiving 
 170           broadcast addresses, and also simplifies matching incoming requests 
 171           to interfaces
 172         */
 173 
 174         iface = talloc(nbtsrv, struct nbtd_interface);
 175         NT_STATUS_HAVE_NO_MEMORY(iface);
 176 
 177         iface->nbtsrv        = nbtsrv;
 178         iface->bcast_address = talloc_steal(iface, bcast);
 179         iface->ip_address    = talloc_steal(iface, address);
 180         iface->netmask       = talloc_steal(iface, netmask);
 181         iface->names         = NULL;
 182         iface->wack_queue    = NULL;
 183 
 184         if (strcmp(netmask, "0.0.0.0") != 0) {
 185                 struct nbt_name_socket *bcast_nbtsock;
 186 
 187                 /* listen for broadcasts on port 137 */
 188                 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx, lp_iconv_convenience(nbtsrv->task->lp_ctx));
 189                 if (!bcast_nbtsock) {
 190                         talloc_free(iface);
 191                         return NT_STATUS_NO_MEMORY;
 192                 }
 193 
 194                 bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name, 
 195                                                             bcast, lp_nbt_port(lp_ctx));
 196                 if (!bcast_address) {
 197                         talloc_free(iface);
 198                         return NT_STATUS_NO_MEMORY;
 199                 }
 200 
 201                 status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
 202                 if (!NT_STATUS_IS_OK(status)) {
 203                         DEBUG(0,("Failed to bind to %s:%d - %s\n", 
 204                                  bcast, lp_nbt_port(lp_ctx), nt_errstr(status)));
 205                         talloc_free(iface);
 206                         return status;
 207                 }
 208                 talloc_free(bcast_address);
 209 
 210                 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
 211         }
 212 
 213         /* listen for unicasts on port 137 */
 214         iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx, 
 215                                               lp_iconv_convenience(nbtsrv->task->lp_ctx));
 216         if (!iface->nbtsock) {
 217                 talloc_free(iface);
 218                 return NT_STATUS_NO_MEMORY;
 219         }
 220 
 221         unicast_address = socket_address_from_strings(iface->nbtsock, 
 222                                                       iface->nbtsock->sock->backend_name, 
 223                                                       bind_address, lp_nbt_port(lp_ctx));
 224 
 225         status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
 226         if (!NT_STATUS_IS_OK(status)) {
 227                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
 228                          bind_address, lp_nbt_port(lp_ctx), nt_errstr(status)));
 229                 talloc_free(iface);
 230                 return status;
 231         }
 232         talloc_free(unicast_address);
 233 
 234         nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
 235         nbt_set_unexpected_handler(iface->nbtsock, nbtd_unexpected_handler, iface);
 236 
 237         /* also setup the datagram listeners */
 238         status = nbtd_dgram_setup(iface, bind_address);
 239         if (!NT_STATUS_IS_OK(status)) {
 240                 DEBUG(0,("Failed to setup dgram listen on %s - %s\n", 
 241                          bind_address, nt_errstr(status)));
 242                 talloc_free(iface);
 243                 return status;
 244         }
 245         
 246         if (strcmp(netmask, "0.0.0.0") == 0) {
 247                 DLIST_ADD(nbtsrv->bcast_interface, iface);
 248         } else {
 249                 DLIST_ADD(nbtsrv->interfaces, iface);
 250         }
 251 
 252         return NT_STATUS_OK;
 253 }
 254 
 255 /*
 256   setup a socket for talking to our WINS servers
 257 */
 258 static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
     /* [<][>][^][v][top][bottom][index][help] */
 259 {
 260         struct nbtd_interface *iface;
 261 
 262         iface = talloc_zero(nbtsrv, struct nbtd_interface);
 263         NT_STATUS_HAVE_NO_MEMORY(iface);
 264 
 265         iface->nbtsrv        = nbtsrv;
 266 
 267         DLIST_ADD(nbtsrv->wins_interface, iface);
 268 
 269         return NT_STATUS_OK;
 270 }
 271 
 272 
 273 /*
 274   setup our listening sockets on the configured network interfaces
 275 */
 276 NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv, struct loadparm_context *lp_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 277                                  struct interface *ifaces)
 278 {
 279         int num_interfaces = iface_count(ifaces);
 280         int i;
 281         TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
 282         NTSTATUS status;
 283 
 284         /* if we are allowing incoming packets from any address, then
 285            we also need to bind to the wildcard address */
 286         if (!lp_bind_interfaces_only(lp_ctx)) {
 287                 const char *primary_address;
 288 
 289                 /* the primary address is the address we will return
 290                    for non-WINS queries not made on a specific
 291                    interface */
 292                 if (num_interfaces > 0) {
 293                         primary_address = iface_n_ip(ifaces, 0);
 294                 } else {
 295                         primary_address = inet_ntoa(interpret_addr2(
 296                                                         lp_netbios_name(lp_ctx)));
 297                 }
 298                 primary_address = talloc_strdup(tmp_ctx, primary_address);
 299                 NT_STATUS_HAVE_NO_MEMORY(primary_address);
 300 
 301                 status = nbtd_add_socket(nbtsrv, 
 302                                          lp_ctx,
 303                                          "0.0.0.0",
 304                                          primary_address,
 305                                          talloc_strdup(tmp_ctx, "255.255.255.255"),
 306                                          talloc_strdup(tmp_ctx, "0.0.0.0"));
 307                 NT_STATUS_NOT_OK_RETURN(status);
 308         }
 309 
 310         for (i=0; i<num_interfaces; i++) {
 311                 const char *bcast = iface_n_bcast(ifaces, i);
 312                 const char *address, *netmask;
 313 
 314                 /* we can't assume every interface is broadcast capable */
 315                 if (bcast == NULL) continue;
 316 
 317                 address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
 318                 bcast   = talloc_strdup(tmp_ctx, bcast);
 319                 netmask = talloc_strdup(tmp_ctx, iface_n_netmask(ifaces, i));
 320 
 321                 status = nbtd_add_socket(nbtsrv, lp_ctx, 
 322                                          address, address, bcast, netmask);
 323                 NT_STATUS_NOT_OK_RETURN(status);
 324         }
 325 
 326         if (lp_wins_server_list(lp_ctx)) {
 327                 status = nbtd_add_wins_socket(nbtsrv);
 328                 NT_STATUS_NOT_OK_RETURN(status);
 329         }
 330 
 331         talloc_free(tmp_ctx);
 332 
 333         return NT_STATUS_OK;
 334 }
 335 
 336 
 337 /*
 338   form a list of addresses that we should use in name query replies
 339   we always place the IP in the given interface first
 340 */
 341 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 342 {
 343         struct nbtd_server *nbtsrv = iface->nbtsrv;
 344         const char **ret = NULL;
 345         struct nbtd_interface *iface2;
 346         bool is_loopback = false;
 347 
 348         if (iface->ip_address) {
 349                 is_loopback = iface_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
 350                 ret = str_list_add(ret, iface->ip_address);
 351         }
 352 
 353         for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
 354                 if (iface2 == iface) continue;
 355 
 356                 if (!iface2->ip_address) continue;
 357 
 358                 if (!is_loopback) {
 359                         if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
 360                                 continue;
 361                         }
 362                 }
 363 
 364                 ret = str_list_add(ret, iface2->ip_address);
 365         }
 366 
 367         talloc_steal(mem_ctx, ret);
 368 
 369         return ret;
 370 }
 371 
 372 
 373 /*
 374   find the interface to use for sending a outgoing request
 375 */
 376 struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
     /* [<][>][^][v][top][bottom][index][help] */
 377                                                const char *address, bool allow_bcast_iface)
 378 {
 379         struct nbtd_interface *cur;
 380 
 381         /* try to find a exact match */
 382         for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
 383                 if (iface_same_net(address, cur->ip_address, cur->netmask)) {
 384                         DEBUG(10,("find interface for dst[%s] ip: %s/%s (iface[%p])\n",
 385                                   address, cur->ip_address, cur->netmask, cur));
 386                         return cur;
 387                 }
 388         }
 389 
 390         /* no exact match, if we have the broadcast interface, use that */
 391         if (allow_bcast_iface && nbtd_server->bcast_interface) {
 392                 cur = nbtd_server->bcast_interface;
 393                 DEBUG(10,("find interface for dst[%s] ip: %s/%s (bcast iface[%p])\n",
 394                         address, cur->ip_address, cur->netmask, cur));
 395                 return cur;
 396         }
 397 
 398         /* fallback to first interface */
 399         cur = nbtd_server->interfaces;
 400         DEBUG(10,("find interface for dst[%s] ip: %s/%s (default iface[%p])\n",
 401                 address, cur->ip_address, cur->netmask, cur));
 402         return cur;
 403 }
 404 
 405 /*
 406  * find the interface to use for sending a outgoing reply
 407  */
 408 struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
     /* [<][>][^][v][top][bottom][index][help] */
 409                                              const char *address, bool allow_bcast_iface)
 410 {
 411         struct nbtd_server *nbtd_server = iface->nbtsrv;
 412 
 413         /* first try to use the given interfacel when it's not the broadcast one */
 414         if (iface != nbtd_server->bcast_interface) {
 415                 return iface;
 416         }
 417 
 418         return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
 419 }

/* [<][>][^][v][top][bottom][index][help] */