r1383: sync from 3.0 tree
[Samba.git] / source / lib / interface.c
blobadf9ca34381e45d723450fe6cbf2b816e13d73db
1 /*
2 Unix SMB/CIFS implementation.
3 multiple interface handling
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 static struct iface_struct *probed_ifaces;
24 static int total_probed;
26 struct in_addr allones_ip;
27 struct in_addr loopback_ip;
29 static struct interface *local_interfaces;
31 #define ALLONES ((uint32)0xFFFFFFFF)
32 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
33 #define MKNETADDR(_IP, _NM) (_IP & _NM)
35 /****************************************************************************
36 Try and find an interface that matches an ip. If we cannot, return NULL
37 **************************************************************************/
38 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
40 struct interface *i;
41 if (is_zero_ip(ip)) return local_interfaces;
43 for (i=local_interfaces;i;i=i->next)
44 if (CheckMask) {
45 if (same_net(i->ip,ip,i->nmask)) return i;
46 } else if ((i->ip).s_addr == ip.s_addr) return i;
48 return NULL;
52 /****************************************************************************
53 add an interface to the linked list of interfaces
54 ****************************************************************************/
55 static void add_interface(struct in_addr ip, struct in_addr nmask)
57 struct interface *iface;
58 if (iface_find(ip, False)) {
59 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
60 return;
63 if (ip_equal(nmask, allones_ip)) {
64 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
65 return;
68 iface = (struct interface *)malloc(sizeof(*iface));
69 if (!iface) return;
71 ZERO_STRUCTPN(iface);
73 iface->ip = ip;
74 iface->nmask = nmask;
75 iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
77 DLIST_ADD(local_interfaces, iface);
79 DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
80 DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
81 DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
86 /****************************************************************************
87 interpret a single element from a interfaces= config line
89 This handles the following different forms:
91 1) wildcard interface name
92 2) DNS name
93 3) IP/masklen
94 4) ip/mask
95 5) bcast/mask
96 ****************************************************************************/
97 static void interpret_interface(char *token)
99 struct in_addr ip, nmask;
100 char *p;
101 int i, added=0;
103 zero_ip(&ip);
104 zero_ip(&nmask);
106 /* first check if it is an interface name */
107 for (i=0;i<total_probed;i++) {
108 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
109 add_interface(probed_ifaces[i].ip,
110 probed_ifaces[i].netmask);
111 added = 1;
114 if (added) return;
116 /* maybe it is a DNS name */
117 p = strchr_m(token,'/');
118 if (!p) {
119 ip = *interpret_addr2(token);
120 for (i=0;i<total_probed;i++) {
121 if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
122 !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
123 add_interface(probed_ifaces[i].ip,
124 probed_ifaces[i].netmask);
125 return;
128 DEBUG(2,("can't determine netmask for %s\n", token));
129 return;
132 /* parse it into an IP address/netmasklength pair */
133 *p = 0;
134 ip = *interpret_addr2(token);
135 *p++ = '/';
137 if (strlen(p) > 2) {
138 nmask = *interpret_addr2(p);
139 } else {
140 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
143 /* maybe the first component was a broadcast address */
144 if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
145 ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
146 for (i=0;i<total_probed;i++) {
147 if (same_net(ip, probed_ifaces[i].ip, nmask)) {
148 add_interface(probed_ifaces[i].ip, nmask);
149 return;
152 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
153 return;
156 add_interface(ip, nmask);
160 /****************************************************************************
161 load the list of network interfaces
162 ****************************************************************************/
163 void load_interfaces(void)
165 const char **ptr;
166 int i;
167 struct iface_struct ifaces[MAX_INTERFACES];
169 ptr = lp_interfaces();
171 allones_ip = *interpret_addr2("255.255.255.255");
172 loopback_ip = *interpret_addr2("127.0.0.1");
174 SAFE_FREE(probed_ifaces);
176 /* dump the current interfaces if any */
177 while (local_interfaces) {
178 struct interface *iface = local_interfaces;
179 DLIST_REMOVE(local_interfaces, local_interfaces);
180 ZERO_STRUCTPN(iface);
181 SAFE_FREE(iface);
184 /* probe the kernel for interfaces */
185 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
187 if (total_probed > 0) {
188 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
191 /* if we don't have a interfaces line then use all broadcast capable
192 interfaces except loopback */
193 if (!ptr || !*ptr || !**ptr) {
194 if (total_probed <= 0) {
195 DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
196 exit(1);
198 for (i=0;i<total_probed;i++) {
199 if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
200 probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
201 add_interface(probed_ifaces[i].ip,
202 probed_ifaces[i].netmask);
205 return;
208 if (ptr) {
209 while (*ptr) {
210 char *ptr_cpy = strdup(*ptr);
211 if (ptr_cpy) {
212 interpret_interface(ptr_cpy);
213 free(ptr_cpy);
215 ptr++;
219 if (!local_interfaces) {
220 DEBUG(0,("WARNING: no network interfaces found\n"));
225 /****************************************************************************
226 return True if the list of probed interfaces has changed
227 ****************************************************************************/
228 BOOL interfaces_changed(void)
230 int n;
231 struct iface_struct ifaces[MAX_INTERFACES];
233 n = get_interfaces(ifaces, MAX_INTERFACES);
235 if ((n > 0 )&& (n != total_probed ||
236 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
237 return True;
240 return False;
244 /****************************************************************************
245 check if an IP is one of mine
246 **************************************************************************/
247 BOOL ismyip(struct in_addr ip)
249 struct interface *i;
250 for (i=local_interfaces;i;i=i->next)
251 if (ip_equal(i->ip,ip)) return True;
252 return False;
255 /****************************************************************************
256 check if a packet is from a local (known) net
257 **************************************************************************/
258 BOOL is_local_net(struct in_addr from)
260 struct interface *i;
261 for (i=local_interfaces;i;i=i->next) {
262 if((from.s_addr & i->nmask.s_addr) ==
263 (i->ip.s_addr & i->nmask.s_addr))
264 return True;
266 return False;
269 /****************************************************************************
270 how many interfaces do we have
271 **************************************************************************/
272 int iface_count(void)
274 int ret = 0;
275 struct interface *i;
277 for (i=local_interfaces;i;i=i->next)
278 ret++;
279 return ret;
282 /****************************************************************************
283 return the Nth interface
284 **************************************************************************/
285 struct interface *get_interface(int n)
287 struct interface *i;
289 for (i=local_interfaces;i && n;i=i->next)
290 n--;
292 if (i) return i;
293 return NULL;
296 /****************************************************************************
297 return IP of the Nth interface
298 **************************************************************************/
299 struct in_addr *iface_n_ip(int n)
301 struct interface *i;
303 for (i=local_interfaces;i && n;i=i->next)
304 n--;
306 if (i) return &i->ip;
307 return NULL;
310 /****************************************************************************
311 return bcast of the Nth interface
312 **************************************************************************/
313 struct in_addr *iface_n_bcast(int n)
315 struct interface *i;
317 for (i=local_interfaces;i && n;i=i->next)
318 n--;
320 if (i) return &i->bcast;
321 return NULL;
325 /* these 3 functions return the ip/bcast/nmask for the interface
326 most appropriate for the given ip address. If they can't find
327 an appropriate interface they return the requested field of the
328 first known interface. */
330 struct in_addr *iface_ip(struct in_addr ip)
332 struct interface *i = iface_find(ip, True);
333 return(i ? &i->ip : &local_interfaces->ip);
337 return True if a IP is directly reachable on one of our interfaces
339 BOOL iface_local(struct in_addr ip)
341 return iface_find(ip, True) ? True : False;