1 /*
2  * Copyright (c) 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2009, 2010, 2013, 2016, 2019
3  * The Regents of the University of California. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University nor the names of its contributors
13  *       may be used to endorse or promote products derived from this software
14  *       without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 #ifndef lint
29 static const char rcsid[] =
30     "@(#) $Id: ec.c 1506 2019-11-30 18:39:08Z leres $ (LBL)";
31 #endif
32 
33 /*
34  * ec - manufactures ethernet code routines
35  */
36 
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/time.h>
40 
41 #if __STDC__
42 struct mbuf;
43 struct rtentry;
44 #endif
45 #include <net/if.h>
46 
47 #include <netinet/in.h>
48 
49 #include <arpa/inet.h>
50 
51 #include <ctype.h>
52 #include <errno.h>
53 #ifdef HAVE_MEMORY_H
54 #include <memory.h>
55 #endif
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <syslog.h>
60 
61 #include "gnuc.h"
62 #ifdef HAVE_OS_PROTO_H
63 #include "os-proto.h"
64 #endif
65 
66 #include "arpwatch.h"
67 #include "ec.h"
68 #include "util.h"
69 
70 /* Basic data structure */
71 struct ecent {
72 	u_int32_t o;		/* first 3 octets */
73 	char *text;		/* associated text */
74 };
75 
76 static struct ecent *list;
77 static u_int ec_last;
78 static u_int ec_len;
79 
80 /* Forwards */
81 static int ec_a2o(char *, u_int32_t *);
82 
83 /* Convert an 3 octets from an ethernet address to a u_int32_t */
84 static int
ec_a2o(char * cp,u_int32_t * op)85 ec_a2o(char *cp, u_int32_t *op)
86 {
87 	char xbuf[128];
88 	u_char e[6];
89 
90 	(void)snprintf(xbuf, sizeof(xbuf), "%.32s:0:0:0", cp);
91 	if (!str2e(xbuf, e))
92 		return (0);
93 	*op = 0;
94 	memmove(op, e, 3);
95 	return (1);
96 }
97 
98 /* Add a ethernet code to the database */
99 int
ec_add(u_int32_t o,const char * text)100 ec_add(u_int32_t o, const char *text)
101 {
102 	struct ecent *olist;
103 
104 	if (ec_last >= ec_len) {
105 		if (list == NULL) {
106 			ec_len = 512;
107 			olist = NULL;
108 			list = malloc(ec_len * sizeof(*list));
109 		} else {
110 			ec_len *= 2;
111 			olist = list;
112 			list = realloc(olist, ec_len * sizeof(*list));
113 		}
114 		if (list == NULL) {
115 			if (olist != NULL)
116 				free(olist);
117 			lg(LOG_ERR, "ec_add(): malloc: %s", strerror(errno));
118 			exit(1);
119 		}
120 	}
121 	list[ec_last].o = o;
122 	list[ec_last].text = savestr(text);
123 	++ec_last;
124 	return (1);
125 }
126 
127 /* Find the manufacture for a given ethernet address */
128 char *
ec_find(const u_char * e)129 ec_find(const u_char *e)
130 {
131 	u_int32_t o;
132 	int i;
133 
134 	o = 0;
135 	memmove(&o, e, 3);
136 	for (i = 0; i < ec_last; ++i)
137 		if (list[i].o == o)
138 			return (list[i].text);
139 
140 	return (NULL);
141 }
142 
143 /* Loop through the ethernet code database */
144 int
ec_loop(FILE * f,ec_process fn,const char * nm)145 ec_loop(FILE *f, ec_process fn, const char *nm)
146 {
147 	int n;
148 	char *cp, *cp2, *text;
149 	int sawblank;
150 	u_int32_t o;
151 	char line[1024];
152 
153 	n = 0;
154 	while (fgets(line, sizeof(line), f)) {
155 		++n;
156 		cp = line;
157 		cp2 = cp + strlen(cp) - 1;
158 		if (cp2 >= cp && *cp2 == '\n')
159 			*cp2++ = '\0';
160 		if (*cp == '#')
161 			continue;
162 		if ((cp2 = strchr(cp, '\t')) == 0) {
163 			lg(LOG_ERR, "ec_loop(): %s:%d missing tab", nm, n);
164 			continue;
165 		}
166 
167 		/* 3 octets come first */
168 		*cp2++ = '\0';
169 		text = cp2;
170 		if (!ec_a2o(cp, &o)) {
171 			lg(LOG_ERR, "ec_loop(): %s:%d bad octets", nm, n);
172 			continue;
173 		}
174 
175 		/* Compress blanks */
176 		cp = cp2 = text;
177 		sawblank = 0;
178 		while (*cp != '\0') {
179 			if (sawblank) {
180 				*cp2++ = ' ';
181 				sawblank = 0;
182 			}
183 			*cp2++ = *cp++;
184 			while (isspace((int)*cp)) {
185 				++cp;
186 				sawblank = 1;
187 			}
188 		}
189 		*cp2 = '\0';
190 
191 		if (!(*fn)(o, text))
192 			return (0);
193 	}
194 
195 	return (1);
196 }
197 
198 /* DECnet local logical address prefix */
199 static u_char decnet[3] = { 0xaa, 0x0, 0x4 };
200 
201 /* Returns true if an ethernet address is decnet, else false */
202 int
isdecnet(const u_char * e)203 isdecnet(const u_char *e)
204 {
205 	return (memcmp(e, decnet, sizeof(decnet)) == 0);
206 }
207 
208 /* Convert an ascii ethernet string to ethernet address */
209 int
str2e(const char * str,u_char * e)210 str2e(const char *str, u_char *e)
211 {
212 	int i;
213 	u_int n[6];
214 
215 	memset(n, 0, sizeof(n));
216 	if (sscanf(str, "%x:%x:%x:%x:%x:%x",
217 	    &n[0], &n[1], &n[2], &n[3], &n[4], &n[5]) != 6)
218 		return (0);
219 	for (i = 0; i < 6; ++i) {
220 		if (n[i] > 0xff)
221 			return (0);
222 		e[i] = n[i];
223 	}
224 	return (1);
225 }
226 
227 /* Convert an ethernet address to an ascii ethernet string */
228 char *
e2str(const u_char * e)229 e2str(const u_char *e)
230 {
231 	static char str[32];
232 
233 	(void)snprintf(str, sizeof(str),
234 	    zeropad ? "%02x:%02x:%02x:%02x:%02x:%02x" : "%x:%x:%x:%x:%x:%x",
235 	    e[0], e[1], e[2], e[3], e[4], e[5]);
236 	return (str);
237 }
238