in.rarpd.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
* under license from the Regents of the University of California.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* rarpd.c Reverse-ARP server.
* Refer to RFC 903 "A Reverse Address Resolution Protocol".
*/
#define _REENTRANT
#include <thread.h>
#include <synch.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <dirent.h>
#include <syslog.h>
#include <signal.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/if_ether.h>
#include <stropts.h>
#include <libinetutil.h>
#include <net/if_types.h>
#define MAXIFS 256
/*
* Logical network devices
*/
struct ifdev {
int lunit;
};
/*
* Physical network device
*/
struct rarpdev {
int unit;
int fd;
int ifaddrlen; /* mac address length */
int ifsaplen; /* indicates dlsap format */
int ifrarplen; /* size of rarp data packet */
};
struct rarpreply {
};
static struct rarpreply *delay_list;
static sema_t delay_sema;
static mutex_t delay_mutex;
static mutex_t debug_mutex;
static struct rarpdev *rarpdev_head;
/*
* Globals initialized before multi-threading
*/
static char *cmdname; /* command name from argv[0] */
static int dflag = 0; /* enable diagnostics */
static int aflag = 0; /* start rarpd on all interfaces */
static char *alarmmsg; /* alarm() error message */
static long pc_name_max; /* pathconf maximum path name */
static void getintf(void);
static void init_rarpdev(struct rarpdev *);
static void do_rarp(void *);
uchar_t *);
static void do_delay_write(void *);
static int rarp_write(int, struct rarpreply *);
static void sigalarm(int);
static int strioctl(int, int, int, int, char *);
static void usage();
static void syserr(char *);
static void error(char *, ...);
static void debug(char *, ...);
extern int optind;
extern char *optarg;
int
{
int c;
int i;
switch (c) {
case 'a':
aflag = 1;
break;
case 'd':
dflag = 1;
break;
default:
usage();
}
}
usage();
/* NOTREACHED */
}
if (!dflag) {
/*
* Background
*/
switch (fork()) {
case -1: /* error */
syserr("fork");
/*NOTREACHED*/
case 0: /* child */
break;
default: /* parent */
return (0);
}
for (i = 0; i < 3; i++) {
(void) close(i);
}
(void) dup2(0, 1);
(void) dup2(0, 2);
/*
* Detach terminal
*/
if (setsid() < 0)
syserr("setsid");
}
syserr("setrlimit");
/*
* Look up the maximum name length of the BOOTDIR, it may not
* exist so use /, if that fails use a reasonable sized buffer.
*/
pc_name_max = 255;
}
}
if (aflag) {
/*
* Get each interface name and load rarpdev list
*/
getintf();
} else {
/*
* Load specified device as only element of the list
*/
sizeof (struct rarpdev));
if (rarpdev_head == NULL) {
error("out of memory");
}
error("out of memory");
}
error("invalid interface specification");
}
if (ifsp.ifsp_lunvalid) {
} else
sizeof (rarpdev_head->device));
}
/*
* Initialize each rarpdev
*/
}
/*
* Start delayed processing thread
*/
THR_NEW_LWP, NULL);
/*
* Start RARP processing for each device
*/
THR_NEW_LWP, NULL);
}
}
/*
* Exit main() thread
*/
return (0);
}
static void
getintf(void)
{
int fd;
int numifs;
unsigned bufsize;
/*
* Open the IP provider.
*/
/*
* Ask IP for the list of configured interfaces.
*/
}
error("out of memory");
}
syserr("SIOCGIFCONF");
/*
* Initialize a rarpdev for each interface
*/
syserr("ioctl SIOCGIFFLAGS");
exit(1);
}
continue;
error("ifparse_ifspec failed");
/*
* Look for an existing device for logical interfaces
*/
error("out of memory");
rarpdev_head = rdev;
}
error("out of memory");
if (ifsp.ifsp_lunvalid) {
} else
}
}
static struct rarpdev *
{
return (rdev);
}
return (NULL);
}
static void
{
char *dev;
int unit;
/*
* Open datalink provider and get our mac address.
*/
/*
* rarp_open may fail on certain types of interfaces
*/
return;
}
/*
* Get the IP address and netmask from directory service for
* each logical interface.
*/
/*
* If lunit == -1 then this is the primary interface name
*/
} else {
}
/*
* Use IP address of the interface.
*/
}
}
static void
{
char *cause;
union DL_primitives *dlp;
/*
* to be malloc'ed.
*/
error("unsupported media");
syserr("malloc");
if (dflag) {
debug("starting rarp service on device %s%d address %s",
}
}
/*
* read RARP packets and respond to them.
*/
for (;;) {
flags = 0;
syserr("getmsg");
/*
* Validate DL_UNITDATA_IND.
*/
/* LINTED pointer */
cause = "missing control part of message";
cause = "short control part of message";
cause = "not unitdata_ind";
cause = "MORECTL flag";
cause = "MOREDATA flag";
cause = "short unitdata_ind";
cause = "short arp";
cause = "hrd";
cause = "pro";
cause = "hln";
cause = "pln";
if (cause) {
if (dflag)
debug("receive check failed: cause: %s",
cause);
continue;
}
/*
* Good request.
* Pick out the mac source address of this RARP request.
*/
/*
* Handle the request.
*/
case REVARP_REQUEST:
break;
case ARPOP_REQUEST:
break;
case REVARP_REPLY:
if (dflag)
debug("REVARP_REPLY ignored");
break;
case ARPOP_REPLY:
if (dflag)
debug("ARPOP_REPLY ignored");
break;
default:
if (dflag)
break;
}
}
/* NOTREACHED */
}
/*
* Reverse address determination and allocation code.
*/
static void
{
if (dflag) {
}
}
/*
* third party lookups are rare and wonderful
*/
if (dflag)
debug("weird (3rd party lookup)");
}
/*
* fill in given parts of reply packet
*/
/*
* If a good address is stored in our lookup tables, return it
* immediately or after a delay. Store it our kernel's ARP cache.
*/
return;
if (dflag) {
}
error("out of memory");
/*
* Create rarpreply structure.
*/
/*
* If this is diskless and we're not its bootserver, let the
* bootserver reply first by delaying a while.
*/
if (dflag)
debug("immediate reply sent");
} else {
}
}
/*
* Download an ARP entry into our kernel.
*/
static void
{
struct sockaddr_in *sin;
int fd;
/*
* Common part of query or set
*/
/*
* Open the IP provider.
*/
/*
* Set the entry
*/
(char *)&ar);
(char *)&ar) < 0)
syserr("SIOCSXARP");
}
/*
* The RARP spec says we must be able to process ARP requests,
* even through the packet type is RARP. Let's hope this feature
* is not heavily used.
*/
static void
{
int ret;
if (dflag)
debug("ARPOP_REQUEST");
break;
}
return;
/*
* Create rarp reply structure.
*/
error("out of memory");
if (ret < 0)
error("rarp_write error");
}
/*
* OPEN the datalink provider device, ATTACH to the unit,
* and BIND to the revarp type.
* Return the resulting descriptor.
*
* MT-UNSAFE
*/
static int
{
register int fd;
union DL_primitives *dlp;
int flags;
/*
* Prefix the device name with "/dev/" if it doesn't
* start with a "/" .
*/
if (*device == '/')
else
/*
* Open the datalink provider.
*/
/*
* Issue DL_INFO_REQ and check DL_INFO_ACK for sanity.
*/
/* LINTED pointer */
syserr("putmsg");
alarmmsg = "DL_INFO_REQ failed: timeout waiting for DL_INFO_ACK";
(void) alarm(10);
flags = 0;
syserr("getmsg");
(void) alarm(0);
/*
* Validate DL_INFO_ACK reply.
*/
error("DL_INFO_REQ failed: short reply to DL_INFO_REQ");
error("DL_INFO_REQ failed: dl_primitive 0x%lx received",
dlp->dl_primitive);
error("DL_INFO_REQ failed: short info_ack: %d bytes",
error("DL_INFO_ACK: incompatible version: %lu",
if (dflag)
"%s%d DL_INFO_ACK: incompatible dl_sap_length: %ld",
return (-1);
}
if (dflag)
"%s%d DL_INFO_ACK: incompatible dl_service_mode: 0x%lx",
return (-1);
}
/*
* Issue DL_ATTACH_REQ.
*/
/* LINTED pointer */
syserr("putmsg");
alarmmsg = "DL_ATTACH_REQ failed: timeout waiting for DL_OK_ACK";
(void) alarm(10);
flags = 0;
syserr("getmsg");
(void) alarm(0);
/*
* Validate DL_OK_ACK reply.
*/
error("DL_ATTACH_REQ failed: short reply to attach request");
error("DL_ATTACH_REQ failed: dl_errno %lu unix_errno %lu",
error("DL_ATTACH_REQ failed: dl_primitive 0x%lx received",
dlp->dl_primitive);
error("attach failed: short ok_ack: %d bytes",
/*
* Issue DL_BIND_REQ.
*/
/* LINTED pointer */
syserr("putmsg");
alarmmsg = "DL_BIND_REQ failed: timeout waiting for DL_BIND_ACK";
(void) alarm(10);
flags = 0;
syserr("getmsg");
(void) alarm(0);
/*
* Validate DL_BIND_ACK reply.
*/
error("DL_BIND_REQ failed: short reply");
error("DL_BIND_REQ failed: dl_errno %lu unix_errno %lu",
error("DL_BIND_REQ failed: dl_primitive 0x%lx received",
dlp->dl_primitive);
"DL_BIND_REQ failed: short bind acknowledgement received");
"DL_BIND_REQ failed: returned dl_sap %lu != requested sap %d",
/*
* Issue DL_PHYS_ADDR_REQ to get our local mac address.
*/
/* LINTED pointer */
syserr("putmsg");
alarmmsg =
"DL_PHYS_ADDR_REQ failed: timeout waiting for DL_PHYS_ADDR_ACK";
(void) alarm(10);
flags = 0;
syserr("getmsg");
(void) alarm(0);
/*
* Validate DL_PHYS_ADDR_ACK reply.
*/
error("DL_PHYS_ADDR_REQ failed: short reply");
error("DL_PHYS_ADDR_REQ failed: dl_errno %lu unix_errno %lu",
error("DL_PHYS_ADDR_REQ failed: dl_primitive 0x%lx received",
dlp->dl_primitive);
error("DL_PHYS_ADDR_REQ failed: short ack received");
if (dflag)
"%s%d DL_PHYS_ADDR_ACK failed: incompatible dl_addr_length: %lu",
return (-1);
}
/*
* Save our mac address.
*/
if (dflag)
return (-1);
}
if (dflag) {
}
}
return (fd);
}
/* ARGSUSED */
static void
do_delay_write(void *buf)
{
int err;
for (;;) {
continue;
error("do_delay_write: sema_wait failed");
}
(void) mutex_lock(&delay_mutex);
rrp = delay_list;
(void) mutex_unlock(&delay_mutex);
error("rarp_write error");
}
/* NOTREACHED */
}
/* ARGSUSED */
static void
{
(void) mutex_lock(&delay_mutex);
if (delay_list == NULL) {
delay_list = rrp;
} else {
trp = delay_list;
}
(void) mutex_unlock(&delay_mutex);
(void) sema_post(&delay_sema);
}
static int
{
union DL_primitives *dlp;
/*
* Construct DL_UNITDATA_REQ.
*/
/* LINTED pointer */
return (-1);
sizeof (etype));
/*
* Send DL_UNITDATA_REQ.
*/
}
/*
* See if we have a TFTP boot file for this guy. Filenames in TFTP
* boot requests are of the form <ipaddr> for Sun-3's and of the form
* <ipaddr>.<arch> for all other architectures. Since we don't know
* the client's architecture, either format will do.
*/
static int
{
/*
* Try a quick access() first.
*/
return (1);
/*
* Not there, do it the slow way by
* reading through the directory.
*/
return (0);
pc_name_max + 1);
error("out of memory");
}
#ifdef _POSIX_PTHREAD_SEMANTICS
break;
#else
#endif
continue;
continue;
break;
}
return (dp? 1: 0);
}
/*
* Get our IP address and local netmask.
*/
static void
{
int fd;
struct sockaddr_in *sin;
/* LINTED pointer */
/*
* Open the IP provider.
*/
/*
* Ask IP for our IP address.
*/
(char *)&ifr) < 0)
syserr("SIOCGIFADDR");
if (dflag)
debug("device %s%d address %s",
/*
* Ask IP for our netmask.
*/
(char *)&ifr) < 0)
syserr("SIOCGIFNETMASK");
if (dflag)
debug("device %s%d subnet mask %s",
/*
* Thankyou ip.
*/
}
/*
* Translate mac address to IP address.
* Return 0 on success, nonzero on failure.
*/
static int
{
int herror;
char **p;
if (dflag)
"address to IP address");
return (1);
}
/*
* Translate mac address to hostname
* and IP address.
*/
&herror)) ||
if (dflag)
debug("could not map hardware address to IP address");
return (1);
}
/*
* Find the IP address on the right net.
*/
for (p = hp->h_addr_list; *p; p++) {
if (dflag) {
sizeof (ipaddr_t));
"trying physical netnum %s mask %x",
ifdev->if_netmask);
else
"trying logical %d netnum %s mask %x",
ifdev->if_netmask);
}
/*
* Return the correct IP address.
*/
/*
* Return the interface's ipaddr
*/
sizeof (ipaddr_t));
return (0);
}
}
}
if (dflag)
debug("got host entry but no IP address on this net");
return (1);
}
/*ARGSUSED*/
void
sigalarm(int i)
{
}
static int
{
}
static void
usage()
{
}
static void
syserr(s)
char *s;
{
char buf[256];
int status = 1;
}
/*PRINTFLIKE1*/
static void
{
char buf[256];
int status = 1;
}
/*PRINTFLIKE1*/
static void
{
(void) mutex_lock(&debug_mutex);
(void) mutex_unlock(&debug_mutex);
}