forked from royhills/arp-scan
-
Notifications
You must be signed in to change notification settings - Fork 4
/
inet_aton.c
131 lines (117 loc) · 4.57 KB
/
inet_aton.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
**
** Replacement for a missing inet_aton.
**
** Written by Russ Allbery <[email protected]>
** This work is hereby placed in the public domain by its author.
**
** Provides the same functionality as the standard library routine
** inet_aton for those platforms that don't have it. inet_aton is
** thread-safe.
*/
#include "config.h"
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
/* If we're running the test suite, rename inet_ntoa to avoid conflicts with
the system version. */
#if TESTING
# define inet_aton test_inet_aton
int test_inet_aton(const char *, struct in_addr *);
#endif
int
inet_aton(const char *s, struct in_addr *addr)
{
unsigned long octet[4], address;
const char *p;
int base, i;
int part = 0;
if (s == NULL) return 0;
/* Step through each period-separated part of the address. If we see
more than four parts, the address is invalid. */
for (p = s; *p != 0; part++) {
if (part > 3) return 0;
/* Determine the base of the section we're looking at. Numbers are
represented the same as in C; octal starts with 0, hex starts
with 0x, and anything else is decimal. */
if (*p == '0') {
p++;
if (*p == 'x') {
p++;
base = 16;
} else {
base = 8;
}
} else {
base = 10;
}
/* Make sure there's actually a number. (A section of just "0"
would set base to 8 and leave us pointing at a period; allow
that.) */
if (*p == '.' && base != 8) return 0;
octet[part] = 0;
/* Now, parse this segment of the address. For each digit, multiply
the result so far by the base and then add the value of the
digit. Be careful of arithmetic overflow in cases where an
unsigned long is 32 bits; we need to detect it *before* we
multiply by the base since otherwise we could overflow and wrap
and then not detect the error. */
for (; *p != 0 && *p != '.'; p++) {
if (octet[part] > 0xffffffffUL / base) return 0;
/* Use a switch statement to parse each digit rather than
assuming ASCII. Probably pointless portability.... */
switch (*p) {
case '0': i = 0; break;
case '1': i = 1; break;
case '2': i = 2; break;
case '3': i = 3; break;
case '4': i = 4; break;
case '5': i = 5; break;
case '6': i = 6; break;
case '7': i = 7; break;
case '8': i = 8; break;
case '9': i = 9; break;
case 'A': case 'a': i = 10; break;
case 'B': case 'b': i = 11; break;
case 'C': case 'c': i = 12; break;
case 'D': case 'd': i = 13; break;
case 'E': case 'e': i = 14; break;
case 'F': case 'f': i = 15; break;
default: return 0;
}
if (i >= base) return 0;
octet[part] = (octet[part] * base) + i;
}
/* Advance over periods; the top of the loop will increment the
count of parts we've seen. We need a check here to detect an
illegal trailing period. */
if (*p == '.') {
p++;
if (*p == 0) return 0;
}
}
if (part == 0) return 0;
/* IPv4 allows three types of address specification:
a.b
a.b.c
a.b.c.d
If there are fewer than four segments, the final segment accounts for
all of the remaining portion of the address. For example, in the a.b
form, b is the final 24 bits of the address. We also allow a simple
number, which is interpreted as the 32-bit number corresponding to
the full IPv4 address.
The first for loop below ensures that any initial segments represent
only 8 bits of the address and builds the upper portion of the IPv4
address. Then, the remaining segment is checked to make sure it's no
bigger than the remaining space in the address and then is added into
the result. */
address = 0;
for (i = 0; i < part - 1; i++) {
if (octet[i] > 0xff) return 0;
address |= octet[i] << (8 * (3 - i));
}
if (octet[i] > (0xffffffffUL >> (i * 8))) return 0;
address |= octet[i];
if (addr != NULL) addr->s_addr = htonl(address);
return 1;
}