socket.c
来自「open source dhcp server client etc...」· C语言 代码 · 共 378 行
C
378 行
/* socket.c BSD socket interface code... *//* * Copyright (c) 1995-2000 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 in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about the Internet Software Consortium, see * ``http://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.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 lintstatic char copyright[] ="$Id: socket.c,v 1.55 2000/09/30 01:24:55 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";#endif /* not lint */#include "dhcpd.h"#ifdef USE_SOCKET_FALLBACK# if !defined (USE_SOCKET_SEND)# define if_register_send if_register_fallback# define send_packet send_fallback# define if_reinitialize_send if_reinitialize_fallback# endif#endifstatic int once = 0;/* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)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_RECEIVEvoid 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) || \ defined (USE_SOCKET_FALLBACK)/* Generic interface registration routine... */int if_register_socket (info) struct interface_info *info;{ struct sockaddr_in name; int sock; int flag;#if !defined (HAVE_SO_BINDTODEVICE) && !defined (USE_FALLBACK) /* Make sure only one interface is registered. */ if (once) log_fatal ("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 = local_address; memset (name.sin_zero, 0, sizeof (name.sin_zero)); /* Make a socket... */ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) log_fatal ("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) log_fatal ("Can't set SO_REUSEADDR option on dhcp socket: %m"); /* Set the BROADCAST option so that we can broadcast DHCP responses. We shouldn't do this for fallback devices, and we can detect that a device is a fallback because it has no ifp structure. */ if (info -> ifp && (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *)&flag, sizeof flag) < 0)) log_fatal ("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) { log_error ("Can't bind to dhcp address: %m"); log_error ("Please make sure there is no other dhcp server"); log_error ("running and that there's no entry for dhcp or"); log_error ("bootp in /etc/inetd.conf. Also make sure you"); log_error ("are not running HP JetAdmin software, which"); log_fatal ("includes a bootp server."); }#if defined (HAVE_SO_BINDTODEVICE) /* Bind this socket to this interface. */ if (info -> ifp && setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)(info -> ifp), sizeof *(info -> ifp)) < 0) { log_fatal ("setsockopt: SO_BINDTODEVICE: %m"); }#endif return sock;}#endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)void if_register_send (info) struct interface_info *info;{#ifndef USE_SOCKET_RECEIVE info -> wfdesc = if_register_socket (info);#if defined (USE_SOCKET_FALLBACK) /* Fallback only registers for send, but may need to receive as well. */ info -> rfdesc = info -> wfdesc;#endif#else info -> wfdesc = info -> rfdesc;#endif if (!quiet_interface_discovery) log_info ("Sending on Socket/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : ""));}#if defined (USE_SOCKET_SEND)void if_deregister_send (info) struct interface_info *info;{#ifndef USE_SOCKET_RECEIVE close (info -> wfdesc);#endif info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on Socket/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : ""));}#endif /* USE_SOCKET_SEND */#endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */#ifdef USE_SOCKET_RECEIVEvoid 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) log_info ("Listening on Socket/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : ""));}void if_deregister_receive (info) struct interface_info *info;{ close (info -> rfdesc); info -> rfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling input on Socket/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : ""));}#endif /* USE_SOCKET_RECEIVE */#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)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 if (result < 0) { log_error ("send_packet: %m"); if (errno == ENETUNREACH) log_error ("send_packet: please consult README file%s", " regarding broadcast address."); } return result;}#endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */#ifdef USE_SOCKET_RECEIVEssize_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;{ SOCKLEN_T 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 */#if defined (USE_SOCKET_FALLBACK)/* This just reads in a packet and silently discards it. */isc_result_t fallback_discard (object) omapi_object_t *object;{ char buf [1540]; struct sockaddr_in from; SOCKLEN_T flen = sizeof from; int status; struct interface_info *interface; if (object -> type != dhcp_type_interface) return ISC_R_INVALIDARG; interface = (struct interface_info *)object; status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0, (struct sockaddr *)&from, &flen); if (status < 0) { log_error ("fallback_discard: %m"); return ISC_R_UNEXPECTED; } return ISC_R_SUCCESS;}#endif /* USE_SOCKET_FALLBACK */#if defined (USE_SOCKET_SEND)int can_unicast_without_arp (ip) struct interface_info *ip;{ return 0;}int can_receive_unicast_unconfigured (ip) struct interface_info *ip;{#if defined (SOCKET_CAN_RECEIVE_UNICAST_UNCONFIGURED) return 1;#else return 0;#endif}int supports_multiple_interfaces (ip) struct interface_info *ip;{#if defined (SO_BINDTODEVICE) return 1;#else return 0;#endif}/* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise, do not. */void maybe_setup_fallback (){#if defined (USE_SOCKET_FALLBACK) isc_result_t status; struct interface_info *fbi = (struct interface_info *)0; if (setup_fallback (&fbi, MDL)) { fbi -> wfdesc = if_register_socket (fbi); fbi -> rfdesc = fbi -> wfdesc; log_info ("Sending on Socket/%s%s%s", fbi -> name, (fbi -> shared_network ? "/" : ""), (fbi -> shared_network ? fbi -> shared_network -> name : "")); status = omapi_register_io_object ((omapi_object_t *)fbi, if_readsocket, 0, fallback_discard, 0, 0); if (status != ISC_R_SUCCESS) log_fatal ("Can't register I/O handle for %s: %s", fbi -> name, isc_result_totext (status)); interface_dereference (&fbi, MDL); }#endif}#endif /* USE_SOCKET_SEND */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?