1 /* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
2  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
3  *
4  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
5  */
6 
7 /*
8  * Manuel Novoa III       Dec 2000
9  *
10  * Converted to use my new (un)signed long (long) to string routines, which
11  * are smaller than the previous functions and don't require static buffers.
12  * In the process, removed the reference to strcat and cut object size of
13  * inet_ntoa in half (from 190 bytes down to 94).
14  *
15  * Manuel Novoa III       Feb 2002
16  *
17  * Changed to use _int10tostr.
18  */
19 
20 #include <stdio.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <bits/uClibc_uintmaxtostr.h>
26 
27 #ifdef L_inet_aton
28 /*
29  * More undocumented inet_aton features.
30  * (read: uclibc doesnt support but glibc does)
31  * http://www.mkssoftware.com/docs/man3/inet_aton.3.asp
32  *
33  * *cp can take the form of:
34  * a.b.c.d    - {a,b,c,d} -> 1 byte
35  * a.b.c      - {a,b}     -> 1 byte    {c} -> 2 bytes
36  * a.b        - {a}       -> 1 byte    {b} -> 3 bytes
37  * a          -                        {a} -> 4 bytes
38  *
39  * Each part may be decimal, octal, or hexadecimal as in ISO C.
40  * 0x or 0X    -> hexadecimal
41  * leading 0   -> octal
42  * all else    -> decimal
43  */
inet_aton(const char * cp,struct in_addr * addrptr)44 int inet_aton(const char *cp, struct in_addr *addrptr)
45 {
46 	in_addr_t addr;
47 	int value;
48 	int part;
49 
50 	if (cp == NULL) {
51 		return 0;
52 	}
53 
54 	addr = 0;
55 	for (part = 1; part <= 4; part++) {
56 
57 		if (!isdigit(*cp))
58 			return 0;
59 
60 		value = 0;
61 		while (isdigit(*cp)) {
62 			value *= 10;
63 			value += *cp++ - '0';
64 			if (value > 255)
65 				return 0;
66 		}
67 
68 		if (part < 4) {
69 			if (*cp++ != '.')
70 				return 0;
71 		} else {
72 			char c = *cp++;
73 			if (c != '\0' && !isspace(c))
74 				return 0;
75 		}
76 
77 		addr <<= 8;
78 		addr |= value;
79 	}
80 
81 	/*  W. Richard Stevens in his book UNIX Network Programming,
82 	 *  Volume 1, second edition, on page 71 says:
83 	 *
84 	 *  An undocumented feature of inet_aton is that if addrptr is
85 	 *  a null pointer, the function still performs it validation
86 	 *  of the input string, but does not store the result.
87 	 */
88 	if (addrptr) {
89 		addrptr->s_addr = htonl(addr);
90 	}
91 
92 	return 1;
93 }
libc_hidden_def(inet_aton)94 libc_hidden_def(inet_aton)
95 #endif
96 
97 #ifdef L_inet_addr
98 
99 in_addr_t inet_addr(const char *cp)
100 {
101 	struct in_addr a;
102 
103 	if (!inet_aton(cp, &a))
104 		return INADDR_NONE;
105 	else
106 		return a.s_addr;
107 }
libc_hidden_def(inet_addr)108 libc_hidden_def(inet_addr)
109 #endif
110 
111 #ifdef L_inet_ntoa
112 
113 #define INET_NTOA_MAX_LEN	16	/* max 12 digits + 3 '.'s + 1 nul */
114 
115 static char *__inet_ntoa_r(struct in_addr in, char buf[INET_NTOA_MAX_LEN])
116 {
117 	in_addr_t addr = ntohl(in.s_addr);
118 	int i;
119 	char *p, *q;
120 
121 	q = 0;
122 	p = buf + INET_NTOA_MAX_LEN - 1; /* cannot use sizeof(buf) here */
123 	for (i = 0; i < 4; i++ ) {
124 		p = _int10tostr(p, addr & 0xff) - 1;
125 		addr >>= 8;
126 		if (q) {
127 			*q = '.';
128 		}
129 		q = p;
130 	}
131 
132 	return p+1;
133 }
strong_alias(__inet_ntoa_r,inet_ntoa_r)134 strong_alias(__inet_ntoa_r,inet_ntoa_r)
135 
136 char *inet_ntoa(struct in_addr in)
137 {
138 	static char buf[INET_NTOA_MAX_LEN];
139 	return __inet_ntoa_r(in, buf);
140 }
libc_hidden_def(inet_ntoa)141 libc_hidden_def(inet_ntoa)
142 #endif
143 
144 #ifdef L_inet_makeaddr
145 
146 /* for some reason it does not remove the jump relocation */
147 
148 /*
149  * Formulate an Internet address from network + host.  Used in
150  * building addresses stored in the ifnet structure.
151  */
152 struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host)
153 {
154 	struct in_addr in;
155 
156 	if (net < 128)
157 		in.s_addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
158 	else if (net < 65536)
159 		in.s_addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
160 	else if (net < 16777216UL)
161 		in.s_addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
162 	else
163 		in.s_addr = net | host;
164 	in.s_addr = htonl(in.s_addr);
165 	return in;
166 }
libc_hidden_def(inet_makeaddr)167 libc_hidden_def(inet_makeaddr)
168 #endif
169 
170 #ifdef L_inet_lnaof
171 /*
172  * Return the local network address portion of an
173  * internet address; handles class a/b/c network
174  * number formats.
175  */
176 in_addr_t inet_lnaof(struct in_addr in)
177 {
178 	in_addr_t i = ntohl(in.s_addr);
179 
180 	if (IN_CLASSA(i))
181 		return (i & IN_CLASSA_HOST);
182 	else if (IN_CLASSB(i))
183 		return (i & IN_CLASSB_HOST);
184 	else
185 		return (i & IN_CLASSC_HOST);
186 }
187 #endif
188 
189 #ifdef L_inet_netof
190 
191 /*
192  * Return the network number from an internet
193  * address; handles class a/b/c network #'s.
194  */
195 in_addr_t
inet_netof(struct in_addr in)196 inet_netof(struct in_addr in)
197 {
198 	in_addr_t i = ntohl(in.s_addr);
199 
200 	if (IN_CLASSA(i))
201 		return ((i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
202 	else if (IN_CLASSB(i))
203 		return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
204 	else
205 		return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
206 }
207 libc_hidden_def(inet_netof)
208 #endif
209