xref: /openbmc/linux/net/sunrpc/addr.c (revision e8e0929d)
1 /*
2  * Copyright 2009, Oracle.  All rights reserved.
3  *
4  * Convert socket addresses to presentation addresses and universal
5  * addresses, and vice versa.
6  *
7  * Universal addresses are introduced by RFC 1833 and further refined by
8  * recent RFCs describing NFSv4.  The universal address format is part
9  * of the external (network) interface provided by rpcbind version 3
10  * and 4, and by NFSv4.  Such an address is a string containing a
11  * presentation format IP address followed by a port number in
12  * "hibyte.lobyte" format.
13  *
14  * IPv6 addresses can also include a scope ID, typically denoted by
15  * a '%' followed by a device name or a non-negative integer.  Refer to
16  * RFC 4291, Section 2.2 for details on IPv6 presentation formats.
17  */
18 
19 #include <net/ipv6.h>
20 #include <linux/sunrpc/clnt.h>
21 
22 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
23 
24 static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
25 				  char *buf, const int buflen)
26 {
27 	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
28 	const struct in6_addr *addr = &sin6->sin6_addr;
29 
30 	/*
31 	 * RFC 4291, Section 2.2.2
32 	 *
33 	 * Shorthanded ANY address
34 	 */
35 	if (ipv6_addr_any(addr))
36 		return snprintf(buf, buflen, "::");
37 
38 	/*
39 	 * RFC 4291, Section 2.2.2
40 	 *
41 	 * Shorthanded loopback address
42 	 */
43 	if (ipv6_addr_loopback(addr))
44 		return snprintf(buf, buflen, "::1");
45 
46 	/*
47 	 * RFC 4291, Section 2.2.3
48 	 *
49 	 * Special presentation address format for mapped v4
50 	 * addresses.
51 	 */
52 	if (ipv6_addr_v4mapped(addr))
53 		return snprintf(buf, buflen, "::ffff:%pI4",
54 					&addr->s6_addr32[3]);
55 
56 	/*
57 	 * RFC 4291, Section 2.2.1
58 	 *
59 	 * To keep the result as short as possible, especially
60 	 * since we don't shorthand, we don't want leading zeros
61 	 * in each halfword, so avoid %pI6.
62 	 */
63 	return snprintf(buf, buflen, "%x:%x:%x:%x:%x:%x:%x:%x",
64 		ntohs(addr->s6_addr16[0]), ntohs(addr->s6_addr16[1]),
65 		ntohs(addr->s6_addr16[2]), ntohs(addr->s6_addr16[3]),
66 		ntohs(addr->s6_addr16[4]), ntohs(addr->s6_addr16[5]),
67 		ntohs(addr->s6_addr16[6]), ntohs(addr->s6_addr16[7]));
68 }
69 
70 static size_t rpc_ntop6(const struct sockaddr *sap,
71 			char *buf, const size_t buflen)
72 {
73 	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
74 	char scopebuf[IPV6_SCOPE_ID_LEN];
75 	size_t len;
76 	int rc;
77 
78 	len = rpc_ntop6_noscopeid(sap, buf, buflen);
79 	if (unlikely(len == 0))
80 		return len;
81 
82 	if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
83 	    !(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_SITELOCAL))
84 		return len;
85 
86 	rc = snprintf(scopebuf, sizeof(scopebuf), "%c%u",
87 			IPV6_SCOPE_DELIMITER, sin6->sin6_scope_id);
88 	if (unlikely((size_t)rc > sizeof(scopebuf)))
89 		return 0;
90 
91 	len += rc;
92 	if (unlikely(len > buflen))
93 		return 0;
94 
95 	strcat(buf, scopebuf);
96 	return len;
97 }
98 
99 #else	/* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */
100 
101 static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
102 				  char *buf, const int buflen)
103 {
104 	return 0;
105 }
106 
107 static size_t rpc_ntop6(const struct sockaddr *sap,
108 			char *buf, const size_t buflen)
109 {
110 	return 0;
111 }
112 
113 #endif	/* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */
114 
115 static int rpc_ntop4(const struct sockaddr *sap,
116 		     char *buf, const size_t buflen)
117 {
118 	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
119 
120 	return snprintf(buf, buflen, "%pI4", &sin->sin_addr);
121 }
122 
123 /**
124  * rpc_ntop - construct a presentation address in @buf
125  * @sap: socket address
126  * @buf: construction area
127  * @buflen: size of @buf, in bytes
128  *
129  * Plants a %NUL-terminated string in @buf and returns the length
130  * of the string, excluding the %NUL.  Otherwise zero is returned.
131  */
132 size_t rpc_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
133 {
134 	switch (sap->sa_family) {
135 	case AF_INET:
136 		return rpc_ntop4(sap, buf, buflen);
137 	case AF_INET6:
138 		return rpc_ntop6(sap, buf, buflen);
139 	}
140 
141 	return 0;
142 }
143 EXPORT_SYMBOL_GPL(rpc_ntop);
144 
145 static size_t rpc_pton4(const char *buf, const size_t buflen,
146 			struct sockaddr *sap, const size_t salen)
147 {
148 	struct sockaddr_in *sin = (struct sockaddr_in *)sap;
149 	u8 *addr = (u8 *)&sin->sin_addr.s_addr;
150 
151 	if (buflen > INET_ADDRSTRLEN || salen < sizeof(struct sockaddr_in))
152 		return 0;
153 
154 	memset(sap, 0, sizeof(struct sockaddr_in));
155 
156 	if (in4_pton(buf, buflen, addr, '\0', NULL) == 0)
157 		return 0;
158 
159 	sin->sin_family = AF_INET;
160 	return sizeof(struct sockaddr_in);;
161 }
162 
163 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
164 static int rpc_parse_scope_id(const char *buf, const size_t buflen,
165 			      const char *delim, struct sockaddr_in6 *sin6)
166 {
167 	char *p;
168 	size_t len;
169 
170 	if ((buf + buflen) == delim)
171 		return 1;
172 
173 	if (*delim != IPV6_SCOPE_DELIMITER)
174 		return 0;
175 
176 	if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
177 	    !(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_SITELOCAL))
178 		return 0;
179 
180 	len = (buf + buflen) - delim - 1;
181 	p = kstrndup(delim + 1, len, GFP_KERNEL);
182 	if (p) {
183 		unsigned long scope_id = 0;
184 		struct net_device *dev;
185 
186 		dev = dev_get_by_name(&init_net, p);
187 		if (dev != NULL) {
188 			scope_id = dev->ifindex;
189 			dev_put(dev);
190 		} else {
191 			if (strict_strtoul(p, 10, &scope_id) == 0) {
192 				kfree(p);
193 				return 0;
194 			}
195 		}
196 
197 		kfree(p);
198 
199 		sin6->sin6_scope_id = scope_id;
200 		return 1;
201 	}
202 
203 	return 0;
204 }
205 
206 static size_t rpc_pton6(const char *buf, const size_t buflen,
207 			struct sockaddr *sap, const size_t salen)
208 {
209 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
210 	u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
211 	const char *delim;
212 
213 	if (buflen > (INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN) ||
214 	    salen < sizeof(struct sockaddr_in6))
215 		return 0;
216 
217 	memset(sap, 0, sizeof(struct sockaddr_in6));
218 
219 	if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0)
220 		return 0;
221 
222 	if (!rpc_parse_scope_id(buf, buflen, delim, sin6))
223 		return 0;
224 
225 	sin6->sin6_family = AF_INET6;
226 	return sizeof(struct sockaddr_in6);
227 }
228 #else
229 static size_t rpc_pton6(const char *buf, const size_t buflen,
230 			struct sockaddr *sap, const size_t salen)
231 {
232 	return 0;
233 }
234 #endif
235 
236 /**
237  * rpc_pton - Construct a sockaddr in @sap
238  * @buf: C string containing presentation format IP address
239  * @buflen: length of presentation address in bytes
240  * @sap: buffer into which to plant socket address
241  * @salen: size of buffer in bytes
242  *
243  * Returns the size of the socket address if successful; otherwise
244  * zero is returned.
245  *
246  * Plants a socket address in @sap and returns the size of the
247  * socket address, if successful.  Returns zero if an error
248  * occurred.
249  */
250 size_t rpc_pton(const char *buf, const size_t buflen,
251 		struct sockaddr *sap, const size_t salen)
252 {
253 	unsigned int i;
254 
255 	for (i = 0; i < buflen; i++)
256 		if (buf[i] == ':')
257 			return rpc_pton6(buf, buflen, sap, salen);
258 	return rpc_pton4(buf, buflen, sap, salen);
259 }
260 EXPORT_SYMBOL_GPL(rpc_pton);
261 
262 /**
263  * rpc_sockaddr2uaddr - Construct a universal address string from @sap.
264  * @sap: socket address
265  *
266  * Returns a %NUL-terminated string in dynamically allocated memory;
267  * otherwise NULL is returned if an error occurred.  Caller must
268  * free the returned string.
269  */
270 char *rpc_sockaddr2uaddr(const struct sockaddr *sap)
271 {
272 	char portbuf[RPCBIND_MAXUADDRPLEN];
273 	char addrbuf[RPCBIND_MAXUADDRLEN];
274 	unsigned short port;
275 
276 	switch (sap->sa_family) {
277 	case AF_INET:
278 		if (rpc_ntop4(sap, addrbuf, sizeof(addrbuf)) == 0)
279 			return NULL;
280 		port = ntohs(((struct sockaddr_in *)sap)->sin_port);
281 		break;
282 	case AF_INET6:
283 		if (rpc_ntop6_noscopeid(sap, addrbuf, sizeof(addrbuf)) == 0)
284 			return NULL;
285 		port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
286 		break;
287 	default:
288 		return NULL;
289 	}
290 
291 	if (snprintf(portbuf, sizeof(portbuf),
292 		     ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf))
293 		return NULL;
294 
295 	if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf))
296 		return NULL;
297 
298 	return kstrdup(addrbuf, GFP_KERNEL);
299 }
300 EXPORT_SYMBOL_GPL(rpc_sockaddr2uaddr);
301 
302 /**
303  * rpc_uaddr2sockaddr - convert a universal address to a socket address.
304  * @uaddr: C string containing universal address to convert
305  * @uaddr_len: length of universal address string
306  * @sap: buffer into which to plant socket address
307  * @salen: size of buffer
308  *
309  * Returns the size of the socket address if successful; otherwise
310  * zero is returned.
311  */
312 size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len,
313 			  struct sockaddr *sap, const size_t salen)
314 {
315 	char *c, buf[RPCBIND_MAXUADDRLEN];
316 	unsigned long portlo, porthi;
317 	unsigned short port;
318 
319 	if (uaddr_len > sizeof(buf))
320 		return 0;
321 
322 	memcpy(buf, uaddr, uaddr_len);
323 
324 	buf[uaddr_len] = '\n';
325 	buf[uaddr_len + 1] = '\0';
326 
327 	c = strrchr(buf, '.');
328 	if (unlikely(c == NULL))
329 		return 0;
330 	if (unlikely(strict_strtoul(c + 1, 10, &portlo) != 0))
331 		return 0;
332 	if (unlikely(portlo > 255))
333 		return 0;
334 
335 	c[0] = '\n';
336 	c[1] = '\0';
337 
338 	c = strrchr(buf, '.');
339 	if (unlikely(c == NULL))
340 		return 0;
341 	if (unlikely(strict_strtoul(c + 1, 10, &porthi) != 0))
342 		return 0;
343 	if (unlikely(porthi > 255))
344 		return 0;
345 
346 	port = (unsigned short)((porthi << 8) | portlo);
347 
348 	c[0] = '\0';
349 
350 	if (rpc_pton(buf, strlen(buf), sap, salen) == 0)
351 		return 0;
352 
353 	switch (sap->sa_family) {
354 	case AF_INET:
355 		((struct sockaddr_in *)sap)->sin_port = htons(port);
356 		return sizeof(struct sockaddr_in);
357 	case AF_INET6:
358 		((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
359 		return sizeof(struct sockaddr_in6);
360 	}
361 
362 	return 0;
363 }
364 EXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr);
365