diff options
Diffstat (limited to 'contrib/isc-dhcp/common/socket.c')
-rw-r--r-- | contrib/isc-dhcp/common/socket.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/contrib/isc-dhcp/common/socket.c b/contrib/isc-dhcp/common/socket.c new file mode 100644 index 000000000000..b317ff2ba255 --- /dev/null +++ b/contrib/isc-dhcp/common/socket.c @@ -0,0 +1,256 @@ +/* socket.c + + BSD socket interface code... */ + +/* + * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie + * Enterprises. To learn more about the Internet Software Consortium, + * see ``http://www.vix.com/isc''. To learn more about Vixie + * Enterprises, see ``http://www.vix.com''. + */ + +/* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu). + * This sockopt allows a socket to be bound to a particular interface, + * thus enabling the use of DHCPD on a multihomed host. + * If SO_BINDTODEVICE is defined in your system header files, the use of + * this sockopt will be automatically enabled. + * I have implemented it under Linux; other systems should be doable also. + */ + +#ifndef lint +static char copyright[] = +"$Id: socket.c,v 1.26.2.2 1998/06/25 21:11:32 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +#ifdef USE_SOCKET_FALLBACK +# define USE_SOCKET_SEND +# define if_register_send if_register_fallback +# define send_packet send_fallback +# define if_reinitialize_send if_reinitialize_fallback +#endif + +static int once = 0; + +/* Reinitializes the specified interface after an address change. This + is not required for packet-filter APIs. */ + +#ifdef USE_SOCKET_SEND +void if_reinitialize_send (info) + struct interface_info *info; +{ +#if 0 +#ifndef USE_SOCKET_RECEIVE + once = 0; + close (info -> wfdesc); +#endif + if_register_send (info); +#endif +} +#endif + +#ifdef USE_SOCKET_RECEIVE +void if_reinitialize_receive (info) + struct interface_info *info; +{ +#if 0 + once = 0; + close (info -> rfdesc); + if_register_receive (info); +#endif +} +#endif + +#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) +/* Generic interface registration routine... */ +int if_register_socket (info) + struct interface_info *info; +{ + struct sockaddr_in name; + int sock; + int flag; + +#ifndef SO_BINDTODEVICE + /* Make sure only one interface is registered. */ + if (once) + error ("The standard socket API can only support %s", + "hosts with a single network interface."); + once = 1; +#endif + + /* Set up the address we're going to bind to. */ + name.sin_family = AF_INET; + name.sin_port = local_port; + name.sin_addr.s_addr = INADDR_ANY; + memset (name.sin_zero, 0, sizeof (name.sin_zero)); + + /* Make a socket... */ + if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + error ("Can't create dhcp socket: %m"); + + /* Set the REUSEADDR option so that we don't fail to start if + we're being restarted. */ + flag = 1; + if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&flag, sizeof flag) < 0) + error ("Can't set SO_REUSEADDR option on dhcp socket: %m"); + + /* Set the BROADCAST option so that we can broadcast DHCP responses. */ + if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, + (char *)&flag, sizeof flag) < 0) + error ("Can't set SO_BROADCAST option on dhcp socket: %m"); + + /* Bind the socket to this interface's IP address. */ + if (bind (sock, (struct sockaddr *)&name, sizeof name) < 0) + error ("Can't bind to dhcp address: %m"); + +#ifdef SO_BINDTODEVICE + /* Bind this socket to this interface. */ + if (setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE, + (char *)(info -> ifp), sizeof *(info -> ifp)) < 0) { + error("setting SO_BINDTODEVICE"); + } +#endif + + return sock; +} +#endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE */ + +#ifdef USE_SOCKET_SEND +void if_register_send (info) + struct interface_info *info; +{ +#ifndef USE_SOCKET_RECEIVE + info -> wfdesc = if_register_socket (info); +#else + info -> wfdesc = info -> rfdesc; +#endif + if (!quiet_interface_discovery) + note ("Sending on Socket/%s/%s", + info -> name, + (info -> shared_network ? + info -> shared_network -> name : "unattached")); + +} +#endif /* USE_SOCKET_SEND */ + +#ifdef USE_SOCKET_RECEIVE +void if_register_receive (info) + struct interface_info *info; +{ + /* If we're using the socket API for sending and receiving, + we don't need to register this interface twice. */ + info -> rfdesc = if_register_socket (info); + if (!quiet_interface_discovery) + note ("Listening on Socket/%s/%s", + info -> name, + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} +#endif /* USE_SOCKET_RECEIVE */ + +#ifdef USE_SOCKET_SEND +ssize_t send_packet (interface, packet, raw, len, from, to, hto) + struct interface_info *interface; + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct in_addr from; + struct sockaddr_in *to; + struct hardware *hto; +{ + int result; +#ifdef IGNORE_HOSTUNREACH + int retry = 0; + do { +#endif + result = sendto (interface -> wfdesc, (char *)raw, len, 0, + (struct sockaddr *)to, sizeof *to); +#ifdef IGNORE_HOSTUNREACH + } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) && + result < 0 && + (errno == EHOSTUNREACH || + errno == ECONNREFUSED) && + retry++ < 10); +#endif + return result; +} +#endif /* USE_SOCKET_SEND */ + +#ifdef USE_SOCKET_RECEIVE +ssize_t receive_packet (interface, buf, len, from, hfrom) + struct interface_info *interface; + unsigned char *buf; + size_t len; + struct sockaddr_in *from; + struct hardware *hfrom; +{ + int flen = sizeof *from; + int result; + +#ifdef IGNORE_HOSTUNREACH + int retry = 0; + do { +#endif + result = recvfrom (interface -> rfdesc, (char *)buf, len, 0, + (struct sockaddr *)from, &flen); +#ifdef IGNORE_HOSTUNREACH + } while (result < 0 && + (errno == EHOSTUNREACH || + errno == ECONNREFUSED) && + retry++ < 10); +#endif + return result; +} +#endif /* USE_SOCKET_RECEIVE */ + +#ifdef USE_SOCKET_FALLBACK +/* This just reads in a packet and silently discards it. */ + +void fallback_discard (protocol) + struct protocol *protocol; +{ + char buf [1540]; + struct sockaddr_in from; + int flen = sizeof from; + int status; + struct interface_info *interface = protocol -> local; + + status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0, + (struct sockaddr *)&from, &flen); + if (status < 0) + warn ("fallback_discard: %m"); +} +#endif /* USE_SOCKET_RECEIVE */ |