xref: /freebsd/lib/libc/net/ether_addr.c (revision 559a218c)
1df57947fSPedro F. Giffuni /*-
2df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni  *
4b0661945SRobert Watson  * Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu>.
562ad77f0SRobert Watson  * Copyright (c) 2007 Robert N. M. Watson
6b0661945SRobert Watson  * All rights reserved.
77680d1b0SBill Paul  *
87680d1b0SBill Paul  * Redistribution and use in source and binary forms, with or without
97680d1b0SBill Paul  * modification, are permitted provided that the following conditions
107680d1b0SBill Paul  * are met:
117680d1b0SBill Paul  * 1. Redistributions of source code must retain the above copyright
127680d1b0SBill Paul  *    notice, this list of conditions and the following disclaimer.
137680d1b0SBill Paul  * 2. Redistributions in binary form must reproduce the above copyright
147680d1b0SBill Paul  *    notice, this list of conditions and the following disclaimer in the
157680d1b0SBill Paul  *    documentation and/or other materials provided with the distribution.
167680d1b0SBill Paul  * 3. All advertising materials mentioning features or use of this software
177680d1b0SBill Paul  *    must display the following acknowledgement:
187680d1b0SBill Paul  *	This product includes software developed by Bill Paul.
197680d1b0SBill Paul  * 4. Neither the name of the author nor the names of any co-contributors
207680d1b0SBill Paul  *    may be used to endorse or promote products derived from this software
217680d1b0SBill Paul  *    without specific prior written permission.
227680d1b0SBill Paul  *
237680d1b0SBill Paul  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
247680d1b0SBill Paul  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
257680d1b0SBill Paul  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
267680d1b0SBill Paul  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
277680d1b0SBill Paul  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
287680d1b0SBill Paul  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
297680d1b0SBill Paul  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
307680d1b0SBill Paul  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
317680d1b0SBill Paul  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
327680d1b0SBill Paul  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
337680d1b0SBill Paul  * SUCH DAMAGE.
347680d1b0SBill Paul  *
357680d1b0SBill Paul  * ethernet address conversion and lookup routines
367680d1b0SBill Paul  *
377680d1b0SBill Paul  * Written by Bill Paul <wpaul@ctr.columbia.edu>
387680d1b0SBill Paul  * Center for Telecommunications Research
397680d1b0SBill Paul  * Columbia University, New York City
407680d1b0SBill Paul  */
417680d1b0SBill Paul 
427680d1b0SBill Paul #include <sys/param.h>
437680d1b0SBill Paul #include <sys/socket.h>
44b0661945SRobert Watson 
4513629194SGarrett Wollman #include <net/ethernet.h>
46b0661945SRobert Watson 
477680d1b0SBill Paul #ifdef YP
487680d1b0SBill Paul #include <rpc/rpc.h>
497680d1b0SBill Paul #include <rpcsvc/yp_prot.h>
507680d1b0SBill Paul #include <rpcsvc/ypclnt.h>
517680d1b0SBill Paul #endif
527680d1b0SBill Paul 
53b0661945SRobert Watson #include <paths.h>
54b0661945SRobert Watson #include <stdio.h>
55b0661945SRobert Watson #include <stdlib.h>
56b0661945SRobert Watson #include <string.h>
57b0661945SRobert Watson 
587680d1b0SBill Paul #ifndef _PATH_ETHERS
597680d1b0SBill Paul #define	_PATH_ETHERS	"/etc/ethers"
607680d1b0SBill Paul #endif
617680d1b0SBill Paul 
627680d1b0SBill Paul /*
63b0661945SRobert Watson  * Parse a string of text containing an ethernet address and hostname and
64b0661945SRobert Watson  * separate it into its component parts.
657680d1b0SBill Paul  */
66ee6c974dSEric Melville int
ether_line(const char * l,struct ether_addr * e,char * hostname)67b0661945SRobert Watson ether_line(const char *l, struct ether_addr *e, char *hostname)
687680d1b0SBill Paul {
697680d1b0SBill Paul 	int i, o[6];
707680d1b0SBill Paul 
71b0661945SRobert Watson 	i = sscanf(l, "%x:%x:%x:%x:%x:%x %s", &o[0], &o[1], &o[2], &o[3],
72b0661945SRobert Watson 	    &o[4], &o[5], hostname);
7376a1f42fSJulio Merino 	if (i == 7) {
747680d1b0SBill Paul 		for (i = 0; i < 6; i++)
757680d1b0SBill Paul 			e->octet[i] = o[i];
767680d1b0SBill Paul 		return (0);
7776a1f42fSJulio Merino 	} else {
7876a1f42fSJulio Merino 		return (-1);
7976a1f42fSJulio Merino 	}
807680d1b0SBill Paul }
817680d1b0SBill Paul 
827680d1b0SBill Paul /*
83b0661945SRobert Watson  * Convert an ASCII representation of an ethernet address to binary form.
847680d1b0SBill Paul  */
85b0661945SRobert Watson struct ether_addr *
ether_aton_r(const char * a,struct ether_addr * e)8662ad77f0SRobert Watson ether_aton_r(const char *a, struct ether_addr *e)
877680d1b0SBill Paul {
887680d1b0SBill Paul 	int i;
8951295a4dSJordan K. Hubbard 	unsigned int o0, o1, o2, o3, o4, o5;
907680d1b0SBill Paul 
9151295a4dSJordan K. Hubbard 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5);
927680d1b0SBill Paul 	if (i != 6)
937680d1b0SBill Paul 		return (NULL);
9462ad77f0SRobert Watson 	e->octet[0]=o0;
9562ad77f0SRobert Watson 	e->octet[1]=o1;
9662ad77f0SRobert Watson 	e->octet[2]=o2;
9762ad77f0SRobert Watson 	e->octet[3]=o3;
9862ad77f0SRobert Watson 	e->octet[4]=o4;
9962ad77f0SRobert Watson 	e->octet[5]=o5;
10062ad77f0SRobert Watson 	return (e);
10162ad77f0SRobert Watson }
10262ad77f0SRobert Watson 
10362ad77f0SRobert Watson struct ether_addr *
ether_aton(const char * a)10462ad77f0SRobert Watson ether_aton(const char *a)
10562ad77f0SRobert Watson {
10662ad77f0SRobert Watson 	static struct ether_addr e;
10762ad77f0SRobert Watson 
10862ad77f0SRobert Watson 	return (ether_aton_r(a, &e));
1097680d1b0SBill Paul }
1107680d1b0SBill Paul 
1117680d1b0SBill Paul /*
112b0661945SRobert Watson  * Convert a binary representation of an ethernet address to an ASCII string.
1137680d1b0SBill Paul  */
114b0661945SRobert Watson char *
ether_ntoa_r(const struct ether_addr * n,char * a)11562ad77f0SRobert Watson ether_ntoa_r(const struct ether_addr *n, char *a)
1167680d1b0SBill Paul {
1177680d1b0SBill Paul 	int i;
1187680d1b0SBill Paul 
119b0661945SRobert Watson 	i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", n->octet[0],
120b0661945SRobert Watson 	    n->octet[1], n->octet[2], n->octet[3], n->octet[4], n->octet[5]);
121dab8ffaaSRuslan Ermilov 	if (i < 17)
1227680d1b0SBill Paul 		return (NULL);
12362ad77f0SRobert Watson 	return (a);
12462ad77f0SRobert Watson }
12562ad77f0SRobert Watson 
12662ad77f0SRobert Watson char *
ether_ntoa(const struct ether_addr * n)12762ad77f0SRobert Watson ether_ntoa(const struct ether_addr *n)
12862ad77f0SRobert Watson {
12962ad77f0SRobert Watson 	static char a[18];
13062ad77f0SRobert Watson 
13162ad77f0SRobert Watson 	return (ether_ntoa_r(n, a));
1327680d1b0SBill Paul }
1337680d1b0SBill Paul 
1347680d1b0SBill Paul /*
135b0661945SRobert Watson  * Map an ethernet address to a hostname. Use either /etc/ethers or NIS/YP.
1367680d1b0SBill Paul  */
137ee6c974dSEric Melville int
ether_ntohost(char * hostname,const struct ether_addr * e)138b0661945SRobert Watson ether_ntohost(char *hostname, const struct ether_addr *e)
1397680d1b0SBill Paul {
1407680d1b0SBill Paul 	FILE *fp;
1413951b8e3SBill Paul 	char buf[BUFSIZ + 2];
1427680d1b0SBill Paul 	struct ether_addr local_ether;
1437680d1b0SBill Paul 	char local_host[MAXHOSTNAMELEN];
1447680d1b0SBill Paul #ifdef YP
1457680d1b0SBill Paul 	char *result;
1467680d1b0SBill Paul 	int resultlen;
1477680d1b0SBill Paul 	char *ether_a;
1487680d1b0SBill Paul 	char *yp_domain;
1497680d1b0SBill Paul #endif
150b0661945SRobert Watson 
151a93705b0SJilles Tjoelker 	if ((fp = fopen(_PATH_ETHERS, "re")) == NULL)
1527680d1b0SBill Paul 		return (1);
1537680d1b0SBill Paul 	while (fgets(buf,BUFSIZ,fp)) {
1547680d1b0SBill Paul 		if (buf[0] == '#')
1557680d1b0SBill Paul 			continue;
1567680d1b0SBill Paul #ifdef YP
1577680d1b0SBill Paul 		if (buf[0] == '+') {
1587680d1b0SBill Paul 			if (yp_get_default_domain(&yp_domain))
1591e890b05SBill Paul 				continue;
1607680d1b0SBill Paul 			ether_a = ether_ntoa(e);
1617680d1b0SBill Paul 			if (yp_match(yp_domain, "ethers.byaddr", ether_a,
1627680d1b0SBill Paul 			    strlen(ether_a), &result, &resultlen)) {
1631e890b05SBill Paul 				continue;
1647680d1b0SBill Paul 			}
1652696fe9cSJordan K. Hubbard 			strncpy(buf, result, resultlen);
1663951b8e3SBill Paul 			buf[resultlen] = '\0';
1677680d1b0SBill Paul 			free(result);
1687680d1b0SBill Paul 		}
1697680d1b0SBill Paul #endif
1702696fe9cSJordan K. Hubbard 		if (!ether_line(buf, &local_ether, local_host)) {
1717680d1b0SBill Paul 			if (!bcmp((char *)&local_ether.octet[0],
1727680d1b0SBill Paul 			    (char *)&e->octet[0], 6)) {
173b0661945SRobert Watson 				/* We have a match. */
1742696fe9cSJordan K. Hubbard 				strcpy(hostname, local_host);
1757680d1b0SBill Paul 				fclose(fp);
1767680d1b0SBill Paul 				return(0);
1777680d1b0SBill Paul 			}
1787680d1b0SBill Paul 		}
1797680d1b0SBill Paul 	}
1807680d1b0SBill Paul 	fclose(fp);
1817680d1b0SBill Paul 	return (1);
1827680d1b0SBill Paul }
1837680d1b0SBill Paul 
1847680d1b0SBill Paul /*
185b0661945SRobert Watson  * Map a hostname to an ethernet address using /etc/ethers or NIS/YP.
1867680d1b0SBill Paul  */
187ee6c974dSEric Melville int
ether_hostton(const char * hostname,struct ether_addr * e)188b0661945SRobert Watson ether_hostton(const char *hostname, struct ether_addr *e)
1897680d1b0SBill Paul {
1907680d1b0SBill Paul 	FILE *fp;
1913951b8e3SBill Paul 	char buf[BUFSIZ + 2];
1927680d1b0SBill Paul 	struct ether_addr local_ether;
1937680d1b0SBill Paul 	char local_host[MAXHOSTNAMELEN];
1947680d1b0SBill Paul #ifdef YP
1957680d1b0SBill Paul 	char *result;
1967680d1b0SBill Paul 	int resultlen;
1977680d1b0SBill Paul 	char *yp_domain;
1987680d1b0SBill Paul #endif
199b0661945SRobert Watson 
200a93705b0SJilles Tjoelker 	if ((fp = fopen(_PATH_ETHERS, "re")) == NULL)
2017680d1b0SBill Paul 		return (1);
2027680d1b0SBill Paul 	while (fgets(buf,BUFSIZ,fp)) {
2037680d1b0SBill Paul 		if (buf[0] == '#')
2047680d1b0SBill Paul 			continue;
2057680d1b0SBill Paul #ifdef YP
2067680d1b0SBill Paul 		if (buf[0] == '+') {
2077680d1b0SBill Paul 			if (yp_get_default_domain(&yp_domain))
2081e890b05SBill Paul 				continue;
2097680d1b0SBill Paul 			if (yp_match(yp_domain, "ethers.byname", hostname,
2107680d1b0SBill Paul 			    strlen(hostname), &result, &resultlen)) {
2111e890b05SBill Paul 				continue;
2127680d1b0SBill Paul 			}
2132696fe9cSJordan K. Hubbard 			strncpy(buf, result, resultlen);
2143951b8e3SBill Paul 			buf[resultlen] = '\0';
2157680d1b0SBill Paul 			free(result);
2167680d1b0SBill Paul 		}
2177680d1b0SBill Paul #endif
2182696fe9cSJordan K. Hubbard 		if (!ether_line(buf, &local_ether, local_host)) {
2192696fe9cSJordan K. Hubbard 			if (!strcmp(hostname, local_host)) {
220b0661945SRobert Watson 				/* We have a match. */
2217680d1b0SBill Paul 				bcopy((char *)&local_ether.octet[0],
2227680d1b0SBill Paul 				    (char *)&e->octet[0], 6);
2237680d1b0SBill Paul 				fclose(fp);
2247680d1b0SBill Paul 				return(0);
2257680d1b0SBill Paul 			}
2267680d1b0SBill Paul 		}
2277680d1b0SBill Paul 	}
2287680d1b0SBill Paul 	fclose(fp);
2297680d1b0SBill Paul 	return (1);
2307680d1b0SBill Paul }
231