diff options
Diffstat (limited to 'usr.sbin/dhcp/relay/dhcrelay.c')
-rw-r--r-- | usr.sbin/dhcp/relay/dhcrelay.c | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/usr.sbin/dhcp/relay/dhcrelay.c b/usr.sbin/dhcp/relay/dhcrelay.c new file mode 100644 index 00000000000..12e40d2eb50 --- /dev/null +++ b/usr.sbin/dhcp/relay/dhcrelay.c @@ -0,0 +1,359 @@ +/* dhcrelay.c + + DHCP/BOOTP Relay Agent. */ + +/* + * Copyright (c) 1997 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: dhcrelay.c,v 1.1 1998/08/18 03:43:34 deraadt Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +static void usage PROTO ((void)); + +TIME cur_time; +TIME default_lease_time = 43200; /* 12 hours... */ +TIME max_lease_time = 86400; /* 24 hours... */ +struct tree_cache *global_options [256]; + +int log_perror = 1; + +char *path_dhcrelay_pid = _PATH_DHCRELAY_PID; + +#ifdef USE_FALLBACK +struct interface_info fallback_interface; +#endif + +u_int16_t local_port; +u_int16_t remote_port; +int log_priority; + +struct server_list { + struct server_list *next; + struct sockaddr_in to; +} *servers; + +int main (argc, argv, envp) + int argc; + char **argv, **envp; +{ + int i; + struct servent *ent; + struct server_list *sp = (struct server_list *)0; + int no_daemon = 0; + int quiet = 0; + +#ifdef SYSLOG_4_2 + openlog ("dhcrelay", LOG_NDELAY); + log_priority = LOG_DAEMON; +#else + openlog ("dhcrelay", LOG_NDELAY, LOG_DAEMON); +#endif + +#if !(defined (DEBUG) || defined (SYSLOG_4_2)) + setlogmask (LOG_UPTO (LOG_INFO)); +#endif + + for (i = 1; i < argc; i++) { + if (!strcmp (argv [i], "-p")) { + if (++i == argc) + usage (); + local_port = htons (atoi (argv [i])); + debug ("binding to user-specified port %d", + ntohs (local_port)); + } else if (!strcmp (argv [i], "-d")) { + no_daemon = 1; + } else if (!strcmp (argv [i], "-i")) { + struct interface_info *tmp = + ((struct interface_info *) + dmalloc (sizeof *tmp, "specified_interface")); + if (!tmp) + error ("Insufficient memory to %s %s", + "record interface", argv [i]); + if (++i == argc) { + usage (); + } + memset (tmp, 0, sizeof *tmp); + strcpy (tmp -> name, argv [i]); + tmp -> next = interfaces; + tmp -> flags = INTERFACE_REQUESTED; + interfaces = tmp; + } else if (!strcmp (argv [i], "-q")) { + quiet = 1; + quiet_interface_discovery = 1; + } else if (argv [i][0] == '-') { + usage (); + } else { + struct hostent *he; + struct in_addr ia, *iap = (struct in_addr *)0; + if (inet_aton (argv [i], &ia)) { + iap = &ia; + } else { + he = gethostbyname (argv [i]); + if (!he) { + warn ("%s: host unknown", argv [i]); + } else { + iap = ((struct in_addr *) + he -> h_addr_list [0]); + } + } + if (iap) { + sp = (struct server_list *)malloc (sizeof *sp); + if (!sp) + error ("no memory for server.\n"); + sp -> next = servers; + servers = sp; + memcpy (&sp -> to.sin_addr, + iap, sizeof *iap); + } + } + } + + /* Default to the DHCP/BOOTP port. */ + if (!local_port) { + ent = getservbyname ("dhcps", "udp"); + if (!ent) + local_port = htons (67); + else + local_port = ent -> s_port; + endservent (); + } + remote_port = htons (ntohs (local_port) + 1); + + /* We need at least one server. */ + if (!sp) { + usage (); + } + + /* Set up the server sockaddrs. */ + for (sp = servers; sp; sp = sp -> next) { + sp -> to.sin_port = local_port; + sp -> to.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + sp -> to.sin_len = sizeof sp -> to; +#endif + } + + /* Get the current time... */ + GET_TIME (&cur_time); + + /* Discover all the network interfaces. */ + discover_interfaces (DISCOVER_RELAY); + + /* Set up the bootp packet handler... */ + bootp_packet_handler = relay; + + /* Become a daemon... */ + if (!no_daemon) { + int pid; + FILE *pf; + int pfdesc; + + log_perror = 0; + + if ((pid = fork()) < 0) + error ("can't fork daemon: %m"); + else if (pid) + exit (0); + + pfdesc = open (path_dhcrelay_pid, + O_CREAT | O_TRUNC | O_WRONLY, 0644); + + if (pfdesc < 0) { + warn ("Can't create %s: %m", path_dhcrelay_pid); + } else { + pf = fdopen (pfdesc, "w"); + if (!pf) + warn ("Can't fdopen %s: %m", + path_dhcrelay_pid); + else { + fprintf (pf, "%ld\n", (long)getpid ()); + fclose (pf); + } + } + + close (0); + close (1); + close (2); + pid = setsid (); + } + + /* Start dispatching packets and timeouts... */ + dispatch (); + + /*NOTREACHED*/ + return 0; +} + +void relay (ip, packbuf, length, from_port, from, hfrom) + struct interface_info *ip; + u_int8_t *packbuf; + int length; + u_int16_t from_port; + struct iaddr from; + struct hardware *hfrom; +{ + struct dhcp_packet *packet = (struct dhcp_packet *)packbuf; + struct server_list *sp; + struct sockaddr_in to; + struct interface_info *out; + struct hardware hto; + + /* If it's a bootreply, forward it to the client. */ + if (packet -> op == BOOTREPLY) { +#ifndef USE_FALLBACK + if (!(packet -> flags & htons (BOOTP_BROADCAST))) { + to.sin_addr = packet -> yiaddr; + to.sin_port = remote_port; + } else +#endif + { + to.sin_addr.s_addr = htonl (INADDR_BROADCAST); + to.sin_port = remote_port; + } + to.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + to.sin_len = sizeof to; +#endif + + memcpy (hto.haddr, packet -> chaddr, + (packet -> hlen > sizeof hto.haddr + ? sizeof hto.haddr + : packet -> hlen)); + hto.htype = packet -> htype; + + /* Find the interface that corresponds to the giaddr + in the packet. */ + for (out = interfaces; out; out = out -> next) { + if (!memcmp (&out -> primary_address, + &packet -> giaddr, + sizeof packet -> giaddr)) + break; + } + if (!out) { + warn ("packet to bogus giaddr %s.\n", + inet_ntoa (packet -> giaddr)); + return; + } + + if (send_packet (out, + (struct packet *)0, + packet, length, out -> primary_address, + &to, &hto) < 0) + debug ("sendpkt: %m"); + else + debug ("forwarded BOOTREPLY for %s to %s", + print_hw_addr (packet -> htype, packet -> hlen, + packet -> chaddr), + inet_ntoa (to.sin_addr)); + + return; + } + + /* If giaddr is set on a BOOTREQUEST, ignore it - it's already + been gatewayed. */ + if (packet -> giaddr.s_addr) { + note ("ignoring BOOTREQUEST with giaddr of %s\n", + inet_ntoa (packet -> giaddr)); + return; + } + + /* Set the giaddr so the server can figure out what net it's + from and so that we can later forward the response to the + correct net. */ + packet -> giaddr = ip -> primary_address; + + /* Otherwise, it's a BOOTREQUEST, so forward it to all the + servers. */ + for (sp = servers; sp; sp = sp -> next) { + if ( +#ifdef USE_FALLBACK + send_fallback (&fallback_interface, + (struct packet *)0, + packet, length, ip -> primary_address, + &sp -> to, (struct hardware *)0) +#else + send_packet (interfaces, + (struct packet *)0, + packet, length, ip -> primary_address, + &sp -> to, (struct hardware *)0) +#endif + < 0) { + debug ("send_packet: %m"); + } else { + debug ("forwarded BOOTREQUEST for %s to %s", + print_hw_addr (packet -> htype, packet -> hlen, + packet -> chaddr), + inet_ntoa (sp -> to.sin_addr)); + } + } + +} + +static void usage () +{ + error ("Usage: dhcrelay [-c] [-p <port>] [server1 [... serverN]]"); +} + +void cleanup () +{ +} + +int write_lease (lease) + struct lease *lease; +{ + return 1; +} + +int commit_leases () +{ + return 1; +} + +void bootp (packet) + struct packet *packet; +{ +} + +void dhcp (packet) + struct packet *packet; +{ +} |