r5114: the nbtd task can now act as a basic B-node server. It registers its
[garming/samba-autobuild/.git] / source4 / nbt_server / interfaces.c
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "dlinklist.h"
25 #include "nbt_server/nbt_server.h"
26 #include "smbd/service_task.h"
27
28 /*
29   find a registered name on an interface
30 */
31 struct nbt_iface_name *nbt_find_iname(struct nbt_interface *iface, struct nbt_name *name, 
32                                       uint16_t nb_flags)
33 {
34         struct nbt_iface_name *iname;
35         for (iname=iface->names;iname;iname=iname->next) {
36                 if (iname->name.type == name->type &&
37                     StrCaseCmp(name->name, iname->name.name) == 0 &&
38                     ((iname->nb_flags & nb_flags) == nb_flags)) {
39                         return iname;
40                 }
41         }
42         return NULL;
43 }
44
45 /*
46   see if a src address matches an interface
47 */
48 static BOOL nbt_iface_match(struct nbt_interface *iface, const char *src_address)
49 {
50         struct ipv4_addr ip1, ip2, mask;
51         ip1  = interpret_addr2(iface->ip_address);
52         ip2  = interpret_addr2(src_address);
53         mask = interpret_addr2(iface->netmask);
54         return same_net(ip1, ip2, mask);
55 }
56
57
58 /*
59   find the appropriate interface for a incoming packet. If a local interface isn't
60   found then the general broadcast interface is used
61 */
62 struct nbt_interface *nbt_iface_find(struct nbt_name_socket *nbtsock, const char *src_address)
63 {
64         struct nbt_interface *iface = talloc_get_type(nbtsock->incoming.private, struct nbt_interface);
65         struct nbt_server *nbtsrv = iface->nbtsrv;
66         
67         /* it might have been received by one of our specific bound
68            addresses */
69         if (iface != nbtsrv->bcast_interface) {
70                 return iface;
71         }
72
73         /* it came in on our broadcast interface - try to find a match */
74         for (iface=nbtsrv->interfaces;iface;iface=iface->next) {
75                 if (nbt_iface_match(iface, src_address)) {
76                         return iface;
77                 }
78         }
79
80         /* it didn't match any specific interface - use our general broadcast interface */
81         return nbtsrv->bcast_interface;
82 }
83
84
85 /*
86   start listening on the given address
87 */
88 static NTSTATUS nbt_add_socket(struct nbt_server *nbtsrv, 
89                                const char *bind_address, 
90                                const char *address, 
91                                const char *bcast, 
92                                const char *netmask)
93 {
94         struct nbt_interface *iface;
95         NTSTATUS status;
96
97         iface = talloc(nbtsrv, struct nbt_interface);
98         NT_STATUS_HAVE_NO_MEMORY(iface);
99
100         iface->nbtsrv        = nbtsrv;
101         iface->bcast_address = talloc_steal(iface, bcast);
102         iface->ip_address    = talloc_steal(iface, address);
103         iface->netmask       = talloc_steal(iface, netmask);
104         iface->names         = NULL;
105
106         iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
107         NT_STATUS_HAVE_NO_MEMORY(iface->ip_address);
108
109         status = socket_listen(iface->nbtsock->sock, bind_address, lp_nbt_port(), 0, 0);
110         if (!NT_STATUS_IS_OK(status)) {
111                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
112                          address, lp_nbt_port(), nt_errstr(status)));
113                 talloc_free(iface);
114                 return status;
115         }
116
117         socket_set_option(iface->nbtsock->sock, "SO_BROADCAST", "1");
118
119         if (strcmp(netmask, "0.0.0.0") == 0) {
120                 DLIST_ADD(nbtsrv->bcast_interface, iface);
121         } else {
122                 DLIST_ADD(nbtsrv->interfaces, iface);
123         }
124
125         return NT_STATUS_OK;
126 }
127
128
129 /*
130   setup our listening sockets on the configured network interfaces
131 */
132 NTSTATUS nbt_startup_interfaces(struct nbt_server *nbtsrv)
133 {
134         int num_interfaces = iface_count();
135         int i;
136         TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
137         NTSTATUS status;
138         const char *primary_address;
139
140         /* the primary address is the address we will return for non-WINS queries 
141            not made on a specific interface */
142         if (num_interfaces > 0) {
143                 primary_address = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_ip(0)));
144         } else {
145                 primary_address = sys_inet_ntoa(interpret_addr2(lp_netbios_name()));
146         }
147
148         status = nbt_add_socket(nbtsrv, 
149                                 "0.0.0.0",
150                                 primary_address,
151                                 talloc_strdup(tmp_ctx, "255.255.255.255"),
152                                 talloc_strdup(tmp_ctx, "0.0.0.0"));
153         NT_STATUS_NOT_OK_RETURN(status);
154
155         for (i=0; i<num_interfaces; i++) {
156                 const char *address = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_ip(i)));
157                 const char *bcast   = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_bcast(i)));
158                 const char *netmask = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_netmask(i)));
159
160                 status = nbt_add_socket(nbtsrv, address, address, bcast, netmask);
161                 NT_STATUS_NOT_OK_RETURN(status);
162         }
163
164         talloc_free(tmp_ctx);
165
166         return NT_STATUS_OK;
167 }