1 /*        $NetBSD: etherent.c,v 1.6 2024/09/02 15:33:36 christos Exp $          */
2 
3 /*
4  * Copyright (c) 1990, 1993, 1994, 1995, 1996
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23 
24 #include <sys/cdefs.h>
25 __RCSID("$NetBSD: etherent.c,v 1.6 2024/09/02 15:33:36 christos Exp $");
26 
27 #include <config.h>
28 
29 #include <pcap-types.h>
30 
31 #include <memory.h>
32 #include <stdio.h>
33 #include <string.h>
34 
35 #include "pcap-int.h"
36 
37 #include <pcap/namedb.h>
38 
39 #include "thread-local.h"
40 
41 #ifdef HAVE_OS_PROTO_H
42 #include "os-proto.h"
43 #endif
44 
45 static inline int skip_space(FILE *);
46 static inline int skip_line(FILE *);
47 
48 /* Hex digit to integer. */
49 static inline u_char
xdtoi(u_char c)50 xdtoi(u_char c)
51 {
52           if (c >= '0' && c <= '9')
53                     return (u_char)(c - '0');
54           else if (c >= 'a' && c <= 'f')
55                     return (u_char)(c - 'a' + 10);
56           else
57                     return (u_char)(c - 'A' + 10);
58 }
59 
60 /*
61  * Skip linear white space (space and tab) and any CRs before LF.
62  * Stop when we hit a non-white-space character or an end-of-line LF.
63  */
64 static inline int
skip_space(FILE * f)65 skip_space(FILE *f)
66 {
67           int c;
68 
69           do {
70                     c = getc(f);
71           } while (c == ' ' || c == '\t' || c == '\r');
72 
73           return c;
74 }
75 
76 static inline int
skip_line(FILE * f)77 skip_line(FILE *f)
78 {
79           int c;
80 
81           do
82                     c = getc(f);
83           while (c != '\n' && c != EOF);
84 
85           return c;
86 }
87 
88 struct pcap_etherent *
pcap_next_etherent(FILE * fp)89 pcap_next_etherent(FILE *fp)
90 {
91           register int c, i;
92           u_char d;
93           char *bp;
94           size_t namesize;
95           static thread_local struct pcap_etherent e;
96 
97           memset((char *)&e, 0, sizeof(e));
98           for (;;) {
99                     /* Find addr */
100                     c = skip_space(fp);
101                     if (c == EOF)
102                               return (NULL);
103                     if (c == '\n')
104                               continue;
105 
106                     /* If this is a comment, or first thing on line
107                        cannot be Ethernet address, skip the line. */
108                     if (!PCAP_ISXDIGIT(c)) {
109                               c = skip_line(fp);
110                               if (c == EOF)
111                                         return (NULL);
112                               continue;
113                     }
114 
115                     /* must be the start of an address */
116                     for (i = 0; i < 6; i += 1) {
117                               d = xdtoi((u_char)c);
118                               c = getc(fp);
119                               if (c == EOF)
120                                         return (NULL);
121                               if (PCAP_ISXDIGIT(c)) {
122                                         d <<= 4;
123                                         d |= xdtoi((u_char)c);
124                                         c = getc(fp);
125                                         if (c == EOF)
126                                                   return (NULL);
127                               }
128                               e.addr[i] = d;
129                               if (c != ':')
130                                         break;
131                               c = getc(fp);
132                               if (c == EOF)
133                                         return (NULL);
134                     }
135 
136                     /* Must be whitespace */
137                     if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
138                               c = skip_line(fp);
139                               if (c == EOF)
140                                         return (NULL);
141                               continue;
142                     }
143                     c = skip_space(fp);
144                     if (c == EOF)
145                               return (NULL);
146 
147                     /* hit end of line... */
148                     if (c == '\n')
149                               continue;
150 
151                     if (c == '#') {
152                               c = skip_line(fp);
153                               if (c == EOF)
154                                         return (NULL);
155                               continue;
156                     }
157 
158                     /* pick up name */
159                     bp = e.name;
160                     /* Use 'namesize' to prevent buffer overflow. */
161                     namesize = sizeof(e.name) - 1;
162                     do {
163                               *bp++ = (u_char)c;
164                               c = getc(fp);
165                               if (c == EOF)
166                                         return (NULL);
167                     } while (c != ' ' && c != '\t' && c != '\r' && c != '\n'
168                         && --namesize != 0);
169                     *bp = '\0';
170 
171                     /* Eat trailing junk */
172                     if (c != '\n')
173                               (void)skip_line(fp);
174 
175                     return &e;
176           }
177 }
178