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