net: Add net_addr_pton()

This function converts a string into an IP address.

Change-Id: If57983a345fe4c18df01e58dbce7d9a50a27b82a
Signed-off-by: Jaakko Hannikainen <jaakko.hannikainen@intel.com>
This commit is contained in:
Jaakko Hannikainen 2016-08-24 14:57:55 +03:00 committed by Jukka Rissanen
parent b52f8f1fa1
commit f9f0d895ea
2 changed files with 138 additions and 0 deletions

View file

@ -739,6 +739,22 @@ struct sockaddr_in_ptr *net_sin_ptr(const struct sockaddr_ptr *addr)
return (struct sockaddr_in_ptr *)addr;
}
/**
* @brief Convert a string to IP address.
*
* @param family IP address family (AF_INET or AF_INET6)
* @param src IP address in a null terminated string
* @param dst Pointer to struct in_addr if family is AF_INET or
* pointer to struct in6_addr if family is AF_INET6
*
* @note This function doesn't do precise error checking,
* do not use for untrusted strings.
*
* @return 0 if ok, < 0 if error
*/
int net_addr_pton(sa_family_t family, const char *src,
struct sockaddr *dst);
#ifdef __cplusplus
}
#endif

View file

@ -27,6 +27,9 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <net/net_ip.h>
#include <net/nbuf.h>
#include <net/net_core.h>
@ -237,6 +240,125 @@ char *net_sprint_ip_addr_buf(const uint8_t *ip, int ip_len,
return buf;
}
int net_addr_pton(sa_family_t family, const char *src,
struct sockaddr *dst)
{
if (family == AF_INET) {
struct in_addr *addr = (struct in_addr *)dst;
int i, len;
len = strlen(src);
for (i = 0; i < len; i++) {
if (!(src[i] >= '0' && src[i] <= '9') &&
src[i] != '.') {
return -EINVAL;
}
}
for (i = 0; i < 4; i++) {
addr->s4_addr[i] = strtol(src, NULL, 10);
src++;
}
} else if (family == AF_INET6) {
/* If the string contains a '.', it means it's of the form
* X:X:X:X:X:X:x.x.x.x, and contains only 6 16-bit pieces
*/
int expected_groups = strchr(src, '.') ? 6 : 8;
struct in6_addr *addr = (struct in6_addr *)dst;
int i, len;
if (*src == ':') {
/* Ignore a leading colon, makes parsing neater */
src++;
}
len = strlen(src);
for (i = 0; i < len; i++) {
if (!(src[i] >= '0' && src[i] <= '9') &&
!(src[i] >= 'A' && src[i] <= 'F') &&
!(src[i] >= 'a' && src[i] <= 'f') &&
src[i] != '.' && src[i] != ':')
return -EINVAL;
}
for (i = 0; i < expected_groups; i++) {
char *tmp;
if (!src || *src == '\0') {
return -EINVAL;
}
if (*src != ':') {
/* Normal IPv6 16-bit piece */
addr->s6_addr16[i] = htons(strtol(src, NULL,
16));
src = strchr(src, ':');
if (!src && i < expected_groups - 1) {
return -EINVAL;
}
src++;
continue;
}
/* Two colons in a row */
for (; i < expected_groups; i++) {
addr->s6_addr16[i] = 0;
}
tmp = strrchr(src, ':');
if (src == tmp && (expected_groups == 6 || !src[1])) {
src++;
break;
}
if (expected_groups == 6) {
/* we need to drop the trailing
* colon since it's between the
* ipv6 and ipv4 addresses, rather than being
* a part of the ipv6 address
*/
tmp--;
}
/* Calculate the amount of skipped zeros */
i = expected_groups - 1;
do {
if (*tmp == ':') {
i--;
}
} while (tmp-- != src);
src++;
}
if (expected_groups == 6) {
/* Parse the IPv4 part */
for (i = 0; i < 4; i++) {
if (!src || !*src) {
return -EINVAL;
}
addr->s6_addr[12 + i] = strtol(src, NULL, 10);
src = strchr(src, '.');
if (!src && i < 3) {
return -EINVAL;
}
src++;
}
}
} else {
return -EINVAL;
}
return 0;
}
static uint16_t calc_chksum(uint16_t sum, const uint8_t *ptr, uint16_t len)
{
uint16_t tmp;