if we are adding a new sambaAccount, make sure that we add a
[Samba.git] / source / lib / interface.c
blob2e67b4a4a674927bb2f76da56b8a54120435cb40
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 multiple interface handling
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 static struct iface_struct *probed_ifaces;
25 static int total_probed;
27 struct in_addr allones_ip;
28 struct in_addr loopback_ip;
30 static struct interface *local_interfaces = NULL;
32 #define ALLONES ((uint32)0xFFFFFFFF)
33 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
34 #define MKNETADDR(_IP, _NM) (_IP & _NM)
36 /****************************************************************************
37 Try and find an interface that matches an ip. If we cannot, return NULL
38 **************************************************************************/
39 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
41 struct interface *i;
42 if (is_zero_ip(ip))
43 return local_interfaces;
45 for (i=local_interfaces;i;i=i->next)
46 if (CheckMask) {
47 if (same_net(i->ip,ip,i->nmask)) return i;
48 } else if ((i->ip).s_addr == ip.s_addr) return i;
50 return NULL;
54 /****************************************************************************
55 add an interface to the linked list of interfaces
56 ****************************************************************************/
57 static void add_interface(struct in_addr ip, struct in_addr nmask)
59 struct interface *iface;
60 if (iface_find(ip, False)) {
61 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
62 return;
65 if (ip_equal(nmask, allones_ip)) {
66 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
67 return;
70 iface = (struct interface *)malloc(sizeof(*iface));
71 if (!iface) return;
73 ZERO_STRUCTPN(iface);
75 iface->ip = ip;
76 iface->nmask = nmask;
77 iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
79 DLIST_ADD(local_interfaces, iface);
81 DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
82 DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
83 DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
88 /****************************************************************************
89 interpret a single element from a interfaces= config line
91 This handles the following different forms:
93 1) wildcard interface name
94 2) DNS name
95 3) IP/masklen
96 4) ip/mask
97 5) bcast/mask
98 ****************************************************************************/
99 static void interpret_interface(char *token)
101 struct in_addr ip, nmask;
102 char *p;
103 int i, added=0;
105 zero_ip(&ip);
106 zero_ip(&nmask);
108 /* first check if it is an interface name */
109 for (i=0;i<total_probed;i++) {
110 if (ms_fnmatch(token, probed_ifaces[i].name) == 0) {
111 add_interface(probed_ifaces[i].ip,
112 probed_ifaces[i].netmask);
113 added = 1;
116 if (added) return;
118 /* maybe it is a DNS name */
119 p = strchr(token,'/');
120 if (!p) {
121 ip = *interpret_addr2(token);
122 for (i=0;i<total_probed;i++) {
123 if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
124 !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
125 add_interface(probed_ifaces[i].ip,
126 probed_ifaces[i].netmask);
127 return;
130 DEBUG(2,("can't determine netmask for %s\n", token));
131 return;
134 /* parse it into an IP address/netmasklength pair */
135 *p++ = 0;
137 ip = *interpret_addr2(token);
139 if (strlen(p) > 2) {
140 nmask = *interpret_addr2(p);
141 } else {
142 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
145 /* maybe the first component was a broadcast address */
146 if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
147 ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
148 for (i=0;i<total_probed;i++) {
149 if (same_net(ip, probed_ifaces[i].ip, nmask)) {
150 add_interface(probed_ifaces[i].ip, nmask);
151 return;
154 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
155 return;
158 add_interface(ip, nmask);
162 /****************************************************************************
163 load the list of network interfaces
164 ****************************************************************************/
165 void load_interfaces(void)
167 char *ptr;
168 fstring token;
169 int i;
170 struct iface_struct ifaces[MAX_INTERFACES];
172 ptr = lp_interfaces();
174 allones_ip = *interpret_addr2("255.255.255.255");
175 loopback_ip = *interpret_addr2("127.0.0.1");
177 SAFE_FREE(probed_ifaces);
179 /* dump the current interfaces if any */
180 while (local_interfaces) {
181 struct interface *iface = local_interfaces;
182 DLIST_REMOVE(local_interfaces, local_interfaces);
183 ZERO_STRUCTPN(iface);
184 SAFE_FREE(iface);
187 /* probe the kernel for interfaces */
188 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
190 if (total_probed > 0) {
191 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
194 /* if we don't have a interfaces line then use all broadcast capable
195 interfaces except loopback */
196 if (!ptr || !*ptr) {
197 if (total_probed <= 0) {
198 DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
199 exit(1);
201 for (i=0;i<total_probed;i++) {
202 if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
203 probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
204 add_interface(probed_ifaces[i].ip,
205 probed_ifaces[i].netmask);
208 return;
211 while (next_token(&ptr,token,NULL,sizeof(token))) {
212 interpret_interface(token);
215 if (!local_interfaces) {
216 DEBUG(0,("WARNING: no network interfaces found\n"));
221 /****************************************************************************
222 return True if the list of probed interfaces has changed
223 ****************************************************************************/
224 BOOL interfaces_changed(void)
226 int n;
227 struct iface_struct ifaces[MAX_INTERFACES];
229 n = get_interfaces(ifaces, MAX_INTERFACES);
231 if ((n > 0 )&& (n != total_probed ||
232 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
233 return True;
236 return False;
240 /****************************************************************************
241 check if an IP is one of mine
242 **************************************************************************/
243 BOOL ismyip(struct in_addr ip)
245 struct interface *i;
246 for (i=local_interfaces;i;i=i->next)
247 if (ip_equal(i->ip,ip)) return True;
248 return False;
251 /****************************************************************************
252 check if a packet is from a local (known) net
253 **************************************************************************/
254 BOOL is_local_net(struct in_addr from)
256 struct interface *i;
257 for (i=local_interfaces;i;i=i->next) {
258 if((from.s_addr & i->nmask.s_addr) ==
259 (i->ip.s_addr & i->nmask.s_addr))
260 return True;
262 return False;
265 /****************************************************************************
266 how many interfaces do we have
267 **************************************************************************/
268 int iface_count(void)
270 int ret = 0;
271 struct interface *i;
273 for (i=local_interfaces;i;i=i->next)
274 ret++;
275 return ret;
278 /****************************************************************************
279 True if we have two or more interfaces.
280 **************************************************************************/
281 BOOL we_are_multihomed(void)
283 static int multi = -1;
285 if(multi == -1)
286 multi = (iface_count() > 1 ? True : False);
288 return multi;
291 /****************************************************************************
292 return the Nth interface
293 **************************************************************************/
294 struct interface *get_interface(int n)
296 struct interface *i;
298 for (i=local_interfaces;i && n;i=i->next)
299 n--;
301 if (i) return i;
302 return NULL;
305 /****************************************************************************
306 return IP of the Nth interface
307 **************************************************************************/
308 struct in_addr *iface_n_ip(int n)
310 struct interface *i;
312 for (i=local_interfaces;i && n;i=i->next)
313 n--;
315 if (i) return &i->ip;
316 return NULL;
319 /****************************************************************************
320 return bcast of the Nth interface
321 **************************************************************************/
322 struct in_addr *iface_n_bcast(int n)
324 struct interface *i;
326 for (i=local_interfaces;i && n;i=i->next)
327 n--;
329 if (i) return &i->bcast;
330 return NULL;
334 /****************************************************************************
335 this function provides a simple hash of the configured interfaces. It is
336 used to detect a change in interfaces to tell us whether to discard
337 the current wins.dat file.
338 Note that the result is independent of the order of the interfaces
339 **************************************************************************/
340 unsigned iface_hash(void)
342 unsigned ret = 0;
343 struct interface *i;
345 for (i=local_interfaces;i;i=i->next) {
346 unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip));
347 unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask));
348 ret ^= (x1 ^ x2);
351 return ret;
355 /* these 3 functions return the ip/bcast/nmask for the interface
356 most appropriate for the given ip address. If they can't find
357 an appropriate interface they return the requested field of the
358 first known interface. */
360 struct in_addr *iface_bcast(struct in_addr ip)
362 struct interface *i = iface_find(ip, True);
363 return(i ? &i->bcast : &local_interfaces->bcast);
366 struct in_addr *iface_ip(struct in_addr ip)
368 struct interface *i = iface_find(ip, True);
369 return(i ? &i->ip : &local_interfaces->ip);