xref: /freebsd/sbin/ipf/ipsend/arp.c (revision 43a5ec4eb41567cc92586503212743d89686d78f)
1 /*	$FreeBSD$	*/
2 
3 /*
4  * arp.c (C) 1995-1998 Darren Reed
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if !defined(lint)
9 static const char sccsid[] = "@(#)arp.c	1.4 1/11/96 (C)1995 Darren Reed";
10 static const char rcsid[] = "@(#)$Id$";
11 #endif
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 # include <sys/sockio.h>
15 #include <sys/ioctl.h>
16 #include <netinet/in_systm.h>
17 #include <netinet/in.h>
18 #include <net/if.h>
19 #include <netinet/if_ether.h>
20 # include <net/if_arp.h>
21 #include <netinet/in.h>
22 #include <netinet/ip.h>
23 #include <netinet/ip_var.h>
24 #include <netinet/tcp.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <netdb.h>
28 #include "ipsend.h"
29 #include "iplang/iplang.h"
30 
31 
32 /*
33  * lookup host and return
34  * its IP address in address
35  * (4 bytes)
36  */
37 int	resolve(char *host, char *address)
38 {
39 	struct	hostent	*hp;
40 	u_long	add;
41 
42 	add = inet_addr(host);
43 	if (add == -1)
44 	    {
45 		if (!(hp = gethostbyname(host)))
46 		    {
47 			fprintf(stderr, "unknown host: %s\n", host);
48 			return (-1);
49 		    }
50 		bcopy((char *)hp->h_addr, (char *)address, 4);
51 		return (0);
52 	}
53 	bcopy((char*)&add, address, 4);
54 	return (0);
55 }
56 
57 /*
58  * ARP for the MAC address corresponding
59  * to the IP address.  This taken from
60  * some BSD program, I cant remember which.
61  */
62 int	arp(ip, ether)
63 	char	*ip;
64 	char	*ether;
65 {
66 	static	int	sfd = -1;
67 	static	char	ethersave[6], ipsave[4];
68 	struct	arpreq	ar;
69 	struct	sockaddr_in	*sin, san;
70 	struct	hostent	*hp;
71 	int	fd;
72 
73 #ifdef	IPSEND
74 	if (arp_getipv4(ip, ether) == 0)
75 		return (0);
76 #endif
77 	if (!bcmp(ipsave, ip, 4)) {
78 		bcopy(ethersave, ether, 6);
79 		return (0);
80 	}
81 	fd = -1;
82 	bzero((char *)&ar, sizeof(ar));
83 	sin = (struct sockaddr_in *)&ar.arp_pa;
84 	sin->sin_family = AF_INET;
85 	bcopy(ip, (char *)&sin->sin_addr.s_addr, 4);
86 	if ((hp = gethostbyaddr(ip, 4, AF_INET)))
87 # if SOLARIS && (SOLARIS2 >= 10)
88 		if (!(ether_hostton(hp->h_name, (struct ether_addr *)ether)))
89 # else
90 		if (!(ether_hostton(hp->h_name, ether)))
91 # endif
92 			goto savearp;
93 
94 	if (sfd == -1)
95 		if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
96 		    {
97 			perror("arp: socket");
98 			return (-1);
99 		    }
100 tryagain:
101 	if (ioctl(sfd, SIOCGARP, (caddr_t)&ar) == -1)
102 	    {
103 		if (fd == -1)
104 		    {
105 			bzero((char *)&san, sizeof(san));
106 			san.sin_family = AF_INET;
107 			san.sin_port = htons(1);
108 			bcopy(ip, &san.sin_addr.s_addr, 4);
109 			fd = socket(AF_INET, SOCK_DGRAM, 0);
110 			(void) sendto(fd, ip, 4, 0,
111 				      (struct sockaddr *)&san, sizeof(san));
112 			sleep(1);
113 			(void) close(fd);
114 			goto tryagain;
115 		    }
116 		fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr));
117 		if (errno != ENXIO)
118 			perror("SIOCGARP");
119 		return (-1);
120 	    }
121 
122 	if ((ar.arp_ha.sa_data[0] == 0) && (ar.arp_ha.sa_data[1] == 0) &&
123 	    (ar.arp_ha.sa_data[2] == 0) && (ar.arp_ha.sa_data[3] == 0) &&
124 	    (ar.arp_ha.sa_data[4] == 0) && (ar.arp_ha.sa_data[5] == 0)) {
125 		fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr));
126 		return (-1);
127 	}
128 
129 	bcopy(ar.arp_ha.sa_data, ether, 6);
130 savearp:
131 	bcopy(ether, ethersave, 6);
132 	bcopy(ip, ipsave, 4);
133 	return (0);
134 }
135