1/* socket.c 2 3 BSD socket interface code... */ 4 5/* 6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 7 * Copyright (c) 1995-2003 by Internet Software Consortium 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 * 21 * Internet Systems Consortium, Inc. 22 * 950 Charter Street 23 * Redwood City, CA 94063 24 * <info@isc.org> 25 * http://www.isc.org/ 26 * 27 * This software has been written for Internet Systems Consortium 28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. 29 * To learn more about Internet Systems Consortium, see 30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises, 31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see 32 * ``http://www.nominum.com''. 33 */ 34 35/* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu). 36 * This sockopt allows a socket to be bound to a particular interface, 37 * thus enabling the use of DHCPD on a multihomed host. 38 * If SO_BINDTODEVICE is defined in your system header files, the use of 39 * this sockopt will be automatically enabled. 40 * I have implemented it under Linux; other systems should be doable also. 41 */ 42 43#ifndef lint 44static char copyright[] = 45"$Id: socket.c,v 1.7 2005/08/11 17:13:21 drochner Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n"; 46#endif /* not lint */ 47 48#include "dhcpd.h" 49 50#ifdef USE_SOCKET_FALLBACK 51# if !defined (USE_SOCKET_SEND) 52# define if_register_send if_register_fallback 53# define send_packet send_fallback 54# define if_reinitialize_send if_reinitialize_fallback 55# endif 56#endif 57 58#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK) 59#if 0 60#ifndef USE_SOCKET_RECEIVE 61static int once = 0; 62#endif 63#endif 64#endif 65 66/* Reinitializes the specified interface after an address change. This 67 is not required for packet-filter APIs. */ 68 69#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK) 70void if_reinitialize_send (info) 71 struct interface_info *info; 72{ 73#if 0 74#ifndef USE_SOCKET_RECEIVE 75 once = 0; 76 close (info -> wfdesc); 77#endif 78 if_register_send (info); 79#endif 80} 81#endif 82 83#ifdef USE_SOCKET_RECEIVE 84void if_reinitialize_receive (info) 85 struct interface_info *info; 86{ 87#if 0 88 once = 0; 89 close (info -> rfdesc); 90 if_register_receive (info); 91#endif 92} 93#endif 94 95#if defined (USE_SOCKET_SEND) || \ 96 defined (USE_SOCKET_RECEIVE) || \ 97 defined (USE_SOCKET_FALLBACK) 98/* Generic interface registration routine... */ 99int if_register_socket (info) 100 struct interface_info *info; 101{ 102 struct sockaddr_in name; 103 int sock; 104 int flag; 105#ifndef SMALL 106 char *buf; 107 char *policy = "out bypass"; 108#endif 109 110#if !defined (HAVE_SO_BINDTODEVICE) && !defined (USE_FALLBACK) 111 /* Make sure only one interface is registered. */ 112 if (once) 113 log_fatal ("The standard socket API can only support %s", 114 "hosts with a single network interface."); 115 once = 1; 116#endif 117 118 memset (&name, 0, sizeof (name)); 119 /* Set up the address we're going to bind to. */ 120 name.sin_family = AF_INET; 121 name.sin_port = local_port; 122 name.sin_addr = local_address; 123 124 /* Make a socket... */ 125 if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 126 log_fatal ("Can't create dhcp socket: %m"); 127 128 /* Set the REUSEADDR option so that we don't fail to start if 129 we're being restarted. */ 130 flag = 1; 131 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, 132 (char *)&flag, sizeof flag) < 0) 133 log_fatal ("Can't set SO_REUSEADDR option on dhcp socket: %m"); 134 135#ifndef SMALL 136 /* Set a per-socket IPsec policy to prevent encryption. */ 137 buf = ipsec_set_policy(policy, strlen(policy)); 138 if (setsockopt (sock, IPPROTO_IP, IP_IPSEC_POLICY, buf, 139 ipsec_get_policylen(buf)) < 0 && errno != ENOPROTOOPT) 140 log_fatal ("Can't set IPsec policy on dhcp socket: %m"); 141 free (buf); 142#endif 143 144 /* Set the BROADCAST option so that we can broadcast DHCP responses. 145 We shouldn't do this for fallback devices, and we can detect that 146 a device is a fallback because it has no ifp structure. */ 147 if (info -> ifp && 148 (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, 149 (char *)&flag, sizeof flag) < 0)) 150 log_fatal ("Can't set SO_BROADCAST option on dhcp socket: %m"); 151 152 /* Bind the socket to this interface's IP address. */ 153 if (bind (sock, (struct sockaddr *)&name, sizeof name) < 0) { 154 log_error ("Can't bind to dhcp address: %m"); 155 log_error ("Please make sure there is no other dhcp server"); 156 log_error ("running and that there's no entry for dhcp or"); 157 log_error ("bootp in /etc/inetd.conf. Also make sure you"); 158 log_error ("are not running HP JetAdmin software, which"); 159 log_fatal ("includes a bootp server."); 160 } 161 162#if defined (HAVE_SO_BINDTODEVICE) 163 /* Bind this socket to this interface. */ 164 if (info -> ifp && 165 setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE, 166 (char *)(info -> ifp), sizeof *(info -> ifp)) < 0) { 167 log_fatal ("setsockopt: SO_BINDTODEVICE: %m"); 168 } 169#endif 170 171 return sock; 172} 173#endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */ 174 175#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK) 176void if_register_send (info) 177 struct interface_info *info; 178{ 179#ifndef USE_SOCKET_RECEIVE 180 info -> wfdesc = if_register_socket (info); 181#if defined (USE_SOCKET_FALLBACK) 182 /* Fallback only registers for send, but may need to receive as 183 well. */ 184 info -> rfdesc = info -> wfdesc; 185#endif 186#else 187 info -> wfdesc = info -> rfdesc; 188#endif 189 if (!quiet_interface_discovery) 190 log_info ("Sending on Socket/%s%s%s", 191 info -> name, 192 (info -> shared_network ? "/" : ""), 193 (info -> shared_network ? 194 info -> shared_network -> name : "")); 195} 196 197#if defined (USE_SOCKET_SEND) 198void if_deregister_send (info) 199 struct interface_info *info; 200{ 201#ifndef USE_SOCKET_RECEIVE 202 close (info -> wfdesc); 203#endif 204 info -> wfdesc = -1; 205 206 if (!quiet_interface_discovery) 207 log_info ("Disabling output on Socket/%s%s%s", 208 info -> name, 209 (info -> shared_network ? "/" : ""), 210 (info -> shared_network ? 211 info -> shared_network -> name : "")); 212} 213#endif /* USE_SOCKET_SEND */ 214#endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */ 215 216#ifdef USE_SOCKET_RECEIVE 217void if_register_receive (info) 218 struct interface_info *info; 219{ 220 /* If we're using the socket API for sending and receiving, 221 we don't need to register this interface twice. */ 222 info -> rfdesc = if_register_socket (info); 223 if (!quiet_interface_discovery) 224 log_info ("Listening on Socket/%s%s%s", 225 info -> name, 226 (info -> shared_network ? "/" : ""), 227 (info -> shared_network ? 228 info -> shared_network -> name : "")); 229} 230 231void if_deregister_receive (info) 232 struct interface_info *info; 233{ 234 close (info -> rfdesc); 235 info -> rfdesc = -1; 236 237 if (!quiet_interface_discovery) 238 log_info ("Disabling input on Socket/%s%s%s", 239 info -> name, 240 (info -> shared_network ? "/" : ""), 241 (info -> shared_network ? 242 info -> shared_network -> name : "")); 243} 244#endif /* USE_SOCKET_RECEIVE */ 245 246#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK) 247ssize_t send_packet (interface, packet, raw, len, from, to, hto) 248 struct interface_info *interface; 249 struct packet *packet; 250 struct dhcp_packet *raw; 251 size_t len; 252 struct in_addr from; 253 struct sockaddr_in *to; 254 struct hardware *hto; 255{ 256 int result; 257#ifdef IGNORE_HOSTUNREACH 258 int retry = 0; 259 do { 260#endif 261 result = sendto (interface -> wfdesc, (char *)raw, len, 0, 262 (struct sockaddr *)to, sizeof *to); 263#ifdef IGNORE_HOSTUNREACH 264 } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) && 265 result < 0 && 266 (errno == EHOSTUNREACH || 267 errno == ECONNREFUSED) && 268 retry++ < 10); 269#endif 270 if (result < 0) { 271 log_error ("send_packet: %m"); 272 if (errno == ENETUNREACH) 273 log_error ("send_packet: please consult README file%s", 274 " regarding broadcast address."); 275 } 276 return result; 277} 278#endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */ 279 280#ifdef USE_SOCKET_RECEIVE 281ssize_t receive_packet (interface, buf, len, from, hfrom) 282 struct interface_info *interface; 283 unsigned char *buf; 284 size_t len; 285 struct sockaddr_in *from; 286 struct hardware *hfrom; 287{ 288 SOCKLEN_T flen = sizeof *from; 289 int result; 290 291#ifdef IGNORE_HOSTUNREACH 292 int retry = 0; 293 do { 294#endif 295 result = recvfrom (interface -> rfdesc, (char *)buf, len, 0, 296 (struct sockaddr *)from, &flen); 297#ifdef IGNORE_HOSTUNREACH 298 } while (result < 0 && 299 (errno == EHOSTUNREACH || 300 errno == ECONNREFUSED) && 301 retry++ < 10); 302#endif 303 return result; 304} 305#endif /* USE_SOCKET_RECEIVE */ 306 307#if defined (USE_SOCKET_FALLBACK) 308/* This just reads in a packet and silently discards it. */ 309 310isc_result_t fallback_discard (object) 311 omapi_object_t *object; 312{ 313 char buf [1540]; 314 struct sockaddr_in from; 315 SOCKLEN_T flen = sizeof from; 316 int status; 317 struct interface_info *interface; 318 319 if (object -> type != dhcp_type_interface) 320 return ISC_R_INVALIDARG; 321 interface = (struct interface_info *)object; 322 323 status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0, 324 (struct sockaddr *)&from, &flen); 325#if defined (DEBUG) 326 /* Only report fallback discard errors if we're debugging. */ 327 if (status < 0) { 328 log_error ("fallback_discard: %m"); 329 return ISC_R_UNEXPECTED; 330 } 331#endif 332 return ISC_R_SUCCESS; 333} 334#endif /* USE_SOCKET_FALLBACK */ 335 336#if defined (USE_SOCKET_SEND) 337int can_unicast_without_arp (ip) 338 struct interface_info *ip; 339{ 340 return 0; 341} 342 343int can_receive_unicast_unconfigured (ip) 344 struct interface_info *ip; 345{ 346#if defined (SOCKET_CAN_RECEIVE_UNICAST_UNCONFIGURED) 347 return 1; 348#else 349 return 0; 350#endif 351} 352 353int supports_multiple_interfaces (ip) 354 struct interface_info *ip; 355{ 356#if defined (SO_BINDTODEVICE) 357 return 1; 358#else 359 return 0; 360#endif 361} 362 363/* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise, 364 do not. */ 365 366void maybe_setup_fallback () 367{ 368#if defined (USE_SOCKET_FALLBACK) 369 isc_result_t status; 370 struct interface_info *fbi = (struct interface_info *)0; 371 if (setup_fallback (&fbi, MDL)) { 372 fbi -> wfdesc = if_register_socket (fbi); 373 fbi -> rfdesc = fbi -> wfdesc; 374 log_info ("Sending on Socket/%s%s%s", 375 fbi -> name, 376 (fbi -> shared_network ? "/" : ""), 377 (fbi -> shared_network ? 378 fbi -> shared_network -> name : "")); 379 380 status = omapi_register_io_object ((omapi_object_t *)fbi, 381 if_readsocket, 0, 382 fallback_discard, 0, 0); 383 if (status != ISC_R_SUCCESS) 384 log_fatal ("Can't register I/O handle for %s: %s", 385 fbi -> name, isc_result_totext (status)); 386 interface_dereference (&fbi, MDL); 387 } 388#endif 389} 390#endif /* USE_SOCKET_SEND */ 391