1 /*
2 * The ARP Scanner (arp-scan) is Copyright (C) 2005-2019 Roy Hills,
3 * NTA Monitor Ltd.
4 *
5 * This file is part of arp-scan.
6 *
7 * arp-scan is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * arp-scan is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with arp-scan. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * You are encouraged to send comments, improvements or suggestions
21 * at the github repository https://github.com/royhills/arp-scan
22 *
23 * Author: Roy Hills
24 * Date: 5 April 2004
25 *
26 * This file contains various utility functions used by arp-scan.
27 */
28
29 #include "arp-scan.h"
30
31 /*
32 * timeval_diff -- Calculates the difference between two timevals
33 * and returns this difference in a third timeval.
34 *
35 * Inputs:
36 *
37 * a = First timeval
38 * b = Second timeval
39 * diff = Difference between timevals (a - b).
40 *
41 * Returns:
42 *
43 * None.
44 */
45 void
timeval_diff(const struct timeval * a,const struct timeval * b,struct timeval * diff)46 timeval_diff(const struct timeval *a, const struct timeval *b,
47 struct timeval *diff) {
48 struct timeval temp;
49
50 temp.tv_sec = b->tv_sec;
51 temp.tv_usec = b->tv_usec;
52
53 /* Perform the carry for the later subtraction by updating b. */
54 if (a->tv_usec < temp.tv_usec) {
55 int nsec = (temp.tv_usec - a->tv_usec) / 1000000 + 1;
56 temp.tv_usec -= 1000000 * nsec;
57 temp.tv_sec += nsec;
58 }
59 if (a->tv_usec - temp.tv_usec > 1000000) {
60 int nsec = (a->tv_usec - temp.tv_usec) / 1000000;
61 temp.tv_usec += 1000000 * nsec;
62 temp.tv_sec -= nsec;
63 }
64
65 /* Compute the time difference
66 tv_usec is certainly positive. */
67 diff->tv_sec = a->tv_sec - temp.tv_sec;
68 diff->tv_usec = a->tv_usec - temp.tv_usec;
69 }
70
71 /*
72 * hstr_i -- Convert two-digit hex string to unsigned integer
73 *
74 * Inputs:
75 *
76 * cptr Two-digit hex string
77 *
78 * Returns:
79 *
80 * Number corresponding to input hex value.
81 *
82 * An input of "0A" or "0a" would return 10.
83 * Note that this function does no sanity checking, it's up to the
84 * caller to ensure that *cptr points to at least two hex digits.
85 *
86 * This function is a modified version of hstr_i at www.snippets.org.
87 */
88 unsigned int
hstr_i(const char * cptr)89 hstr_i(const char *cptr)
90 {
91 unsigned int i;
92 unsigned int j = 0;
93 int k;
94
95 for (k=0; k<2; k++) {
96 i = *cptr++ - '0';
97 if (9 < i)
98 i -= 7;
99 j <<= 4;
100 j |= (i & 0x0f);
101 }
102 return j;
103 }
104
105 /*
106 * hex2data -- Convert hex string to binary data
107 *
108 * Inputs:
109 *
110 * string The string to convert
111 * data_len (output) The length of the resultant binary data
112 *
113 * Returns:
114 *
115 * Pointer to the binary data.
116 *
117 * The returned pointer points to malloc'ed storage which should be
118 * free'ed by the caller when it's no longer needed. If the length of
119 * the input string is not even, the function will return NULL and
120 * set data_len to 0.
121 */
122 unsigned char *
hex2data(const char * string,size_t * data_len)123 hex2data(const char *string, size_t *data_len) {
124 unsigned char *data;
125 unsigned char *cp;
126 unsigned i;
127 size_t len;
128
129 if (strlen(string) %2 ) { /* Length is odd */
130 *data_len = 0;
131 return NULL;
132 }
133
134 len = strlen(string) / 2;
135 data = Malloc(len);
136 cp = data;
137 for (i=0; i<len; i++)
138 *cp++=hstr_i(&string[i*2]);
139 *data_len = len;
140 return data;
141 }
142
143 /*
144 * make_message -- allocate a sufficiently large string and print into it.
145 *
146 * Inputs:
147 *
148 * Format and variable number of arguments.
149 *
150 * Outputs:
151 *
152 * Pointer to the string,
153 *
154 * The code for this function is from the Debian Linux "woody" sprintf man
155 * page. Modified slightly to use wrapper functions for malloc and realloc.
156 */
157 char *
make_message(const char * fmt,...)158 make_message(const char *fmt, ...) {
159 int n;
160 /* Guess we need no more than 100 bytes. */
161 size_t size = 100;
162 char *p;
163 va_list ap;
164 p = Malloc (size);
165 while (1) {
166 /* Try to print in the allocated space. */
167 va_start(ap, fmt);
168 n = vsnprintf (p, size, fmt, ap);
169 va_end(ap);
170 /* If that worked, return the string. */
171 if (n > -1 && n < (int) size)
172 return p;
173 /* Else try again with more space. */
174 if (n > -1) /* glibc 2.1 */
175 size = n+1; /* precisely what is needed */
176 else /* glibc 2.0 */
177 size *= 2; /* twice the old size */
178 p = Realloc (p, size);
179 }
180 }
181
182 /*
183 * hexstring -- Convert data to printable hex string form
184 *
185 * Inputs:
186 *
187 * string Pointer to input data.
188 * size Size of input data.
189 *
190 * Returns:
191 *
192 * Pointer to the printable hex string.
193 *
194 * Each byte in the input data will be represented by two hex digits
195 * in the output string. Therefore the output string will be twice
196 * as long as the input data plus one extra byte for the trailing NULL.
197 *
198 * The pointer returned points to malloc'ed storage which should be
199 * free'ed by the caller when it's no longer needed.
200 */
201 char *
hexstring(const unsigned char * data,size_t size)202 hexstring(const unsigned char *data, size_t size) {
203 char *result;
204 char *r;
205 const unsigned char *cp;
206 unsigned i;
207 /*
208 * If the input data is NULL, return an empty string.
209 */
210 if (data == NULL) {
211 result = Malloc(1);
212 result[0] = '\0';
213 return result;
214 }
215 /*
216 * Create and return hex string.
217 */
218 result = Malloc(2*size + 1);
219 cp = data;
220 r = result;
221 for (i=0; i<size; i++) {
222 snprintf(r, 3, "%.2x", *cp++);
223 r += 2;
224 }
225 *r = '\0';
226
227 return result;
228 }
229
230 /*
231 * get_ether_addr -- Get Ethernet hardware address from text string
232 *
233 * Inputs:
234 *
235 * address_string The text string containing the address
236 * ether_addr (output) The Ethernet hardware address
237 *
238 * Returns:
239 *
240 * Zero on success or -1 on failure.
241 *
242 * The address_string should contain an Ethernet hardware address in one
243 * of the following formats:
244 *
245 * 01-23-45-67-89-ab
246 * 01:23:45:67:89:ab
247 *
248 * The hex characters [a-z] may be specified in either upper or lower case.
249 */
250 int
get_ether_addr(const char * address_string,unsigned char * ether_addr)251 get_ether_addr(const char *address_string, unsigned char *ether_addr) {
252 unsigned mac_b0, mac_b1, mac_b2, mac_b3, mac_b4, mac_b5;
253 int result;
254
255 result = sscanf(address_string, "%x:%x:%x:%x:%x:%x",
256 &mac_b0, &mac_b1, &mac_b2, &mac_b3, &mac_b4, &mac_b5);
257 if (result !=6 ) {
258 result = sscanf(address_string, "%x-%x-%x-%x-%x-%x",
259 &mac_b0, &mac_b1, &mac_b2, &mac_b3, &mac_b4, &mac_b5);
260 }
261 if (result !=6 ) {
262 return -1;
263 }
264 ether_addr[0] = mac_b0;
265 ether_addr[1] = mac_b1;
266 ether_addr[2] = mac_b2;
267 ether_addr[3] = mac_b3;
268 ether_addr[4] = mac_b4;
269 ether_addr[5] = mac_b5;
270
271 return 0;
272 }
273
274 /*
275 * str_to_bandwidth -- Convert a bandwidth string to unsigned integer
276 *
277 * Inputs:
278 *
279 * bandwidth_string The bandwidth string to convert
280 *
281 * Returns:
282 *
283 * The bandwidth in bits per second as an unsigned integer
284 */
285 unsigned
str_to_bandwidth(const char * bandwidth_string)286 str_to_bandwidth(const char *bandwidth_string) {
287 char *bandwidth_str;
288 size_t bandwidth_len;
289 unsigned value;
290 int multiplier=1;
291 int end_char;
292
293 bandwidth_str=dupstr(bandwidth_string); /* Writable copy */
294 bandwidth_len=strlen(bandwidth_str);
295 end_char = bandwidth_str[bandwidth_len-1];
296 if (!isdigit(end_char)) { /* End character is not a digit */
297 bandwidth_str[bandwidth_len-1] = '\0'; /* Remove last character */
298 switch (end_char) {
299 case 'M':
300 case 'm':
301 multiplier = 1000000;
302 break;
303 case 'K':
304 case 'k':
305 multiplier = 1000;
306 break;
307 default:
308 err_msg("ERROR: Unknown bandwidth multiplier character: \"%c\"",
309 end_char);
310 break;
311 }
312 }
313 value=Strtoul(bandwidth_str, 10);
314 free(bandwidth_str);
315 return multiplier * value;
316 }
317
318 /*
319 * str_to_interval -- Convert an interval string to unsigned integer
320 *
321 * Inputs:
322 *
323 * interval_string The interval string to convert
324 *
325 * Returns:
326 *
327 * The interval in microsecons as an unsigned integer
328 */
329 unsigned
str_to_interval(const char * interval_string)330 str_to_interval(const char *interval_string) {
331 char *interval_str;
332 size_t interval_len;
333 unsigned value;
334 int multiplier=1000;
335 int end_char;
336
337 interval_str=dupstr(interval_string); /* Writable copy */
338 interval_len=strlen(interval_str);
339 end_char = interval_str[interval_len-1];
340 if (!isdigit(end_char)) { /* End character is not a digit */
341 interval_str[interval_len-1] = '\0'; /* Remove last character */
342 switch (end_char) {
343 case 'U':
344 case 'u':
345 multiplier = 1;
346 break;
347 case 'S':
348 case 's':
349 multiplier = 1000000;
350 break;
351 default:
352 err_msg("ERROR: Unknown interval multiplier character: \"%c\"",
353 end_char);
354 break;
355 }
356 }
357 value=Strtoul(interval_str, 10);
358 free(interval_str);
359 return multiplier * value;
360 }
361
362 /*
363 * dupstr -- duplicate a string
364 *
365 * Inputs:
366 *
367 * str The string to duplcate
368 *
369 * Returns:
370 *
371 * A pointer to the duplicate string.
372 *
373 * This is a replacement for the common but non-standard "strdup"
374 * function.
375 *
376 * The returned pointer points to Malloc'ed memory, which must be
377 * free'ed by the caller.
378 */
379 char *
dupstr(const char * str)380 dupstr(const char *str) {
381 char *cp;
382 size_t len;
383
384 len = strlen(str) + 1; /* Allow space for terminating NULL */
385 cp = Malloc(len);
386 strlcpy(cp, str, len);
387 return cp;
388 }
389