#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <locale.h>
#include <sys/utsname.h>
#include <sys/systeminfo.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/stropts.h>
#include <sys/resource.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <sys/stream.h>
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <rpc/rpc.h>
#include <rpcsvc/bootparam_prot.h>
#define MAXIFS 256
int debug = 0;
int echo_host = 0;
int verbose = 0;
int safe = 0;
int multiple = 0;
static ulong_t if_netmask;
void notsupported(), usage(), bp_whoami();
int get_ifdata();
extern char *inet_ntoa();
extern int getopt(), setdomainname();
struct prototab {
char *name;
void (*func)();
} prototab[] = {
{ "bootparams", bp_whoami },
{ "bootp", notsupported },
{ 0, 0 }
};
int
main(argc, argv)
int argc;
char **argv;
{
struct ifreq *reqbuf;
struct ifreq *ifr;
struct ifconf ifc;
struct in_addr targetaddr;
struct hostent *hp;
char *targethost = NULL;
char *cmdname;
int c;
int n;
struct prototab *ptp;
void (*protofunc)() = NULL;
int numifs;
unsigned bufsize;
extern char *optarg;
extern int optind;
cmdname = argv[0];
while ((c = getopt(argc, argv, "dhvnmf:p:")) != -1) {
switch ((char)c) {
case 'd':
debug++;
break;
case 'h':
echo_host++;
break;
case 'v':
verbose++;
break;
case 'm':
multiple++;
break;
case 'n':
safe++;
break;
case 'f':
targethost = optarg;
break;
case 'p':
protofunc = NULL;
for (ptp = &prototab[0]; ptp->func; ptp++)
if (strcmp(optarg, ptp->name) == 0) {
protofunc = ptp->func;
break;
}
if (protofunc == NULL)
usage(cmdname);
break;
case '?':
usage(cmdname);
}
}
if (protofunc == NULL)
usage(cmdname);
if (targethost) {
if (debug)
fprintf(stdout, "targethost = %s\n", targethost);
if ((hp = gethostbyname(targethost)) == NULL) {
if ((targetaddr.s_addr = inet_addr(targethost)) ==
(ulong_t)(-1)) {
(void) fprintf(stderr,
"%s: cannot get IP address for %s\n",
cmdname, targethost);
return (1);
}
} else {
if (hp->h_length != sizeof (targetaddr)) {
(void) fprintf(stderr,
"%s: cannot find host entry for %s\n",
cmdname, targethost);
return (1);
} else
(void) memcpy(&targetaddr.s_addr, hp->h_addr,
sizeof (targetaddr));
}
} else
targetaddr.s_addr = 0;
if (optind < argc) {
for (; optind < argc; optind++) {
if (debug)
fprintf(stdout, "Trying arg %s\n",
argv[optind]);
(*protofunc)(argv[optind], targetaddr);
}
} else {
int ifcount = 0;
int s;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
return (1);
}
#ifdef SIOCGIFNUM
if (ioctl(s, SIOCGIFNUM, (char *)&numifs) < 0) {
numifs = MAXIFS;
}
#else
numifs = MAXIFS;
#endif
bufsize = numifs * sizeof (struct ifreq);
reqbuf = (struct ifreq *)malloc(bufsize);
if (reqbuf == NULL) {
fprintf(stderr, "out of memory\n");
return (1);
}
ifc.ifc_buf = (caddr_t)&reqbuf[0];
ifc.ifc_len = bufsize;
if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
perror("ioctl(SIOCGIFCONF)");
return (1);
}
ifr = ifc.ifc_req;
n = ifc.ifc_len/sizeof (struct ifreq);
for (; n > 0; n--, ifr++) {
if (ioctl(s, SIOCGIFFLAGS, (char *)ifr) < 0) {
perror("ioctl(SIOCGIFFLAGS)");
return (1);
}
if ((ifr->ifr_flags & IFF_LOOPBACK) ||
!(ifr->ifr_flags & IFF_BROADCAST) ||
!(ifr->ifr_flags & IFF_UP) ||
(ifr->ifr_flags & IFF_NOARP) ||
(ifr->ifr_flags & IFF_POINTOPOINT)) {
if (debug)
fprintf(stdout, "If %s not suitable\n",
ifr->ifr_name);
continue;
} else {
if (debug)
fprintf(stdout, "Trying device %s\n",
ifr->ifr_name);
(*protofunc)(ifr->ifr_name, targetaddr);
ifcount++;
}
}
if (verbose && ifcount == 0) {
fprintf(stderr, "No useable interfaces found.\n");
return (1);
}
(void) close(s);
(void) free((char *)reqbuf);
}
return (0);
}
void
add_default_route(router_addr)
struct in_addr router_addr;
{
struct rtentry route;
struct sockaddr_in *sin;
int s;
(void) memset(&route, 0, sizeof (route));
sin = (struct sockaddr_in *)&route.rt_dst;
sin->sin_family = AF_INET;
sin = (struct sockaddr_in *)&route.rt_gateway;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = router_addr.s_addr;
route.rt_flags = RTF_GATEWAY | RTF_UP;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
return;
}
if (ioctl(s, SIOCADDRT, (char *)&route) == -1) {
perror("add default route");
return;
}
(void) close(s);
}
int
bpanswer(struct bp_whoami_res *res, struct netbuf *nb)
{
struct in_addr router_addr;
static int set;
int len;
char errbuf[MAX_MACHINE_NAME + 28];
(void) memcpy(&router_addr, &res->router_address.bp_address_u.ip_addr,
sizeof (router_addr));
if (verbose) {
struct sockaddr_in *addr;
if (nb) {
addr = (struct sockaddr_in *)nb->buf;
fprintf(stdout, "From [%s]: ",
inet_ntoa(addr->sin_addr));
} else {
fprintf(stdout, "Reply:\\t\\t");
}
fprintf(stdout, "hostname = %s\n", res->client_name);
fprintf(stdout, "\t\typdomain = %s\n", res->domain_name);
fprintf(stdout, "\t\trouter = %s\n", inet_ntoa(router_addr));
}
if (!safe && !set) {
set++;
len = strlen(res->client_name);
if (len != 0) {
if (!echo_host) {
if (sysinfo(SI_SET_HOSTNAME, res->client_name,
len) < 0) {
(void) snprintf(errbuf, sizeof (errbuf),
"sysinfo(SI_SET_HOSTNAME)(%s)",
res->client_name);
perror(errbuf);
}
} else
(void) fprintf(stdout, "%s\n",
res->client_name);
}
len = strlen(res->domain_name);
if (len != 0) {
if (setdomainname(res->domain_name, len) == -1) {
(void) snprintf(errbuf, sizeof (errbuf),
"setdomainname(%s)", res->domain_name);
perror(errbuf);
}
}
if (router_addr.s_addr != 0)
add_default_route(router_addr);
}
if (multiple)
return (0);
exit(0);
}
void
bp_whoami(device, addr)
char *device;
struct in_addr addr;
{
struct bp_whoami_arg req;
struct bp_whoami_res res;
struct in_addr lookupaddr;
enum clnt_stat stat;
int val = 1;
if (debug)
fprintf(stdout, "bp_whoami on interface %s addr %s\n", device,
inet_ntoa(addr));
if (addr.s_addr == 0) {
if (get_ifdata(device, &lookupaddr, &if_netmask) == -1)
exit(1);
} else
(void) memcpy(&lookupaddr, &addr, sizeof (addr));
lookupaddr.s_addr = ntohl(lookupaddr.s_addr);
if (debug)
fprintf(stdout, "lookup address is %s\n",
inet_ntoa(lookupaddr));
(void) memset(&req, 0, sizeof (req));
(void) memset(&res, 0, sizeof (res));
req.client_address.address_type = IP_ADDR_TYPE;
(void) memcpy(&req.client_address.bp_address_u.ip_addr, &lookupaddr,
sizeof (lookupaddr));
(void) __rpc_control(CLCR_SET_LOWVERS, &val);
stat = rpc_broadcast(BOOTPARAMPROG, BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI,
xdr_bp_whoami_arg, (caddr_t)&req, xdr_bp_whoami_res, (caddr_t)&res,
(resultproc_t)bpanswer, "udp");
val = 0;
(void) __rpc_control(CLCR_SET_LOWVERS, &val);
stat = rpc_broadcast(BOOTPARAMPROG, BOOTPARAMVERS,
BOOTPARAMPROC_WHOAMI, xdr_bp_whoami_arg, (caddr_t)&req,
xdr_bp_whoami_res, (caddr_t)&res, (resultproc_t)bpanswer, "udp");
if (stat != RPC_SUCCESS) {
clnt_perrno(stat);
exit(1);
}
}
int
get_ifdata(dev, ipp, maskp)
char *dev;
ulong_t *ipp, *maskp;
{
struct ifreq ifr;
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
int s;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
return (-1);
}
if (strlcpy(ifr.ifr_name, dev, sizeof (ifr.ifr_name)) >=
sizeof (ifr.ifr_name)) {
(void) fprintf(stderr, "Device name too long %s\n",
dev);
return (-1);
}
if (ipp) {
if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
perror("ioctl(SIOCGIFADDR)");
return (-1);
}
*ipp = ntohl(sin->sin_addr.s_addr);
if (debug)
(void) fprintf(stderr, "Interface '%s' address %s\n",
dev, inet_ntoa(sin->sin_addr));
}
if (maskp) {
if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
perror("SIOCGIFNETMASK");
return (-1);
}
*maskp = ntohl(sin->sin_addr.s_addr);
if (debug)
(void) fprintf(stderr,
"Interface '%s' subnet mask %s\n", dev,
inet_ntoa(sin->sin_addr));
}
(void) close(s);
return (0);
}
void
notsupported()
{
fprintf(stderr, "requested protocol is not supported\n");
exit(1);
}
void
usage(cmdname)
char *cmdname;
{
(void) fprintf(stderr, "usage: %s [-v] [-n] [-m] [-h] [<ifname>] "
"[-f <hostname>] -p bootparams|bootp\n", cmdname);
(void) fflush(stderr);
exit(1);
}