1/* 2 Unix SMB/CIFS implementation. 3 multiple interface handling 4 Copyright (C) Andrew Tridgell 1992-1998 5 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. 10 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. 15 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. 19*/ 20 21#include "includes.h" 22 23static struct iface_struct *probed_ifaces; 24static int total_probed; 25 26struct in_addr allones_ip; 27struct in_addr loopback_ip; 28 29static struct interface *local_interfaces; 30 31#define ALLONES ((uint32)0xFFFFFFFF) 32#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES)) 33#define MKNETADDR(_IP, _NM) (_IP & _NM) 34 35/**************************************************************************** 36Try and find an interface that matches an ip. If we cannot, return NULL 37 **************************************************************************/ 38static struct interface *iface_find(struct in_addr ip, BOOL CheckMask) 39{ 40 struct interface *i; 41 if (is_zero_ip(ip)) return local_interfaces; 42 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; 47 48 return NULL; 49} 50 51 52/**************************************************************************** 53add an interface to the linked list of interfaces 54****************************************************************************/ 55static void add_interface(struct in_addr ip, struct in_addr nmask) 56{ 57 struct interface *iface; 58 if (iface_find(ip, False)) { 59 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip))); 60 return; 61 } 62 63#if !defined(__s390__) 64 if (ip_equal(nmask, allones_ip)) { 65 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip))); 66 return; 67 } 68#endif 69 70 iface = SMB_MALLOC_P(struct interface); 71 if (!iface) return; 72 73 ZERO_STRUCTPN(iface); 74 75 iface->ip = ip; 76 iface->nmask = nmask; 77 iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr); 78 79 DLIST_ADD(local_interfaces, iface); 80 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))); 84} 85 86 87 88/**************************************************************************** 89interpret a single element from a interfaces= config line 90 91This handles the following different forms: 92 931) wildcard interface name 942) DNS name 953) IP/masklen 964) ip/mask 975) bcast/mask 98****************************************************************************/ 99static void interpret_interface(char *token) 100{ 101 struct in_addr ip, nmask; 102 char *p; 103 int i, added=0; 104 105 zero_ip(&ip); 106 zero_ip(&nmask); 107 108 /* first check if it is an interface name */ 109 for (i=0;i<total_probed;i++) { 110 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) { 111 add_interface(probed_ifaces[i].ip, 112 probed_ifaces[i].netmask); 113 added = 1; 114 } 115 } 116 if (added) return; 117 118 /* maybe it is a DNS name */ 119 p = strchr_m(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; 128 } 129 } 130 DEBUG(2,("can't determine netmask for %s\n", token)); 131 return; 132 } 133 134 /* parse it into an IP address/netmasklength pair */ 135 *p = 0; 136 ip = *interpret_addr2(token); 137 *p++ = '/'; 138 139 if (strlen(p) > 2) { 140 nmask = *interpret_addr2(p); 141 } else { 142 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES)); 143 } 144 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; 152 } 153 } 154 DEBUG(2,("Can't determine ip for broadcast address %s\n", token)); 155 return; 156 } 157 158 add_interface(ip, nmask); 159} 160 161 162/**************************************************************************** 163load the list of network interfaces 164****************************************************************************/ 165void load_interfaces(void) 166{ 167 const char **ptr; 168 int i; 169 struct iface_struct ifaces[MAX_INTERFACES]; 170 171 ptr = lp_interfaces(); 172 173 allones_ip = *interpret_addr2("255.255.255.255"); 174 loopback_ip = *interpret_addr2("127.0.0.1"); 175 176 SAFE_FREE(probed_ifaces); 177 178 /* dump the current interfaces if any */ 179 while (local_interfaces) { 180 struct interface *iface = local_interfaces; 181 DLIST_REMOVE(local_interfaces, local_interfaces); 182 ZERO_STRUCTPN(iface); 183 SAFE_FREE(iface); 184 } 185 186 /* probe the kernel for interfaces */ 187 total_probed = get_interfaces(ifaces, MAX_INTERFACES); 188 189 if (total_probed > 0) { 190 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed); 191 } 192 193 /* if we don't have a interfaces line then use all broadcast capable 194 interfaces except loopback */ 195 if (!ptr || !*ptr || !**ptr) { 196 if (total_probed <= 0) { 197 DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n")); 198 exit(1); 199 } 200 for (i=0;i<total_probed;i++) { 201 if ( 202#if !defined(__s390__) 203 probed_ifaces[i].netmask.s_addr != allones_ip.s_addr && 204#endif 205 probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) { 206 add_interface(probed_ifaces[i].ip, 207 probed_ifaces[i].netmask); 208 } 209 } 210 return; 211 } 212 213 if (ptr) { 214 while (*ptr) { 215 char *ptr_cpy = SMB_STRDUP(*ptr); 216 if (ptr_cpy) { 217 interpret_interface(ptr_cpy); 218 free(ptr_cpy); 219 } 220 ptr++; 221 } 222 } 223 224 if (!local_interfaces) { 225 DEBUG(0,("WARNING: no network interfaces found\n")); 226 } 227} 228 229 230/**************************************************************************** 231return True if the list of probed interfaces has changed 232****************************************************************************/ 233BOOL interfaces_changed(void) 234{ 235 int n; 236 struct iface_struct ifaces[MAX_INTERFACES]; 237 238 n = get_interfaces(ifaces, MAX_INTERFACES); 239 240 if ((n > 0 )&& (n != total_probed || 241 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) { 242 return True; 243 } 244 245 return False; 246} 247 248 249/**************************************************************************** 250 check if an IP is one of mine 251 **************************************************************************/ 252BOOL ismyip(struct in_addr ip) 253{ 254 struct interface *i; 255 for (i=local_interfaces;i;i=i->next) 256 if (ip_equal(i->ip,ip)) return True; 257 return False; 258} 259 260/**************************************************************************** 261 check if a packet is from a local (known) net 262 **************************************************************************/ 263BOOL is_local_net(struct in_addr from) 264{ 265 struct interface *i; 266 for (i=local_interfaces;i;i=i->next) { 267 if((from.s_addr & i->nmask.s_addr) == 268 (i->ip.s_addr & i->nmask.s_addr)) 269 return True; 270 } 271 return False; 272} 273 274/**************************************************************************** 275 how many interfaces do we have 276 **************************************************************************/ 277int iface_count(void) 278{ 279 int ret = 0; 280 struct interface *i; 281 282 for (i=local_interfaces;i;i=i->next) 283 ret++; 284 return ret; 285} 286 287/**************************************************************************** 288 return the Nth interface 289 **************************************************************************/ 290struct interface *get_interface(int n) 291{ 292 struct interface *i; 293 294 for (i=local_interfaces;i && n;i=i->next) 295 n--; 296 297 if (i) return i; 298 return NULL; 299} 300 301/**************************************************************************** 302 return IP of the Nth interface 303 **************************************************************************/ 304struct in_addr *iface_n_ip(int n) 305{ 306 struct interface *i; 307 308 for (i=local_interfaces;i && n;i=i->next) 309 n--; 310 311 if (i) return &i->ip; 312 return NULL; 313} 314 315/**************************************************************************** 316 return bcast of the Nth interface 317 **************************************************************************/ 318struct in_addr *iface_n_bcast(int n) 319{ 320 struct interface *i; 321 322 for (i=local_interfaces;i && n;i=i->next) 323 n--; 324 325 if (i) return &i->bcast; 326 return NULL; 327} 328 329 330/* these 3 functions return the ip/bcast/nmask for the interface 331 most appropriate for the given ip address. If they can't find 332 an appropriate interface they return the requested field of the 333 first known interface. */ 334 335struct in_addr *iface_ip(struct in_addr ip) 336{ 337 struct interface *i = iface_find(ip, True); 338 return(i ? &i->ip : &local_interfaces->ip); 339} 340 341/* 342 return True if a IP is directly reachable on one of our interfaces 343*/ 344BOOL iface_local(struct in_addr ip) 345{ 346 return iface_find(ip, True) ? True : False; 347} 348