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