1 /*
2  * libc/inet/ethers.c
3  *
4  * Programmatic interface for the /etc/ethers file
5  *
6  * Copyright 2007 by Matthew Wilcox <matthew@wil.cx>
7  *
8  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
9  */
10 
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <netinet/ether.h>
15 
16 #define ETHER_LINE_LEN	256
17 
18 /*
19  * Internal function which returns a pointer to the part of the line
20  * with the start of the hostname, or NULL if we couldn't parse the line.
21  * Note that this line may have a comment symbol on it somewhere; if so
22  * it will return NULL if the # is before or within the ether_addr, and
23  * succeed if the # is before or within the host.  It's up to the callers
24  * to be aware of this.
25  *
26  * I would have preferred to write a NUL to the location of the comment
27  * character, but ether_line takes a const argument.  See __ether_line_w.
28  */
__ether_line(const char * line,struct ether_addr * addr)29 static const char *__ether_line(const char *line, struct ether_addr *addr)
30 {
31 	struct ether_addr *res = ether_aton_r(line, addr);
32 	if (!res)
33 		return NULL;
34 
35 	while (*line && (*line != '\n') && (*line != ' ') && (*line != '\t'))
36 		line++;
37 	while (*line && (*line != '\n') && ((*line == ' ') || (*line == '\t')))
38 		line++;
39 	return (*line && (*line != '\n')) ? line : NULL;
40 }
41 
42 /*
43  * Strips out the comment before calling __ether_line.  We can do this,
44  * since we know the buffer is writable.
45  */
__ether_line_w(char * line,struct ether_addr * addr)46 static const char *__ether_line_w(char *line, struct ether_addr *addr)
47 {
48 	char *end = strpbrk(line, "#\n");
49 	if (end)
50 		*end = '\0';
51 	return __ether_line(line, addr);
52 }
53 
ether_line(const char * line,struct ether_addr * addr,char * hostname)54 int ether_line(const char *line, struct ether_addr *addr, char *hostname)
55 {
56 	const char *name = __ether_line(line, addr);
57 	if (!name)
58 		return -1;
59 
60 	while (*name) {
61 		if ((*name == '#') || isspace(*name))
62 			break;
63 		*hostname++ = *name++;
64 	}
65 	*hostname = '\0';
66 
67 	return 0;
68 }
69 
ether_ntohost(char * hostname,const struct ether_addr * addr)70 int ether_ntohost(char *hostname, const struct ether_addr *addr)
71 {
72 	int res = -1;
73 	FILE *fp;
74 	char buf[ETHER_LINE_LEN];
75 
76 	fp = fopen(ETHER_FILE_NAME, "r");
77 	if (!fp)
78 		return -1;
79 
80 	while (fgets(buf, sizeof(buf), fp)) {
81 		struct ether_addr tmp_addr;
82 		const char *cp = __ether_line_w(buf, &tmp_addr);
83 		if (!cp)
84 			continue;
85 		if (memcmp(addr, &tmp_addr, sizeof(tmp_addr)))
86 			continue;
87 
88 		strcpy(hostname, cp);
89 		res = 0;
90 		break;
91 	}
92 
93 	fclose(fp);
94 	return res;
95 }
96 
ether_hostton(const char * hostname,struct ether_addr * addr)97 int ether_hostton(const char *hostname, struct ether_addr *addr)
98 {
99 	int res = -1;
100 	FILE *fp;
101 	char buf[ETHER_LINE_LEN];
102 
103 	fp = fopen(ETHER_FILE_NAME, "r");
104 	if (!fp)
105 		return -1;
106 
107 	while (fgets(buf, sizeof(buf), fp)) {
108 		const char *cp = __ether_line_w(buf, addr);
109 		if (!cp)
110 			continue;
111 		if (strcasecmp(hostname, cp))
112 			continue;
113 
114 		res = 0;
115 		break;
116 	}
117 
118 	fclose(fp);
119 	return res;
120 }
121